Skip to content

Commit d8e247e

Browse files
committed
More lerp tests, altering lerp docs
1 parent 0865acd commit d8e247e

File tree

4 files changed

+118
-26
lines changed

4 files changed

+118
-26
lines changed

library/std/src/f32.rs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -879,19 +879,27 @@ impl f32 {
879879

880880
/// Linear interpolation between `start` and `end`.
881881
///
882-
/// This enables the calculation of a "smooth" transition between `start` and `end`,
883-
/// where start is represented by `self == 0.0` and `end` is represented by `self == 1.0`.
884-
///
885-
/// Values below 0.0 or above 1.0 are allowed, and in general this function closely
886-
/// resembles the value of `start + self * (end - start)`, plus additional guarantees.
887-
///
888-
/// Those guarantees are, assuming that all values are [`finite`]:
889-
///
890-
/// * The value at 0.0 is always `start` and the value at 1.0 is always `end` (exactness)
891-
/// * If `start == end`, the value at any point will always be `start == end` (consistency)
892-
/// * The values will always move in the direction from `start` to `end` (monotonicity)
893-
///
894-
/// [`finite`]: #method.is_finite
882+
/// This enables linear interpolation between `start` and `end`, where start is represented by
883+
/// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all
884+
/// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0
885+
/// at a given rate, the result will change from `start` to `end` at a similar rate.
886+
///
887+
/// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the
888+
/// range from `start` to `end`. This also is useful for transition functions which might
889+
/// move slightly past the end or start for a desired effect. Mathematically, the values
890+
/// returned are equivalent to `start + self * (end - start)`, although we make a few specific
891+
/// guarantees that are useful specifically to linear interpolation.
892+
///
893+
/// These guarantees are:
894+
///
895+
/// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the
896+
/// value at 1.0 is always `end`. (exactness)
897+
/// * If `start` and `end` are [finite], the values will always move in the direction from
898+
/// `start` to `end` (monotonicity)
899+
/// * If `self` is [finite] and `start == end`, the value at any point will always be
900+
/// `start == end`. (consistency)
901+
///
902+
/// [finite]: #method.is_finite
895903
#[must_use = "method returns a new number and does not mutate the original value"]
896904
#[unstable(feature = "float_interpolation", issue = "71015")]
897905
pub fn lerp(self, start: f32, end: f32) -> f32 {

library/std/src/f32/tests.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,8 +760,11 @@ fn test_total_cmp() {
760760

761761
#[test]
762762
fn test_lerp_exact() {
763+
// simple values
763764
assert_eq!(f32::lerp(0.0, 2.0, 4.0), 2.0);
764765
assert_eq!(f32::lerp(1.0, 2.0, 4.0), 4.0);
766+
767+
// boundary values
765768
assert_eq!(f32::lerp(0.0, f32::MIN, f32::MAX), f32::MIN);
766769
assert_eq!(f32::lerp(1.0, f32::MIN, f32::MAX), f32::MAX);
767770
}
@@ -770,11 +773,50 @@ fn test_lerp_exact() {
770773
fn test_lerp_consistent() {
771774
assert_eq!(f32::lerp(f32::MAX, f32::MIN, f32::MIN), f32::MIN);
772775
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());
773787
}
774788

775789
#[test]
776790
fn test_lerp_values() {
791+
// just a few basic values
777792
assert_eq!(f32::lerp(0.25, 1.0, 2.0), 1.25);
778793
assert_eq!(f32::lerp(0.50, 1.0, 2.0), 1.50);
779794
assert_eq!(f32::lerp(0.75, 1.0, 2.0), 1.75);
780795
}
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

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -881,19 +881,27 @@ impl f64 {
881881

882882
/// Linear interpolation between `start` and `end`.
883883
///
884-
/// This enables the calculation of a "smooth" transition between `start` and `end`,
885-
/// where start is represented by `self == 0.0` and `end` is represented by `self == 1.0`.
886-
///
887-
/// Values below 0.0 or above 1.0 are allowed, and in general this function closely
888-
/// resembles the value of `start + self * (end - start)`, plus additional guarantees.
889-
///
890-
/// Those guarantees are, assuming that all values are [`finite`]:
891-
///
892-
/// * The value at 0.0 is always `start` and the value at 1.0 is always `end` (exactness)
893-
/// * If `start == end`, the value at any point will always be `start == end` (consistency)
894-
/// * The values will always move in the direction from `start` to `end` (monotonicity)
895-
///
896-
/// [`finite`]: #method.is_finite
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
897905
#[must_use = "method returns a new number and does not mutate the original value"]
898906
#[unstable(feature = "float_interpolation", issue = "71015")]
899907
pub fn lerp(self, start: f64, end: f64) -> f64 {

library/std/src/f64/tests.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,8 +756,11 @@ fn test_total_cmp() {
756756

757757
#[test]
758758
fn test_lerp_exact() {
759+
// simple values
759760
assert_eq!(f64::lerp(0.0, 2.0, 4.0), 2.0);
760761
assert_eq!(f64::lerp(1.0, 2.0, 4.0), 4.0);
762+
763+
// boundary values
761764
assert_eq!(f64::lerp(0.0, f64::MIN, f64::MAX), f64::MIN);
762765
assert_eq!(f64::lerp(1.0, f64::MIN, f64::MAX), f64::MAX);
763766
}
@@ -766,11 +769,42 @@ fn test_lerp_exact() {
766769
fn test_lerp_consistent() {
767770
assert_eq!(f64::lerp(f64::MAX, f64::MIN, f64::MIN), f64::MIN);
768771
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());
769783
}
770784

771785
#[test]
772786
fn test_lerp_values() {
787+
// just a few basic values
773788
assert_eq!(f64::lerp(0.25, 1.0, 2.0), 1.25);
774789
assert_eq!(f64::lerp(0.50, 1.0, 2.0), 1.50);
775790
assert_eq!(f64::lerp(0.75, 1.0, 2.0), 1.75);
776791
}
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+
}

0 commit comments

Comments
 (0)