Skip to content

Commit 8871fe8

Browse files
authored
Rollup merge of #90296 - CAD97:rip-lerp, r=Mark-Simulacrum
Remove fNN::lerp Lerp is [surprisingly complex with multiple tradeoffs depending on what guarantees you want to provide](#86269 (comment)) (and what you're willing to drop for raw speed), so we don't have consensus on what implementation to use, let alone what signature - `t.lerp(a, b)` nicely puts `a, b` together, but makes dispatch to lerp custom types with the same signature basically impossible, and major ecosystem crates (e.g. nalgebra, glium) use `a.lerp(b, t)`, which is easily confusable. It was suggested to maybe provide a `Lerp<T>` trait and `t.lerp([a, b])`, which _could_ be implemented by downstream math libraries for their types, but also significantly raises the bar from a simple fNN method to a full trait, and does nothing to solve the implementation question. (It also raises the question of whether we'd support higher-order bezier interpolation.) The only consensus we have is the lack of consensus, and the [general temperature](#86269 (comment)) is that we should just remove this method (giving the method space back to 3rd party libs) and revisit this if (and likely only if) IEEE adds lerp to their specification. If people want a lerp, they're _probably_ already using (or writing) a math support library, which provides a lerp function for its custom math types and can provide the same lerp implementation for the primitive types via an extension trait. See also [previous Zulip discussion](https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs/topic/lerp.20API.20design) cc ``@clarfonthey`` (original PR author), ``@m-ou-se`` (original r+), ``@scottmcm`` (last voice in tracking issue, prompted me to post this) Closes #86269 (removed)
2 parents 3c8f001 + 6b449b4 commit 8871fe8

File tree

5 files changed

+0
-191
lines changed

5 files changed

+0
-191
lines changed

library/std/src/f32.rs

-36
Original file line numberDiff line numberDiff line change
@@ -878,40 +878,4 @@ impl f32 {
878878
pub fn atanh(self) -> f32 {
879879
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
880880
}
881-
882-
/// Linear interpolation between `start` and `end`.
883-
///
884-
/// This enables linear interpolation between `start` and `end`, where start is represented by
885-
/// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all
886-
/// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0
887-
/// at a given rate, the result will change from `start` to `end` at a similar rate.
888-
///
889-
/// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the
890-
/// range from `start` to `end`. This also is useful for transition functions which might
891-
/// move slightly past the end or start for a desired effect. Mathematically, the values
892-
/// returned are equivalent to `start + self * (end - start)`, although we make a few specific
893-
/// guarantees that are useful specifically to linear interpolation.
894-
///
895-
/// These guarantees are:
896-
///
897-
/// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the
898-
/// value at 1.0 is always `end`. (exactness)
899-
/// * If `start` and `end` are [finite], the values will always move in the direction from
900-
/// `start` to `end` (monotonicity)
901-
/// * If `self` is [finite] and `start == end`, the value at any point will always be
902-
/// `start == end`. (consistency)
903-
///
904-
/// [finite]: #method.is_finite
905-
#[must_use = "method returns a new number and does not mutate the original value"]
906-
#[unstable(feature = "float_interpolation", issue = "86269")]
907-
pub fn lerp(self, start: f32, end: f32) -> f32 {
908-
// consistent
909-
if start == end {
910-
start
911-
912-
// exact/monotonic
913-
} else {
914-
self.mul_add(end, (-self).mul_add(start, start))
915-
}
916-
}
917881
}

library/std/src/f32/tests.rs

-63
Original file line numberDiff line numberDiff line change
@@ -757,66 +757,3 @@ fn test_total_cmp() {
757757
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY));
758758
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
759759
}
760-
761-
#[test]
762-
fn test_lerp_exact() {
763-
// simple values
764-
assert_eq!(f32::lerp(0.0, 2.0, 4.0), 2.0);
765-
assert_eq!(f32::lerp(1.0, 2.0, 4.0), 4.0);
766-
767-
// boundary values
768-
assert_eq!(f32::lerp(0.0, f32::MIN, f32::MAX), f32::MIN);
769-
assert_eq!(f32::lerp(1.0, f32::MIN, f32::MAX), f32::MAX);
770-
}
771-
772-
#[test]
773-
fn test_lerp_consistent() {
774-
assert_eq!(f32::lerp(f32::MAX, f32::MIN, f32::MIN), f32::MIN);
775-
assert_eq!(f32::lerp(f32::MIN, f32::MAX, f32::MAX), f32::MAX);
776-
777-
// as long as t is finite, a/b can be infinite
778-
assert_eq!(f32::lerp(f32::MAX, f32::NEG_INFINITY, f32::NEG_INFINITY), f32::NEG_INFINITY);
779-
assert_eq!(f32::lerp(f32::MIN, f32::INFINITY, f32::INFINITY), f32::INFINITY);
780-
}
781-
782-
#[test]
783-
fn test_lerp_nan_infinite() {
784-
// non-finite t is not NaN if a/b different
785-
assert!(!f32::lerp(f32::INFINITY, f32::MIN, f32::MAX).is_nan());
786-
assert!(!f32::lerp(f32::NEG_INFINITY, f32::MIN, f32::MAX).is_nan());
787-
}
788-
789-
#[test]
790-
fn test_lerp_values() {
791-
// just a few basic values
792-
assert_eq!(f32::lerp(0.25, 1.0, 2.0), 1.25);
793-
assert_eq!(f32::lerp(0.50, 1.0, 2.0), 1.50);
794-
assert_eq!(f32::lerp(0.75, 1.0, 2.0), 1.75);
795-
}
796-
797-
#[test]
798-
fn test_lerp_monotonic() {
799-
// near 0
800-
let below_zero = f32::lerp(-f32::EPSILON, f32::MIN, f32::MAX);
801-
let zero = f32::lerp(0.0, f32::MIN, f32::MAX);
802-
let above_zero = f32::lerp(f32::EPSILON, f32::MIN, f32::MAX);
803-
assert!(below_zero <= zero);
804-
assert!(zero <= above_zero);
805-
assert!(below_zero <= above_zero);
806-
807-
// near 0.5
808-
let below_half = f32::lerp(0.5 - f32::EPSILON, f32::MIN, f32::MAX);
809-
let half = f32::lerp(0.5, f32::MIN, f32::MAX);
810-
let above_half = f32::lerp(0.5 + f32::EPSILON, f32::MIN, f32::MAX);
811-
assert!(below_half <= half);
812-
assert!(half <= above_half);
813-
assert!(below_half <= above_half);
814-
815-
// near 1
816-
let below_one = f32::lerp(1.0 - f32::EPSILON, f32::MIN, f32::MAX);
817-
let one = f32::lerp(1.0, f32::MIN, f32::MAX);
818-
let above_one = f32::lerp(1.0 + f32::EPSILON, f32::MIN, f32::MAX);
819-
assert!(below_one <= one);
820-
assert!(one <= above_one);
821-
assert!(below_one <= above_one);
822-
}

library/std/src/f64.rs

-36
Original file line numberDiff line numberDiff line change
@@ -881,42 +881,6 @@ impl f64 {
881881
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
882882
}
883883

884-
/// Linear interpolation between `start` and `end`.
885-
///
886-
/// This enables linear interpolation between `start` and `end`, where start is represented by
887-
/// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all
888-
/// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0
889-
/// at a given rate, the result will change from `start` to `end` at a similar rate.
890-
///
891-
/// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the
892-
/// range from `start` to `end`. This also is useful for transition functions which might
893-
/// move slightly past the end or start for a desired effect. Mathematically, the values
894-
/// returned are equivalent to `start + self * (end - start)`, although we make a few specific
895-
/// guarantees that are useful specifically to linear interpolation.
896-
///
897-
/// These guarantees are:
898-
///
899-
/// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the
900-
/// value at 1.0 is always `end`. (exactness)
901-
/// * If `start` and `end` are [finite], the values will always move in the direction from
902-
/// `start` to `end` (monotonicity)
903-
/// * If `self` is [finite] and `start == end`, the value at any point will always be
904-
/// `start == end`. (consistency)
905-
///
906-
/// [finite]: #method.is_finite
907-
#[must_use = "method returns a new number and does not mutate the original value"]
908-
#[unstable(feature = "float_interpolation", issue = "86269")]
909-
pub fn lerp(self, start: f64, end: f64) -> f64 {
910-
// consistent
911-
if start == end {
912-
start
913-
914-
// exact/monotonic
915-
} else {
916-
self.mul_add(end, (-self).mul_add(start, start))
917-
}
918-
}
919-
920884
// Solaris/Illumos requires a wrapper around log, log2, and log10 functions
921885
// because of their non-standard behavior (e.g., log(-n) returns -Inf instead
922886
// of expected NaN).

library/std/src/f64/tests.rs

-55
Original file line numberDiff line numberDiff line change
@@ -753,58 +753,3 @@ fn test_total_cmp() {
753753
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY));
754754
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
755755
}
756-
757-
#[test]
758-
fn test_lerp_exact() {
759-
// simple values
760-
assert_eq!(f64::lerp(0.0, 2.0, 4.0), 2.0);
761-
assert_eq!(f64::lerp(1.0, 2.0, 4.0), 4.0);
762-
763-
// boundary values
764-
assert_eq!(f64::lerp(0.0, f64::MIN, f64::MAX), f64::MIN);
765-
assert_eq!(f64::lerp(1.0, f64::MIN, f64::MAX), f64::MAX);
766-
}
767-
768-
#[test]
769-
fn test_lerp_consistent() {
770-
assert_eq!(f64::lerp(f64::MAX, f64::MIN, f64::MIN), f64::MIN);
771-
assert_eq!(f64::lerp(f64::MIN, f64::MAX, f64::MAX), f64::MAX);
772-
773-
// as long as t is finite, a/b can be infinite
774-
assert_eq!(f64::lerp(f64::MAX, f64::NEG_INFINITY, f64::NEG_INFINITY), f64::NEG_INFINITY);
775-
assert_eq!(f64::lerp(f64::MIN, f64::INFINITY, f64::INFINITY), f64::INFINITY);
776-
}
777-
778-
#[test]
779-
fn test_lerp_nan_infinite() {
780-
// non-finite t is not NaN if a/b different
781-
assert!(!f64::lerp(f64::INFINITY, f64::MIN, f64::MAX).is_nan());
782-
assert!(!f64::lerp(f64::NEG_INFINITY, f64::MIN, f64::MAX).is_nan());
783-
}
784-
785-
#[test]
786-
fn test_lerp_values() {
787-
// just a few basic values
788-
assert_eq!(f64::lerp(0.25, 1.0, 2.0), 1.25);
789-
assert_eq!(f64::lerp(0.50, 1.0, 2.0), 1.50);
790-
assert_eq!(f64::lerp(0.75, 1.0, 2.0), 1.75);
791-
}
792-
793-
#[test]
794-
fn test_lerp_monotonic() {
795-
// near 0
796-
let below_zero = f64::lerp(-f64::EPSILON, f64::MIN, f64::MAX);
797-
let zero = f64::lerp(0.0, f64::MIN, f64::MAX);
798-
let above_zero = f64::lerp(f64::EPSILON, f64::MIN, f64::MAX);
799-
assert!(below_zero <= zero);
800-
assert!(zero <= above_zero);
801-
assert!(below_zero <= above_zero);
802-
803-
// near 1
804-
let below_one = f64::lerp(1.0 - f64::EPSILON, f64::MIN, f64::MAX);
805-
let one = f64::lerp(1.0, f64::MIN, f64::MAX);
806-
let above_one = f64::lerp(1.0 + f64::EPSILON, f64::MIN, f64::MAX);
807-
assert!(below_one <= one);
808-
assert!(one <= above_one);
809-
assert!(below_one <= above_one);
810-
}

library/std/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,6 @@
284284
#![feature(exact_size_is_empty)]
285285
#![feature(exhaustive_patterns)]
286286
#![feature(extend_one)]
287-
#![feature(float_interpolation)]
288287
#![feature(fn_traits)]
289288
#![feature(format_args_nl)]
290289
#![feature(gen_future)]

0 commit comments

Comments
 (0)