summaryrefslogtreecommitdiffstats
path: root/vendor/num-traits/src/float.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/num-traits/src/float.rs')
-rw-r--r--vendor/num-traits/src/float.rs319
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>();
}
}