]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #42430 - nagisa:core-float, r=alexcrichton
authorbors <bors@rust-lang.org>
Fri, 16 Jun 2017 17:52:11 +0000 (17:52 +0000)
committerbors <bors@rust-lang.org>
Fri, 16 Jun 2017 17:52:11 +0000 (17:52 +0000)
Re-implement float min/max in rust

This also adds the relevant implementations into libcore.

See #42423

src/libcore/num/f32.rs
src/libcore/num/f64.rs
src/libcore/num/mod.rs
src/libcore/tests/lib.rs
src/libcore/tests/num/mod.rs
src/libstd/f32.rs
src/libstd/f64.rs

index 91ca213e96e0d19b84c38b83668d193790804020..cb28035682d650607409d522448243413a03630b 100644 (file)
@@ -242,4 +242,32 @@ fn to_radians(self) -> f32 {
         let value: f32 = consts::PI;
         self * (value / 180.0f32)
     }
+
+    /// Returns the maximum of the two numbers.
+    #[inline]
+    fn max(self, other: f32) -> f32 {
+        // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the
+        // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
+        // is either x or y, canonicalized (this means results might differ among implementations).
+        // When either x or y is a signalingNaN, then the result is according to 6.2.
+        //
+        // Since we do not support sNaN in Rust yet, we do not need to handle them.
+        // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
+        // multiplying by 1.0. Should switch to the `canonicalize` when it works.
+        (if self < other || self.is_nan() { other } else { self }) * 1.0
+    }
+
+    /// Returns the minimum of the two numbers.
+    #[inline]
+    fn min(self, other: f32) -> f32 {
+        // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the
+        // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
+        // is either x or y, canonicalized (this means results might differ among implementations).
+        // When either x or y is a signalingNaN, then the result is according to 6.2.
+        //
+        // Since we do not support sNaN in Rust yet, we do not need to handle them.
+        // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
+        // multiplying by 1.0. Should switch to the `canonicalize` when it works.
+        (if self < other || other.is_nan() { self } else { other }) * 1.0
+    }
 }
index 7d6d6cef049772f3f2d267a394cf44125015ad69..ac6b1e67cd2785b17154e76062210bb6f6f76f8c 100644 (file)
@@ -242,4 +242,32 @@ fn to_radians(self) -> f64 {
         let value: f64 = consts::PI;
         self * (value / 180.0)
     }
+
+    /// Returns the maximum of the two numbers.
+    #[inline]
+    fn max(self, other: f64) -> f64 {
+        // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the
+        // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
+        // is either x or y, canonicalized (this means results might differ among implementations).
+        // When either x or y is a signalingNaN, then the result is according to 6.2.
+        //
+        // Since we do not support sNaN in Rust yet, we do not need to handle them.
+        // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
+        // multiplying by 1.0. Should switch to the `canonicalize` when it works.
+        (if self < other || self.is_nan() { other } else { self }) * 1.0
+    }
+
+    /// Returns the minimum of the two numbers.
+    #[inline]
+    fn min(self, other: f64) -> f64 {
+        // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the
+        // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
+        // is either x or y, canonicalized (this means results might differ among implementations).
+        // When either x or y is a signalingNaN, then the result is according to 6.2.
+        //
+        // Since we do not support sNaN in Rust yet, we do not need to handle them.
+        // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
+        // multiplying by 1.0. Should switch to the `canonicalize` when it works.
+        (if self < other || other.is_nan() { self } else { other }) * 1.0
+    }
 }
index 62d75445cc95e81129988dc75713ba2b9bdf1b7e..cbd59ed3713776f84b6cf42129c11c8742dc2ab9 100644 (file)
@@ -2459,6 +2459,13 @@ pub trait Float: Sized {
     /// Convert degrees to radians.
     #[stable(feature = "deg_rad_conversions", since="1.7.0")]
     fn to_radians(self) -> Self;
+
+    /// Returns the maximum of the two numbers.
+    #[stable(feature = "core_float_min_max", since="1.20.0")]
+    fn max(self, other: Self) -> Self;
+    /// Returns the minimum of the two numbers.
+    #[stable(feature = "core_float_min_max", since="1.20.0")]
+    fn min(self, other: Self) -> Self;
 }
 
 macro_rules! from_str_radix_int_impl {
index 77a9307f43ecf97375ea03c0cf4d1b85ccd8bf19..337f8aa31dc4603ee9a563c2a2f153a7b57ace6f 100644 (file)
@@ -13,6 +13,7 @@
 #![feature(box_syntax)]
 #![feature(char_escape_debug)]
 #![feature(const_fn)]
+#![feature(core_float)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
 #![feature(dec2flt)]
index 8fdcc36a268e8a9288d637a00bc7cd675c7c4123..f233b649a8f3c6bda621047a70bae2ff9ff88381 100644 (file)
@@ -399,3 +399,57 @@ fn $fn_name() {
 test_impl_try_from_signed_to_unsigned_err! { test_try_i64u8, i64, u8 }
 test_impl_try_from_signed_to_unsigned_err! { test_try_i64u16, i64, u16 }
 test_impl_try_from_signed_to_unsigned_err! { test_try_i64u32, i64, u32 }
+
+macro_rules! test_float {
+    ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => { mod $modname {
+        use core::num::Float;
+        // FIXME(nagisa): these tests should test for sign of -0.0
+        #[test]
+        fn min() {
+            assert_eq!(0.0.min(0.0), 0.0);
+            assert_eq!((-0.0).min(-0.0), -0.0);
+            assert_eq!(9.0.min(9.0), 9.0);
+            assert_eq!((-9.0).min(0.0), -9.0);
+            assert_eq!(0.0.min(9.0), 0.0);
+            assert_eq!((-0.0).min(-9.0), -9.0);
+            assert_eq!($inf.min(9.0), 9.0);
+            assert_eq!(9.0.min($inf), 9.0);
+            assert_eq!($inf.min(-9.0), -9.0);
+            assert_eq!((-9.0).min($inf), -9.0);
+            assert_eq!($neginf.min(9.0), $neginf);
+            assert_eq!(9.0.min($neginf), $neginf);
+            assert_eq!($neginf.min(-9.0), $neginf);
+            assert_eq!((-9.0).min($neginf), $neginf);
+            assert_eq!($nan.min(9.0), 9.0);
+            assert_eq!($nan.min(-9.0), -9.0);
+            assert_eq!(9.0.min($nan), 9.0);
+            assert_eq!((-9.0).min($nan), -9.0);
+            assert!($nan.min($nan).is_nan());
+        }
+        #[test]
+        fn max() {
+            assert_eq!(0.0.max(0.0), 0.0);
+            assert_eq!((-0.0).max(-0.0), -0.0);
+            assert_eq!(9.0.max(9.0), 9.0);
+            assert_eq!((-9.0).max(0.0), 0.0);
+            assert_eq!(0.0.max(9.0), 9.0);
+            assert_eq!((-0.0).max(-9.0), -0.0);
+            assert_eq!($inf.max(9.0), $inf);
+            assert_eq!(9.0.max($inf), $inf);
+            assert_eq!($inf.max(-9.0), $inf);
+            assert_eq!((-9.0).max($inf), $inf);
+            assert_eq!($neginf.max(9.0), 9.0);
+            assert_eq!(9.0.max($neginf), 9.0);
+            assert_eq!($neginf.max(-9.0), -9.0);
+            assert_eq!((-9.0).max($neginf), -9.0);
+            assert_eq!($nan.max(9.0), 9.0);
+            assert_eq!($nan.max(-9.0), -9.0);
+            assert_eq!(9.0.max($nan), 9.0);
+            assert_eq!((-9.0).max($nan), -9.0);
+            assert!($nan.max($nan).is_nan());
+        }
+    } }
+}
+
+test_float!(f32, f32, ::core::f32::INFINITY, ::core::f32::NEG_INFINITY, ::core::f32::NAN);
+test_float!(f64, f64, ::core::f64::INFINITY, ::core::f64::NEG_INFINITY, ::core::f64::NAN);
index 4abad7e24f8107a6b2690399190104eec2bf07ba..6134b0b882c5bb80c133ee57b3cbd165294b3451 100644 (file)
@@ -46,8 +46,6 @@ mod cmath {
         pub fn erfcf(n: c_float) -> c_float;
         pub fn expm1f(n: c_float) -> c_float;
         pub fn fdimf(a: c_float, b: c_float) -> c_float;
-        pub fn fmaxf(a: c_float, b: c_float) -> c_float;
-        pub fn fminf(a: c_float, b: c_float) -> c_float;
         pub fn fmodf(a: c_float, b: c_float) -> c_float;
         pub fn ilogbf(n: c_float) -> c_int;
         pub fn logbf(n: c_float) -> c_float;
@@ -673,7 +671,7 @@ pub fn to_radians(self) -> f32 { num::Float::to_radians(self) }
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn max(self, other: f32) -> f32 {
-        unsafe { cmath::fmaxf(self, other) }
+        num::Float::max(self, other)
     }
 
     /// Returns the minimum of the two numbers.
@@ -689,7 +687,7 @@ pub fn max(self, other: f32) -> f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn min(self, other: f32) -> f32 {
-        unsafe { cmath::fminf(self, other) }
+        num::Float::min(self, other)
     }
 
     /// The positive difference of two numbers.
index 813998b75028f5907d21cfb38caf85ace7d0f679..e8d25cfbf949a93c9f9ac81216d3ee16133be22f 100644 (file)
@@ -51,8 +51,6 @@ mod cmath {
         pub fn erfc(n: c_double) -> c_double;
         pub fn expm1(n: c_double) -> c_double;
         pub fn fdim(a: c_double, b: c_double) -> c_double;
-        pub fn fmax(a: c_double, b: c_double) -> c_double;
-        pub fn fmin(a: c_double, b: c_double) -> c_double;
         pub fn fmod(a: c_double, b: c_double) -> c_double;
         pub fn frexp(n: c_double, value: &mut c_int) -> c_double;
         pub fn ilogb(n: c_double) -> c_int;
@@ -587,7 +585,7 @@ pub fn to_radians(self) -> f64 { num::Float::to_radians(self) }
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn max(self, other: f64) -> f64 {
-        unsafe { cmath::fmax(self, other) }
+        num::Float::max(self, other)
     }
 
     /// Returns the minimum of the two numbers.
@@ -603,7 +601,7 @@ pub fn max(self, other: f64) -> f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn min(self, other: f64) -> f64 {
-        unsafe { cmath::fmin(self, other) }
+        num::Float::min(self, other)
     }
 
     /// The positive difference of two numbers.