]> git.lizzy.rs Git - rust.git/blobdiff - src/libstd/num/f32.rs
std: Stabilize/deprecate features for 1.4
[rust.git] / src / libstd / num / f32.rs
index 6a8026a807e726925ad17f6145181e9f043a1512..a04dfbeebe8e6b18704e3d2b88d4057a4381ef05 100644 (file)
@@ -16,7 +16,6 @@
 #![allow(missing_docs)]
 
 use core::num;
-#[cfg(not(target_env = "msvc"))]
 use intrinsics;
 use libc::c_int;
 use num::{FpCategory, ParseFloatError};
@@ -40,11 +39,11 @@ mod cmath {
         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 nextafterf(x: c_float, y: c_float) -> c_float;
+        pub fn ilogbf(n: c_float) -> c_int;
         pub fn logbf(n: c_float) -> c_float;
         pub fn log1pf(n: c_float) -> c_float;
-        pub fn ilogbf(n: c_float) -> c_int;
         pub fn modff(n: c_float, iptr: &mut c_float) -> c_float;
+        pub fn nextafterf(x: c_float, y: c_float) -> c_float;
         pub fn tgammaf(n: c_float) -> c_float;
 
         #[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgammaf_r")]
@@ -124,7 +123,10 @@ pub unsafe fn tanhf(n: c_float) -> c_float {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl f32 {
     /// Parses a float as with a given radix
-    #[unstable(feature = "float_from_str_radix", reason = "recently moved API")]
+    #[unstable(feature = "float_from_str_radix", reason = "recently moved API",
+               issue = "27736")]
+    #[deprecated(since = "1.4.0",
+                 reason = "unclear how useful or correct this is")]
     pub fn from_str_radix(s: &str, radix: u32) -> Result<f32, ParseFloatError> {
         num::Float::from_str_radix(s, radix)
     }
@@ -251,7 +253,8 @@ pub fn classify(self) -> FpCategory { num::Float::classify(self) }
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
     /// [floating-point]: ../../../../../reference.html#machine-types
-    #[unstable(feature = "float_extras", reason = "signature is undecided")]
+    #[unstable(feature = "float_extras", reason = "signature is undecided",
+               issue = "27752")]
     #[inline]
     pub fn integer_decode(self) -> (u64, i16, i8) {
         num::Float::integer_decode(self)
@@ -268,7 +271,27 @@ pub fn integer_decode(self) -> (u64, i16, i8) {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn floor(self) -> f32 { num::Float::floor(self) }
+    pub fn floor(self) -> f32 {
+        return floorf(self);
+
+        // On MSVC LLVM will lower many math intrinsics to a call to the
+        // corresponding function. On MSVC, however, many of these functions
+        // aren't actually available as symbols to call, but rather they are all
+        // `static inline` functions in header files. This means that from a C
+        // perspective it's "compatible", but not so much from an ABI
+        // perspective (which we're worried about).
+        //
+        // The inline header functions always just cast to a f64 and do their
+        // operation, so we do that here as well, but only for MSVC targets.
+        //
+        // Note that there are many MSVC-specific float operations which
+        // redirect to this comment, so `floorf` is just one case of a missing
+        // function on MSVC, but there are many others elsewhere.
+        #[cfg(target_env = "msvc")]
+        fn floorf(f: f32) -> f32 { (f as f64).floor() as f32 }
+        #[cfg(not(target_env = "msvc"))]
+        fn floorf(f: f32) -> f32 { unsafe { intrinsics::floorf32(f) } }
+    }
 
     /// Returns the smallest integer greater than or equal to a number.
     ///
@@ -281,7 +304,15 @@ pub fn floor(self) -> f32 { num::Float::floor(self) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn ceil(self) -> f32 { num::Float::ceil(self) }
+    pub fn ceil(self) -> f32 {
+        return ceilf(self);
+
+        // see notes above in `floor`
+        #[cfg(target_env = "msvc")]
+        fn ceilf(f: f32) -> f32 { (f as f64).ceil() as f32 }
+        #[cfg(not(target_env = "msvc"))]
+        fn ceilf(f: f32) -> f32 { unsafe { intrinsics::ceilf32(f) } }
+    }
 
     /// Returns the nearest integer to a number. Round half-way cases away from
     /// `0.0`.
@@ -295,7 +326,9 @@ pub fn ceil(self) -> f32 { num::Float::ceil(self) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn round(self) -> f32 { num::Float::round(self) }
+    pub fn round(self) -> f32 {
+        unsafe { intrinsics::roundf32(self) }
+    }
 
     /// Returns the integer part of a number.
     ///
@@ -308,7 +341,9 @@ pub fn round(self) -> f32 { num::Float::round(self) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn trunc(self) -> f32 { num::Float::trunc(self) }
+    pub fn trunc(self) -> f32 {
+        unsafe { intrinsics::truncf32(self) }
+    }
 
     /// Returns the fractional part of a number.
     ///
@@ -325,7 +360,7 @@ pub fn trunc(self) -> f32 { num::Float::trunc(self) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn fract(self) -> f32 { num::Float::fract(self) }
+    pub fn fract(self) -> f32 { self - self.trunc() }
 
     /// Computes the absolute value of `self`. Returns `NAN` if the
     /// number is `NAN`.
@@ -424,7 +459,9 @@ pub fn is_sign_negative(self) -> bool { num::Float::is_negative(self) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn mul_add(self, a: f32, b: f32) -> f32 { num::Float::mul_add(self, a, b) }
+    pub fn mul_add(self, a: f32, b: f32) -> f32 {
+        unsafe { intrinsics::fmaf32(self, a, b) }
+    }
 
     /// Takes the reciprocal (inverse) of a number, `1/x`.
     ///
@@ -468,7 +505,15 @@ pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn powf(self, n: f32) -> f32 { num::Float::powf(self, n) }
+    pub fn powf(self, n: f32) -> f32 {
+        return powf(self, n);
+
+        // see notes above in `floor`
+        #[cfg(target_env = "msvc")]
+        fn powf(f: f32, n: f32) -> f32 { (f as f64).powf(n as f64) as f32 }
+        #[cfg(not(target_env = "msvc"))]
+        fn powf(f: f32, n: f32) -> f32 { unsafe { intrinsics::powf32(f, n) } }
+    }
 
     /// Takes the square root of a number.
     ///
@@ -487,7 +532,13 @@ pub fn powf(self, n: f32) -> f32 { num::Float::powf(self, n) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn sqrt(self) -> f32 { num::Float::sqrt(self) }
+    pub fn sqrt(self) -> f32 {
+        if self < 0.0 {
+            NAN
+        } else {
+            unsafe { intrinsics::sqrtf32(self) }
+        }
+    }
 
     /// Returns `e^(self)`, (the exponential function).
     ///
@@ -505,7 +556,15 @@ pub fn sqrt(self) -> f32 { num::Float::sqrt(self) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn exp(self) -> f32 { num::Float::exp(self) }
+    pub fn exp(self) -> f32 {
+        return expf(self);
+
+        // see notes above in `floor`
+        #[cfg(target_env = "msvc")]
+        fn expf(f: f32) -> f32 { (f as f64).exp() as f32 }
+        #[cfg(not(target_env = "msvc"))]
+        fn expf(f: f32) -> f32 { unsafe { intrinsics::expf32(f) } }
+    }
 
     /// Returns `2^(self)`.
     ///
@@ -521,7 +580,9 @@ pub fn exp(self) -> f32 { num::Float::exp(self) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn exp2(self) -> f32 { num::Float::exp2(self) }
+    pub fn exp2(self) -> f32 {
+        unsafe { intrinsics::exp2f32(self) }
+    }
 
     /// Returns the natural logarithm of the number.
     ///
@@ -539,7 +600,15 @@ pub fn exp2(self) -> f32 { num::Float::exp2(self) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn ln(self) -> f32 { num::Float::ln(self) }
+    pub fn ln(self) -> f32 {
+        return logf(self);
+
+        // see notes above in `floor`
+        #[cfg(target_env = "msvc")]
+        fn logf(f: f32) -> f32 { (f as f64).ln() as f32 }
+        #[cfg(not(target_env = "msvc"))]
+        fn logf(f: f32) -> f32 { unsafe { intrinsics::logf32(f) } }
+    }
 
     /// Returns the logarithm of the number with respect to an arbitrary base.
     ///
@@ -560,7 +629,7 @@ pub fn ln(self) -> f32 { num::Float::ln(self) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn log(self, base: f32) -> f32 { num::Float::log(self, base) }
+    pub fn log(self, base: f32) -> f32 { self.ln() / base.ln() }
 
     /// Returns the base 2 logarithm of the number.
     ///
@@ -576,7 +645,9 @@ pub fn log(self, base: f32) -> f32 { num::Float::log(self, base) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn log2(self) -> f32 { num::Float::log2(self) }
+    pub fn log2(self) -> f32 {
+        unsafe { intrinsics::log2f32(self) }
+    }
 
     /// Returns the base 10 logarithm of the number.
     ///
@@ -592,7 +663,15 @@ pub fn log2(self) -> f32 { num::Float::log2(self) }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn log10(self) -> f32 { num::Float::log10(self) }
+    pub fn log10(self) -> f32 {
+        return log10f(self);
+
+        // see notes above in `floor`
+        #[cfg(target_env = "msvc")]
+        fn log10f(f: f32) -> f32 { (f as f64).log10() as f32 }
+        #[cfg(not(target_env = "msvc"))]
+        fn log10f(f: f32) -> f32 { unsafe { intrinsics::log10f32(f) } }
+    }
 
     /// Converts radians to degrees.
     ///
@@ -607,7 +686,8 @@ pub fn log10(self) -> f32 { num::Float::log10(self) }
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
-    #[unstable(feature = "float_extras", reason = "desirability is unclear")]
+    #[unstable(feature = "float_extras", reason = "desirability is unclear",
+               issue = "27752")]
     #[inline]
     pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) }
 
@@ -624,7 +704,8 @@ pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) }
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
-    #[unstable(feature = "float_extras", reason = "desirability is unclear")]
+    #[unstable(feature = "float_extras", reason = "desirability is unclear",
+               issue = "27752")]
     #[inline]
     pub fn to_radians(self) -> f32 { num::Float::to_radians(self) }
 
@@ -640,7 +721,8 @@ pub fn to_radians(self) -> f32 { num::Float::to_radians(self) }
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
     #[unstable(feature = "float_extras",
-               reason = "pending integer conventions")]
+               reason = "pending integer conventions",
+               issue = "27752")]
     #[inline]
     pub fn ldexp(x: f32, exp: isize) -> f32 {
         unsafe { cmath::ldexpf(x, exp as c_int) }
@@ -668,7 +750,8 @@ pub fn ldexp(x: f32, exp: isize) -> f32 {
     /// assert!(abs_difference_1 <= f32::EPSILON);
     /// ```
     #[unstable(feature = "float_extras",
-               reason = "pending integer conventions")]
+               reason = "pending integer conventions",
+               issue = "27752")]
     #[inline]
     pub fn frexp(self) -> (f32, isize) {
         unsafe {
@@ -693,7 +776,8 @@ pub fn frexp(self) -> (f32, isize) {
     /// assert!(abs_diff <= f32::EPSILON);
     /// ```
     #[unstable(feature = "float_extras",
-               reason = "unsure about its place in the world")]
+               reason = "unsure about its place in the world",
+               issue = "27752")]
     #[inline]
     pub fn next_after(self, other: f32) -> f32 {
         unsafe { cmath::nextafterf(self, other) }
@@ -1751,7 +1835,6 @@ fn test_real_consts() {
         use super::consts;
 
         let pi: f32 = consts::PI;
-        let two_pi: f32 = consts::PI_2;
         let frac_pi_2: f32 = consts::FRAC_PI_2;
         let frac_pi_3: f32 = consts::FRAC_PI_3;
         let frac_pi_4: f32 = consts::FRAC_PI_4;
@@ -1768,7 +1851,6 @@ fn test_real_consts() {
         let ln_2: f32 = consts::LN_2;
         let ln_10: f32 = consts::LN_10;
 
-        assert_approx_eq!(two_pi, 2f32 * pi);
         assert_approx_eq!(frac_pi_2, pi / 2f32);
         assert_approx_eq!(frac_pi_3, pi / 3f32);
         assert_approx_eq!(frac_pi_4, pi / 4f32);