diff options
Diffstat (limited to 'vendor/num-traits/src/float.rs')
-rw-r--r-- | vendor/num-traits/src/float.rs | 319 |
1 files changed, 156 insertions, 163 deletions
diff --git a/vendor/num-traits/src/float.rs b/vendor/num-traits/src/float.rs index 47bd65431..87f8387b8 100644 --- a/vendor/num-traits/src/float.rs +++ b/vendor/num-traits/src/float.rs @@ -1,14 +1,10 @@ -use core::mem; use core::num::FpCategory; use core::ops::{Add, Div, Neg}; use core::f32; use core::f64; -use {Num, NumCast, ToPrimitive}; - -#[cfg(all(not(feature = "std"), feature = "libm"))] -use libm; +use crate::{Num, NumCast, ToPrimitive}; /// Generic trait for floating point numbers that works with `no_std`. /// @@ -170,6 +166,7 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy { /// check(0.0f64, false); /// ``` #[inline] + #[allow(clippy::eq_op)] fn is_nan(self) -> bool { self != self } @@ -244,6 +241,32 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy { self.classify() == FpCategory::Normal } + /// Returns `true` if the number is [subnormal]. + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::f64; + /// + /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308_f64 + /// let max = f64::MAX; + /// let lower_than_min = 1.0e-308_f64; + /// let zero = 0.0_f64; + /// + /// assert!(!min.is_subnormal()); + /// assert!(!max.is_subnormal()); + /// + /// assert!(!zero.is_subnormal()); + /// assert!(!f64::NAN.is_subnormal()); + /// assert!(!f64::INFINITY.is_subnormal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(lower_than_min.is_subnormal()); + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Subnormal_number + #[inline] + fn is_subnormal(self) -> bool { + self.classify() == FpCategory::Subnormal + } + /// Returns the floating point category of the number. If only one property /// is going to be tested, it is generally faster to use the specific /// predicate instead. @@ -370,12 +393,10 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy { } else { self - f + one } + } else if -f < h { + self - f } else { - if -f < h { - self - f - } else { - self - f - one - } + self - f - one } } @@ -508,8 +529,7 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy { } /// Returns `true` if `self` is positive, including `+0.0` and - /// `FloatCore::infinity()`, and since Rust 1.20 also - /// `FloatCore::nan()`. + /// `FloatCore::infinity()`, and `FloatCore::nan()`. /// /// # Examples /// @@ -527,6 +547,7 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy { /// check(-0.0f64, false); /// check(f64::NEG_INFINITY, false); /// check(f64::MIN_POSITIVE, true); + /// check(f64::NAN, true); /// check(-f64::NAN, false); /// ``` #[inline] @@ -535,8 +556,7 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy { } /// Returns `true` if `self` is negative, including `-0.0` and - /// `FloatCore::neg_infinity()`, and since Rust 1.20 also - /// `-FloatCore::nan()`. + /// `FloatCore::neg_infinity()`, and `-FloatCore::nan()`. /// /// # Examples /// @@ -555,6 +575,7 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy { /// check(f64::NEG_INFINITY, true); /// check(f64::MIN_POSITIVE, false); /// check(f64::NAN, false); + /// check(-f64::NAN, true); /// ``` #[inline] fn is_sign_negative(self) -> bool { @@ -763,56 +784,28 @@ impl FloatCore for f32 { integer_decode_f32(self) } - #[inline] - #[cfg(not(feature = "std"))] - fn classify(self) -> FpCategory { - const EXP_MASK: u32 = 0x7f800000; - const MAN_MASK: u32 = 0x007fffff; - - // Safety: this identical to the implementation of f32::to_bits(), - // which is only available starting at Rust 1.20 - let bits: u32 = unsafe { mem::transmute(self) }; - match (bits & MAN_MASK, bits & EXP_MASK) { - (0, 0) => FpCategory::Zero, - (_, 0) => FpCategory::Subnormal, - (0, EXP_MASK) => FpCategory::Infinite, - (_, EXP_MASK) => FpCategory::Nan, - _ => FpCategory::Normal, - } - } - - #[inline] - #[cfg(not(feature = "std"))] - fn is_sign_negative(self) -> bool { - const SIGN_MASK: u32 = 0x80000000; - - // Safety: this identical to the implementation of f32::to_bits(), - // which is only available starting at Rust 1.20 - let bits: u32 = unsafe { mem::transmute(self) }; - bits & SIGN_MASK != 0 - } - - #[inline] - #[cfg(not(feature = "std"))] - fn to_degrees(self) -> Self { - // Use a constant for better precision. - const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; - self * PIS_IN_180 - } - - #[inline] - #[cfg(not(feature = "std"))] - fn to_radians(self) -> Self { - self * (f32::consts::PI / 180.0) - } - - #[cfg(feature = "std")] forward! { Self::is_nan(self) -> bool; Self::is_infinite(self) -> bool; Self::is_finite(self) -> bool; Self::is_normal(self) -> bool; Self::classify(self) -> FpCategory; + Self::is_sign_positive(self) -> bool; + Self::is_sign_negative(self) -> bool; + Self::min(self, other: Self) -> Self; + Self::max(self, other: Self) -> Self; + Self::recip(self) -> Self; + Self::to_degrees(self) -> Self; + Self::to_radians(self) -> Self; + } + + #[cfg(has_is_subnormal)] + forward! { + Self::is_subnormal(self) -> bool; + } + + #[cfg(feature = "std")] + forward! { Self::floor(self) -> Self; Self::ceil(self) -> Self; Self::round(self) -> Self; @@ -820,14 +813,7 @@ impl FloatCore for f32 { Self::fract(self) -> Self; Self::abs(self) -> Self; Self::signum(self) -> Self; - Self::is_sign_positive(self) -> bool; - Self::is_sign_negative(self) -> bool; - Self::min(self, other: Self) -> Self; - Self::max(self, other: Self) -> Self; - Self::recip(self) -> Self; Self::powi(self, n: i32) -> Self; - Self::to_degrees(self) -> Self; - Self::to_radians(self) -> Self; } #[cfg(all(not(feature = "std"), feature = "libm"))] @@ -837,8 +823,6 @@ impl FloatCore for f32 { libm::roundf as round(self) -> Self; libm::truncf as trunc(self) -> Self; libm::fabsf as abs(self) -> Self; - libm::fminf as min(self, other: Self) -> Self; - libm::fmaxf as max(self, other: Self) -> Self; } #[cfg(all(not(feature = "std"), feature = "libm"))] @@ -865,57 +849,28 @@ impl FloatCore for f64 { integer_decode_f64(self) } - #[inline] - #[cfg(not(feature = "std"))] - fn classify(self) -> FpCategory { - const EXP_MASK: u64 = 0x7ff0000000000000; - const MAN_MASK: u64 = 0x000fffffffffffff; - - // Safety: this identical to the implementation of f64::to_bits(), - // which is only available starting at Rust 1.20 - let bits: u64 = unsafe { mem::transmute(self) }; - match (bits & MAN_MASK, bits & EXP_MASK) { - (0, 0) => FpCategory::Zero, - (_, 0) => FpCategory::Subnormal, - (0, EXP_MASK) => FpCategory::Infinite, - (_, EXP_MASK) => FpCategory::Nan, - _ => FpCategory::Normal, - } - } - - #[inline] - #[cfg(not(feature = "std"))] - fn is_sign_negative(self) -> bool { - const SIGN_MASK: u64 = 0x8000000000000000; - - // Safety: this identical to the implementation of f64::to_bits(), - // which is only available starting at Rust 1.20 - let bits: u64 = unsafe { mem::transmute(self) }; - bits & SIGN_MASK != 0 - } - - #[inline] - #[cfg(not(feature = "std"))] - fn to_degrees(self) -> Self { - // The division here is correctly rounded with respect to the true - // value of 180/π. (This differs from f32, where a constant must be - // used to ensure a correctly rounded result.) - self * (180.0 / f64::consts::PI) - } - - #[inline] - #[cfg(not(feature = "std"))] - fn to_radians(self) -> Self { - self * (f64::consts::PI / 180.0) - } - - #[cfg(feature = "std")] forward! { Self::is_nan(self) -> bool; Self::is_infinite(self) -> bool; Self::is_finite(self) -> bool; Self::is_normal(self) -> bool; Self::classify(self) -> FpCategory; + Self::is_sign_positive(self) -> bool; + Self::is_sign_negative(self) -> bool; + Self::min(self, other: Self) -> Self; + Self::max(self, other: Self) -> Self; + Self::recip(self) -> Self; + Self::to_degrees(self) -> Self; + Self::to_radians(self) -> Self; + } + + #[cfg(has_is_subnormal)] + forward! { + Self::is_subnormal(self) -> bool; + } + + #[cfg(feature = "std")] + forward! { Self::floor(self) -> Self; Self::ceil(self) -> Self; Self::round(self) -> Self; @@ -923,14 +878,7 @@ impl FloatCore for f64 { Self::fract(self) -> Self; Self::abs(self) -> Self; Self::signum(self) -> Self; - Self::is_sign_positive(self) -> bool; - Self::is_sign_negative(self) -> bool; - Self::min(self, other: Self) -> Self; - Self::max(self, other: Self) -> Self; - Self::recip(self) -> Self; Self::powi(self, n: i32) -> Self; - Self::to_degrees(self) -> Self; - Self::to_radians(self) -> Self; } #[cfg(all(not(feature = "std"), feature = "libm"))] @@ -940,8 +888,6 @@ impl FloatCore for f64 { libm::round as round(self) -> Self; libm::trunc as trunc(self) -> Self; libm::fabs as abs(self) -> Self; - libm::fmin as min(self, other: Self) -> Self; - libm::fmax as max(self, other: Self) -> Self; } #[cfg(all(not(feature = "std"), feature = "libm"))] @@ -1138,9 +1084,35 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> { /// // Values between `0` and `min` are Subnormal. /// assert!(!lower_than_min.is_normal()); /// ``` - /// [subnormal]: http://en.wikipedia.org/wiki/Denormal_number + /// [subnormal]: http://en.wikipedia.org/wiki/Subnormal_number fn is_normal(self) -> bool; + /// Returns `true` if the number is [subnormal]. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308_f64 + /// let max = f64::MAX; + /// let lower_than_min = 1.0e-308_f64; + /// let zero = 0.0_f64; + /// + /// assert!(!min.is_subnormal()); + /// assert!(!max.is_subnormal()); + /// + /// assert!(!zero.is_subnormal()); + /// assert!(!f64::NAN.is_subnormal()); + /// assert!(!f64::INFINITY.is_subnormal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(lower_than_min.is_subnormal()); + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Subnormal_number + #[inline] + fn is_subnormal(self) -> bool { + self.classify() == FpCategory::Subnormal + } + /// Returns the floating point category of the number. If only one property /// is going to be tested, it is generally faster to use the specific /// predicate instead. @@ -1266,12 +1238,13 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> { fn signum(self) -> Self; /// Returns `true` if `self` is positive, including `+0.0`, - /// `Float::infinity()`, and since Rust 1.20 also `Float::nan()`. + /// `Float::infinity()`, and `Float::nan()`. /// /// ``` /// use num_traits::Float; /// use std::f64; /// + /// let nan: f64 = f64::NAN; /// let neg_nan: f64 = -f64::NAN; /// /// let f = 7.0; @@ -1279,18 +1252,20 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> { /// /// assert!(f.is_sign_positive()); /// assert!(!g.is_sign_positive()); + /// assert!(nan.is_sign_positive()); /// assert!(!neg_nan.is_sign_positive()); /// ``` fn is_sign_positive(self) -> bool; /// Returns `true` if `self` is negative, including `-0.0`, - /// `Float::neg_infinity()`, and since Rust 1.20 also `-Float::nan()`. + /// `Float::neg_infinity()`, and `-Float::nan()`. /// /// ``` /// use num_traits::Float; /// use std::f64; /// /// let nan: f64 = f64::NAN; + /// let neg_nan: f64 = -f64::NAN; /// /// let f = 7.0; /// let g = -7.0; @@ -1298,6 +1273,7 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> { /// assert!(!f.is_sign_negative()); /// assert!(g.is_sign_negative()); /// assert!(!nan.is_sign_negative()); + /// assert!(neg_nan.is_sign_negative()); /// ``` fn is_sign_negative(self) -> bool; @@ -1970,9 +1946,13 @@ macro_rules! float_impl_std { } #[cfg(has_copysign)] - #[inline] - fn copysign(self, sign: Self) -> Self { - Self::copysign(self, sign) + forward! { + Self::copysign(self, sign: Self) -> Self; + } + + #[cfg(has_is_subnormal)] + forward! { + Self::is_subnormal(self) -> bool; } } }; @@ -2008,26 +1988,34 @@ macro_rules! float_impl_libm { } forward! { - FloatCore::is_nan(self) -> bool; - FloatCore::is_infinite(self) -> bool; - FloatCore::is_finite(self) -> bool; - FloatCore::is_normal(self) -> bool; - FloatCore::classify(self) -> FpCategory; + Self::is_nan(self) -> bool; + Self::is_infinite(self) -> bool; + Self::is_finite(self) -> bool; + Self::is_normal(self) -> bool; + Self::classify(self) -> FpCategory; + Self::is_sign_positive(self) -> bool; + Self::is_sign_negative(self) -> bool; + Self::min(self, other: Self) -> Self; + Self::max(self, other: Self) -> Self; + Self::recip(self) -> Self; + Self::to_degrees(self) -> Self; + Self::to_radians(self) -> Self; + } + + #[cfg(has_is_subnormal)] + forward! { + Self::is_subnormal(self) -> bool; + } + + forward! { FloatCore::signum(self) -> Self; - FloatCore::is_sign_positive(self) -> bool; - FloatCore::is_sign_negative(self) -> bool; - FloatCore::recip(self) -> Self; FloatCore::powi(self, n: i32) -> Self; - FloatCore::to_degrees(self) -> Self; - FloatCore::to_radians(self) -> Self; } }; } fn integer_decode_f32(f: f32) -> (u64, i16, i8) { - // Safety: this identical to the implementation of f32::to_bits(), - // which is only available starting at Rust 1.20 - let bits: u32 = unsafe { mem::transmute(f) }; + let bits: u32 = f.to_bits(); let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; let mantissa = if exponent == 0 { @@ -2041,9 +2029,7 @@ fn integer_decode_f32(f: f32) -> (u64, i16, i8) { } fn integer_decode_f64(f: f64) -> (u64, i16, i8) { - // Safety: this identical to the implementation of f64::to_bits(), - // which is only available starting at Rust 1.20 - let bits: u64 = unsafe { mem::transmute(f) }; + let bits: u64 = f.to_bits(); let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; let mantissa = if exponent == 0 { @@ -2103,8 +2089,6 @@ impl Float for f32 { libm::asinhf as asinh(self) -> Self; libm::acoshf as acosh(self) -> Self; libm::atanhf as atanh(self) -> Self; - libm::fmaxf as max(self, other: Self) -> Self; - libm::fminf as min(self, other: Self) -> Self; libm::copysignf as copysign(self, other: Self) -> Self; } } @@ -2151,8 +2135,6 @@ impl Float for f64 { libm::asinh as asinh(self) -> Self; libm::acosh as acosh(self) -> Self; libm::atanh as atanh(self) -> Self; - libm::fmax as max(self, other: Self) -> Self; - libm::fmin as min(self, other: Self) -> Self; libm::copysign as copysign(self, sign: Self) -> Self; } } @@ -2244,7 +2226,7 @@ mod tests { #[test] fn convert_deg_rad() { - use float::FloatCore; + use crate::float::FloatCore; for &(deg, rad) in &DEG_RAD_PAIRS { assert!((FloatCore::to_degrees(rad) - deg).abs() < 1e-6); @@ -2260,7 +2242,7 @@ mod tests { #[test] fn convert_deg_rad_std() { for &(deg, rad) in &DEG_RAD_PAIRS { - use Float; + use crate::Float; assert!((Float::to_degrees(rad) - deg).abs() < 1e-6); assert!((Float::to_radians(deg) - rad).abs() < 1e-6); @@ -2272,11 +2254,8 @@ mod tests { } #[test] - // This fails with the forwarded `std` implementation in Rust 1.8. - // To avoid the failure, the test is limited to `no_std` builds. - #[cfg(not(feature = "std"))] fn to_degrees_rounding() { - use float::FloatCore; + use crate::float::FloatCore; assert_eq!( FloatCore::to_degrees(1_f32), @@ -2287,7 +2266,7 @@ mod tests { #[test] #[cfg(any(feature = "std", feature = "libm"))] fn extra_logs() { - use float::{Float, FloatConst}; + use crate::float::{Float, FloatConst}; fn check<F: Float + FloatConst>(diff: F) { let _2 = F::from(2.0).unwrap(); @@ -2306,7 +2285,7 @@ mod tests { #[test] #[cfg(any(feature = "std", feature = "libm"))] fn copysign() { - use float::Float; + use crate::float::Float; test_copysign_generic(2.0_f32, -2.0_f32, f32::nan()); test_copysign_generic(2.0_f64, -2.0_f64, f64::nan()); test_copysignf(2.0_f32, -2.0_f32, f32::nan()); @@ -2314,8 +2293,8 @@ mod tests { #[cfg(any(feature = "std", feature = "libm"))] fn test_copysignf(p: f32, n: f32, nan: f32) { + use crate::float::Float; use core::ops::Neg; - use float::Float; assert!(p.is_sign_positive()); assert!(n.is_sign_negative()); @@ -2327,16 +2306,16 @@ mod tests { assert_eq!(n, Float::copysign(n, n)); assert_eq!(n.neg(), Float::copysign(n, p)); - // FIXME: is_sign... only works on NaN starting in Rust 1.20 - // assert!(Float::copysign(nan, p).is_sign_positive()); - // assert!(Float::copysign(nan, n).is_sign_negative()); + assert!(Float::copysign(nan, p).is_sign_positive()); + assert!(Float::copysign(nan, n).is_sign_negative()); } #[cfg(any(feature = "std", feature = "libm"))] - fn test_copysign_generic<F: ::float::Float + ::core::fmt::Debug>(p: F, n: F, nan: F) { + fn test_copysign_generic<F: crate::float::Float + ::core::fmt::Debug>(p: F, n: F, nan: F) { assert!(p.is_sign_positive()); assert!(n.is_sign_negative()); assert!(nan.is_nan()); + assert!(!nan.is_subnormal()); assert_eq!(p, p.copysign(p)); assert_eq!(p.neg(), p.copysign(n)); @@ -2344,8 +2323,22 @@ mod tests { assert_eq!(n, n.copysign(n)); assert_eq!(n.neg(), n.copysign(p)); - // FIXME: is_sign... only works on NaN starting in Rust 1.20 - // assert!(nan.copysign(p).is_sign_positive()); - // assert!(nan.copysign(n).is_sign_negative()); + assert!(nan.copysign(p).is_sign_positive()); + assert!(nan.copysign(n).is_sign_negative()); + } + + #[cfg(any(feature = "std", feature = "libm"))] + fn test_subnormal<F: crate::float::Float + ::core::fmt::Debug>() { + let min_positive = F::min_positive_value(); + let lower_than_min = min_positive / F::from(2.0f32).unwrap(); + assert!(!min_positive.is_subnormal()); + assert!(lower_than_min.is_subnormal()); + } + + #[test] + #[cfg(any(feature = "std", feature = "libm"))] + fn subnormal() { + test_subnormal::<f64>(); + test_subnormal::<f32>(); } } |