Skip to content

Commit a8ee0e9

Browse files
committed
Implement IEEE 754-2019 minimun and maximum functions for f32/f64
1 parent 41301c3 commit a8ee0e9

File tree

6 files changed

+199
-0
lines changed

6 files changed

+199
-0
lines changed

library/core/src/num/f32.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,68 @@ impl f32 {
703703
intrinsics::minnumf32(self, other)
704704
}
705705

706+
/// Returns the maximum of the two numbers, propagating NaNs.
707+
///
708+
/// This returns NaN when *either* argument is NaN, as opposed to
709+
/// [`f32::max`] which only returns NaN when *both* arguments are NaN.
710+
///
711+
/// ```
712+
/// #![feature(float_minimum_maximum)]
713+
/// let x = 1.0f32;
714+
/// let y = 2.0f32;
715+
///
716+
/// assert_eq!(x.maximum(y), y);
717+
/// assert!(x.maximum(f32::NAN).is_nan());
718+
/// ```
719+
///
720+
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
721+
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
722+
/// Note that this follow the semantics specified in IEEE 754-2019.
723+
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
724+
#[inline]
725+
pub fn maximum(self, other: f32) -> f32 {
726+
if self > other {
727+
self
728+
} else if other > self {
729+
other
730+
} else if self == other {
731+
if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
732+
} else {
733+
self + other
734+
}
735+
}
736+
737+
/// Returns the minimum of the two numbers, propagating NaNs.
738+
///
739+
/// This returns NaN when *either* argument is NaN, as opposed to
740+
/// [`f32::min`] which only returns NaN when *both* arguments are NaN.
741+
///
742+
/// ```
743+
/// #![feature(float_minimum_maximum)]
744+
/// let x = 1.0f32;
745+
/// let y = 2.0f32;
746+
///
747+
/// assert_eq!(x.minimum(y), x);
748+
/// assert!(x.minimum(f32::NAN).is_nan());
749+
/// ```
750+
///
751+
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
752+
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
753+
/// Note that this follow the semantics specified in IEEE 754-2019.
754+
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
755+
#[inline]
756+
pub fn minimum(self, other: f32) -> f32 {
757+
if self < other {
758+
self
759+
} else if other < self {
760+
other
761+
} else if self == other {
762+
if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
763+
} else {
764+
self + other
765+
}
766+
}
767+
706768
/// Rounds toward zero and converts to any primitive integer type,
707769
/// assuming that the value is finite and fits in that type.
708770
///

library/core/src/num/f64.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,68 @@ impl f64 {
719719
intrinsics::minnumf64(self, other)
720720
}
721721

722+
/// Returns the maximum of the two numbers, propagating NaNs.
723+
///
724+
/// This returns NaN when *either* argument is NaN, as opposed to
725+
/// [`f64::max`] which only returns NaN when *both* arguments are NaN.
726+
///
727+
/// ```
728+
/// #![feature(float_minimum_maximum)]
729+
/// let x = 1.0_f64;
730+
/// let y = 2.0_f64;
731+
///
732+
/// assert_eq!(x.maximum(y), y);
733+
/// assert!(x.maximum(f64::NAN).is_nan());
734+
/// ```
735+
///
736+
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
737+
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
738+
/// Note that this follow the semantics specified in IEEE 754-2019.
739+
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
740+
#[inline]
741+
pub fn maximum(self, other: f64) -> f64 {
742+
if self > other {
743+
self
744+
} else if other > self {
745+
other
746+
} else if self == other {
747+
if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
748+
} else {
749+
self + other
750+
}
751+
}
752+
753+
/// Returns the minimum of the two numbers, propagating NaNs.
754+
///
755+
/// This returns NaN when *either* argument is NaN, as opposed to
756+
/// [`f64::min`] which only returns NaN when *both* arguments are NaN.
757+
///
758+
/// ```
759+
/// #![feature(float_minimum_maximum)]
760+
/// let x = 1.0_f64;
761+
/// let y = 2.0_f64;
762+
///
763+
/// assert_eq!(x.minimum(y), x);
764+
/// assert!(x.minimum(f64::NAN).is_nan());
765+
/// ```
766+
///
767+
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
768+
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
769+
/// Note that this follow the semantics specified in IEEE 754-2019.
770+
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
771+
#[inline]
772+
pub fn minimum(self, other: f64) -> f64 {
773+
if self < other {
774+
self
775+
} else if other < self {
776+
other
777+
} else if self == other {
778+
if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
779+
} else {
780+
self + other
781+
}
782+
}
783+
722784
/// Rounds toward zero and converts to any primitive integer type,
723785
/// assuming that the value is finite and fits in that type.
724786
///

library/core/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#![feature(extern_types)]
2828
#![feature(flt2dec)]
2929
#![feature(fmt_internals)]
30+
#![feature(float_minimum_maximum)]
3031
#![feature(array_from_fn)]
3132
#![feature(hashmap_internals)]
3233
#![feature(try_find)]

library/core/tests/num/mod.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,67 @@ macro_rules! test_float {
715715
assert!(($nan as $fty).max($nan).is_nan());
716716
}
717717
#[test]
718+
fn minimum() {
719+
assert_eq!((0.0 as $fty).minimum(0.0), 0.0);
720+
assert!((0.0 as $fty).minimum(0.0).is_sign_positive());
721+
assert_eq!((-0.0 as $fty).minimum(0.0), -0.0);
722+
assert!((-0.0 as $fty).minimum(0.0).is_sign_negative());
723+
assert_eq!((-0.0 as $fty).minimum(-0.0), -0.0);
724+
assert!((-0.0 as $fty).minimum(-0.0).is_sign_negative());
725+
assert_eq!((9.0 as $fty).minimum(9.0), 9.0);
726+
assert_eq!((-9.0 as $fty).minimum(0.0), -9.0);
727+
assert_eq!((0.0 as $fty).minimum(9.0), 0.0);
728+
assert!((0.0 as $fty).minimum(9.0).is_sign_positive());
729+
assert_eq!((-0.0 as $fty).minimum(9.0), -0.0);
730+
assert!((-0.0 as $fty).minimum(9.0).is_sign_negative());
731+
assert_eq!((-0.0 as $fty).minimum(-9.0), -9.0);
732+
assert_eq!(($inf as $fty).minimum(9.0), 9.0);
733+
assert_eq!((9.0 as $fty).minimum($inf), 9.0);
734+
assert_eq!(($inf as $fty).minimum(-9.0), -9.0);
735+
assert_eq!((-9.0 as $fty).minimum($inf), -9.0);
736+
assert_eq!(($neginf as $fty).minimum(9.0), $neginf);
737+
assert_eq!((9.0 as $fty).minimum($neginf), $neginf);
738+
assert_eq!(($neginf as $fty).minimum(-9.0), $neginf);
739+
assert_eq!((-9.0 as $fty).minimum($neginf), $neginf);
740+
assert!(($nan as $fty).minimum(9.0).is_nan());
741+
assert!(($nan as $fty).minimum(-9.0).is_nan());
742+
assert!((9.0 as $fty).minimum($nan).is_nan());
743+
assert!((-9.0 as $fty).minimum($nan).is_nan());
744+
assert!(($nan as $fty).minimum($nan).is_nan());
745+
}
746+
#[test]
747+
fn maximum() {
748+
assert_eq!((0.0 as $fty).maximum(0.0), 0.0);
749+
assert!((0.0 as $fty).maximum(0.0).is_sign_positive());
750+
assert_eq!((-0.0 as $fty).maximum(0.0), 0.0);
751+
assert!((-0.0 as $fty).maximum(0.0).is_sign_positive());
752+
assert_eq!((-0.0 as $fty).maximum(-0.0), -0.0);
753+
assert!((-0.0 as $fty).maximum(-0.0).is_sign_negative());
754+
assert_eq!((9.0 as $fty).maximum(9.0), 9.0);
755+
assert_eq!((-9.0 as $fty).maximum(0.0), 0.0);
756+
assert!((-9.0 as $fty).maximum(0.0).is_sign_positive());
757+
assert_eq!((-9.0 as $fty).maximum(-0.0), -0.0);
758+
assert!((-9.0 as $fty).maximum(-0.0).is_sign_negative());
759+
assert_eq!((0.0 as $fty).maximum(9.0), 9.0);
760+
assert_eq!((0.0 as $fty).maximum(-9.0), 0.0);
761+
assert!((0.0 as $fty).maximum(-9.0).is_sign_positive());
762+
assert_eq!((-0.0 as $fty).maximum(-9.0), -0.0);
763+
assert!((-0.0 as $fty).maximum(-9.0).is_sign_negative());
764+
assert_eq!(($inf as $fty).maximum(9.0), $inf);
765+
assert_eq!((9.0 as $fty).maximum($inf), $inf);
766+
assert_eq!(($inf as $fty).maximum(-9.0), $inf);
767+
assert_eq!((-9.0 as $fty).maximum($inf), $inf);
768+
assert_eq!(($neginf as $fty).maximum(9.0), 9.0);
769+
assert_eq!((9.0 as $fty).maximum($neginf), 9.0);
770+
assert_eq!(($neginf as $fty).maximum(-9.0), -9.0);
771+
assert_eq!((-9.0 as $fty).maximum($neginf), -9.0);
772+
assert!(($nan as $fty).maximum(9.0).is_nan());
773+
assert!(($nan as $fty).maximum(-9.0).is_nan());
774+
assert!((9.0 as $fty).maximum($nan).is_nan());
775+
assert!((-9.0 as $fty).maximum($nan).is_nan());
776+
assert!(($nan as $fty).maximum($nan).is_nan());
777+
}
778+
#[test]
718779
fn rem_euclid() {
719780
let a: $fty = 42.0;
720781
assert!($inf.rem_euclid(a).is_nan());

library/std/src/f32/tests.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ fn test_max_nan() {
1919
assert_eq!(2.0f32.max(f32::NAN), 2.0);
2020
}
2121

22+
#[test]
23+
fn test_minimum() {
24+
assert!(f32::NAN.minimum(2.0).is_nan());
25+
assert!(2.0f32.minimum(f32::NAN).is_nan());
26+
}
27+
28+
#[test]
29+
fn test_maximum() {
30+
assert!(f32::NAN.maximum(2.0).is_nan());
31+
assert!(2.0f32.maximum(f32::NAN).is_nan());
32+
}
33+
2234
#[test]
2335
fn test_nan() {
2436
let nan: f32 = f32::NAN;

library/std/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@
287287
#![feature(exhaustive_patterns)]
288288
#![feature(extend_one)]
289289
#![feature(fn_traits)]
290+
#![feature(float_minimum_maximum)]
290291
#![feature(format_args_nl)]
291292
#![feature(gen_future)]
292293
#![feature(generator_trait)]

0 commit comments

Comments
 (0)