diff --git a/Cargo.toml b/Cargo.toml index c388e9e..b2f8af7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,7 @@ version = "0.1.41" readme = "README.md" [dependencies] + +[features] +default = ["std"] +std = [] diff --git a/src/bounds.rs b/src/bounds.rs index 83fdd0f..191f3e1 100644 --- a/src/bounds.rs +++ b/src/bounds.rs @@ -1,7 +1,7 @@ -use std::{usize, u8, u16, u32, u64}; -use std::{isize, i8, i16, i32, i64}; -use std::{f32, f64}; -use std::num::Wrapping; +use core::{usize, u8, u16, u32, u64}; +use core::{isize, i8, i16, i32, i64}; +use core::{f32, f64}; +use core::num::Wrapping; /// Numbers which have upper and lower bounds pub trait Bounded { diff --git a/src/cast.rs b/src/cast.rs index 62e6bf6..b8a516a 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -1,8 +1,9 @@ -use std::mem::size_of; -use std::num::Wrapping; +use core::mem::size_of; +use core::num::Wrapping; use identities::Zero; use bounds::Bounded; +use float::Float; /// A generic trait for converting a value to a number. pub trait ToPrimitive { @@ -226,8 +227,8 @@ macro_rules! impl_to_primitive_float_to_float { // Make sure the value is in range for the cast. // NaN and +-inf are cast as they are. let n = $slf as f64; - let max_value: $DstT = ::std::$DstT::MAX; - if !n.is_finite() || (-max_value as f64 <= n && n <= max_value as f64) { + let max_value: $DstT = ::core::$DstT::MAX; + if !Float::is_finite(n) || (-max_value as f64 <= n && n <= max_value as f64) { Some($slf as $DstT) } else { None @@ -454,8 +455,8 @@ impl NumCast for Wrapping { #[test] fn to_primitive_float() { - use std::f32; - use std::f64; + use core::f32; + use core::f64; let f32_toolarge = 1e39f64; assert_eq!(f32_toolarge.to_f32(), None); diff --git a/src/float.rs b/src/float.rs index 3c8779a..ea462b1 100644 --- a/src/float.rs +++ b/src/float.rs @@ -1,15 +1,20 @@ -use std::mem; -use std::ops::Neg; -use std::num::FpCategory; +use core::mem; +use core::ops::Neg; +use core::num::FpCategory; // Used for default implementation of `epsilon` -use std::f32; +use core::f32; use {Num, NumCast}; // FIXME: these doctests aren't actually helpful, because they're using and // testing the inherent methods directly, not going through `Float`. +/// Floating point operations. +/// +/// Please note that some methods are disabled for `no_std`. If you implement it +/// only for `no_std`, the build will fail if anyone else in the dependency +/// graph enables `num-traits/std`. pub trait Float : Num + Copy @@ -27,6 +32,7 @@ pub trait Float /// assert!(nan.is_nan()); /// ``` fn nan() -> Self; + /// Returns the infinite value. /// /// ``` @@ -40,6 +46,7 @@ pub trait Float /// assert!(infinity > f32::MAX); /// ``` fn infinity() -> Self; + /// Returns the negative infinite value. /// /// ``` @@ -53,6 +60,7 @@ pub trait Float /// assert!(neg_infinity < f32::MIN); /// ``` fn neg_infinity() -> Self; + /// Returns `-0.0`. /// /// ``` @@ -66,7 +74,10 @@ pub trait Float /// assert_eq!(7.0f32/inf, zero); /// assert_eq!(zero * 10.0, zero); /// ``` - fn neg_zero() -> Self; + #[inline] + fn neg_zero() -> Self { + -Self::zero() + } /// Returns the smallest finite value that this type can represent. /// @@ -134,7 +145,10 @@ pub trait Float /// assert!(nan.is_nan()); /// assert!(!f.is_nan()); /// ``` - fn is_nan(self) -> bool; + #[inline] + fn is_nan(self) -> bool { + self != self + } /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. @@ -154,7 +168,10 @@ pub trait Float /// assert!(inf.is_infinite()); /// assert!(neg_inf.is_infinite()); /// ``` - fn is_infinite(self) -> bool; + #[inline] + fn is_infinite(self) -> bool { + self == Self::infinity() || self == Self::neg_infinity() + } /// Returns `true` if this number is neither infinite nor `NaN`. /// @@ -173,7 +190,10 @@ pub trait Float /// assert!(!inf.is_finite()); /// assert!(!neg_inf.is_finite()); /// ``` - fn is_finite(self) -> bool; + #[inline] + fn is_finite(self) -> bool { + !(self.is_nan() || self.is_infinite()) + } /// Returns `true` if the number is neither zero, infinite, /// [subnormal][subnormal], or `NaN`. @@ -197,7 +217,10 @@ pub trait Float /// assert!(!lower_than_min.is_normal()); /// ``` /// [subnormal]: http://en.wikipedia.org/wiki/Denormal_number - fn is_normal(self) -> bool; + #[inline] + fn is_normal(self) -> bool { + self.classify() == FpCategory::Normal + } /// 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 @@ -227,6 +250,7 @@ pub trait Float /// assert_eq!(f.floor(), 3.0); /// assert_eq!(g.floor(), 3.0); /// ``` + #[cfg(feature = "std")] fn floor(self) -> Self; /// Returns the smallest integer greater than or equal to a number. @@ -240,6 +264,7 @@ pub trait Float /// assert_eq!(f.ceil(), 4.0); /// assert_eq!(g.ceil(), 4.0); /// ``` + #[cfg(feature = "std")] fn ceil(self) -> Self; /// Returns the nearest integer to a number. Round half-way cases away from @@ -254,6 +279,7 @@ pub trait Float /// assert_eq!(f.round(), 3.0); /// assert_eq!(g.round(), -3.0); /// ``` + #[cfg(feature = "std")] fn round(self) -> Self; /// Return the integer part of a number. @@ -267,6 +293,7 @@ pub trait Float /// assert_eq!(f.trunc(), 3.0); /// assert_eq!(g.trunc(), -3.0); /// ``` + #[cfg(feature = "std")] fn trunc(self) -> Self; /// Returns the fractional part of a number. @@ -282,6 +309,7 @@ pub trait Float /// assert!(abs_difference_x < 1e-10); /// assert!(abs_difference_y < 1e-10); /// ``` + #[cfg(feature = "std")] fn fract(self) -> Self; /// Computes the absolute value of `self`. Returns `Float::nan()` if the @@ -302,7 +330,16 @@ pub trait Float /// /// assert!(f64::NAN.abs().is_nan()); /// ``` - fn abs(self) -> Self; + #[inline] + fn abs(self) -> Self { + if self.is_sign_positive() { + return self; + } + if self.is_sign_negative() { + return -self; + } + Self::nan() + } /// Returns a number that represents the sign of `self`. /// @@ -321,7 +358,16 @@ pub trait Float /// /// assert!(f64::NAN.signum().is_nan()); /// ``` - fn signum(self) -> Self; + #[inline] + fn signum(self) -> Self { + if self.is_nan() { + Self::nan() + } else if self.is_sign_negative() { + -Self::one() + } else { + Self::one() + } + } /// Returns `true` if `self` is positive, including `+0.0`, /// `Float::infinity()`, and with newer versions of Rust `f64::NAN`. @@ -339,7 +385,10 @@ pub trait Float /// assert!(!g.is_sign_positive()); /// assert!(!neg_nan.is_sign_positive()); /// ``` - fn is_sign_positive(self) -> bool; + #[inline] + fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } /// Returns `true` if `self` is negative, including `-0.0`, /// `Float::neg_infinity()`, and with newer versions of Rust `-f64::NAN`. @@ -357,7 +406,11 @@ pub trait Float /// assert!(g.is_sign_negative()); /// assert!(!nan.is_sign_negative()); /// ``` - fn is_sign_negative(self) -> bool; + #[inline] + fn is_sign_negative(self) -> bool { + let (_, _, sign) = self.integer_decode(); + sign < 0 + } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -375,7 +428,9 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn mul_add(self, a: Self, b: Self) -> Self; + /// Take the reciprocal (inverse) of a number, `1/x`. /// /// ``` @@ -386,7 +441,10 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` - fn recip(self) -> Self; + #[inline] + fn recip(self) -> Self { + Self::one() / self + } /// Raise a number to an integer power. /// @@ -400,7 +458,35 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` - fn powi(self, n: i32) -> Self; + #[inline] + fn powi(self, mut exp: i32) -> Self { + let mut base = self; + if exp == 0 { + return Self::one(); + } else if exp < 0 { + base = base.recip(); + exp = exp.wrapping_neg(); + } + let mut exp = exp as u32; + + // duplicated from `::pow`, but using `Mul` by value instead of by reference. + + while exp & 1 == 0 { + base = base * base; + exp >>= 1; + } + if exp == 1 { return base; } + + let mut acc = base; + while exp > 1 { + exp >>= 1; + base = base * base; + if exp & 1 == 1 { + acc = acc * base; + } + } + acc + } /// Raise a number to a floating point power. /// @@ -412,6 +498,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn powf(self, n: Self) -> Self; /// Take the square root of a number. @@ -429,6 +516,7 @@ pub trait Float /// assert!(abs_difference < 1e-10); /// assert!(negative.sqrt().is_nan()); /// ``` + #[cfg(feature = "std")] fn sqrt(self) -> Self; /// Returns `e^(self)`, (the exponential function). @@ -445,6 +533,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn exp(self) -> Self; /// Returns `2^(self)`. @@ -459,6 +548,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn exp2(self) -> Self; /// Returns the natural logarithm of the number. @@ -475,6 +565,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn ln(self) -> Self; /// Returns the logarithm of the number with respect to an arbitrary base. @@ -494,6 +585,7 @@ pub trait Float /// assert!(abs_difference_10 < 1e-10); /// assert!(abs_difference_2 < 1e-10); /// ``` + #[cfg(feature = "std")] fn log(self, base: Self) -> Self; /// Returns the base 2 logarithm of the number. @@ -508,6 +600,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn log2(self) -> Self; /// Returns the base 10 logarithm of the number. @@ -522,6 +615,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn log10(self) -> Self; /// Converts radians to degrees. @@ -535,6 +629,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] #[inline] fn to_degrees(self) -> Self { let halfpi = Self::zero().acos(); @@ -542,6 +637,39 @@ pub trait Float self * ninety / halfpi } + /// Converts radians to degrees. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = consts::PI; + /// + /// let abs_difference = (angle.to_degrees() - 180.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[cfg(not(feature = "std"))] + fn to_degrees(self) -> Self; + + /// Converts degrees to radians. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = 180.0_f64; + /// + /// let abs_difference = (angle.to_radians() - consts::PI).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[cfg(feature = "std")] + #[inline] + fn to_radians(self) -> Self { + let halfpi = Self::zero().acos(); + let ninety = Self::from(90u8).unwrap(); + self * halfpi / ninety + } + /// Converts degrees to radians. /// /// ``` @@ -553,15 +681,13 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` - #[inline] - fn to_radians(self) -> Self { - let halfpi = Self::zero().acos(); - let ninety = Self::from(90u8).unwrap(); - self * halfpi / ninety - } + #[cfg(not(feature = "std"))] + fn to_radians(self) -> Self; /// Returns the maximum of the two numbers. /// + /// If one of the arguments is NaN, then the other argument is returned. + /// /// ``` /// use num_traits::Float; /// @@ -570,10 +696,21 @@ pub trait Float /// /// assert_eq!(x.max(y), y); /// ``` - fn max(self, other: Self) -> Self; + #[inline] + fn max(self, other: Self) -> Self { + if self.is_nan() { + return other; + } + if other.is_nan() { + return self; + } + if self > other { self } else { other } + } /// Returns the minimum of the two numbers. /// + /// If one of the arguments is NaN, then the other argument is returned. + /// /// ``` /// use num_traits::Float; /// @@ -582,7 +719,16 @@ pub trait Float /// /// assert_eq!(x.min(y), x); /// ``` - fn min(self, other: Self) -> Self; + #[inline] + fn min(self, other: Self) -> Self { + if self.is_nan() { + return other; + } + if other.is_nan() { + return self; + } + if self < other { self } else { other } + } /// The positive difference of two numbers. /// @@ -601,6 +747,7 @@ pub trait Float /// assert!(abs_difference_x < 1e-10); /// assert!(abs_difference_y < 1e-10); /// ``` + #[cfg(feature = "std")] fn abs_sub(self, other: Self) -> Self; /// Take the cubic root of a number. @@ -615,6 +762,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn cbrt(self) -> Self; /// Calculate the length of the hypotenuse of a right-angle triangle given @@ -631,6 +779,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn hypot(self, other: Self) -> Self; /// Computes the sine of a number (in radians). @@ -645,6 +794,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn sin(self) -> Self; /// Computes the cosine of a number (in radians). @@ -659,6 +809,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn cos(self) -> Self; /// Computes the tangent of a number (in radians). @@ -672,6 +823,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-14); /// ``` + #[cfg(feature = "std")] fn tan(self) -> Self; /// Computes the arcsine of a number. Return value is in radians in @@ -689,6 +841,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn asin(self) -> Self; /// Computes the arccosine of a number. Return value is in radians in @@ -706,6 +859,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn acos(self) -> Self; /// Computes the arctangent of a number. Return value is in radians in the @@ -721,6 +875,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn atan(self) -> Self; /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). @@ -750,6 +905,7 @@ pub trait Float /// assert!(abs_difference_1 < 1e-10); /// assert!(abs_difference_2 < 1e-10); /// ``` + #[cfg(feature = "std")] fn atan2(self, other: Self) -> Self; /// Simultaneously computes the sine and cosine of the number, `x`. Returns @@ -768,6 +924,7 @@ pub trait Float /// assert!(abs_difference_0 < 1e-10); /// assert!(abs_difference_0 < 1e-10); /// ``` + #[cfg(feature = "std")] fn sin_cos(self) -> (Self, Self); /// Returns `e^(self) - 1` in a way that is accurate even if the @@ -783,6 +940,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn exp_m1(self) -> Self; /// Returns `ln(1+n)` (natural logarithm) more accurately than if @@ -799,6 +957,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn ln_1p(self) -> Self; /// Hyperbolic sine function. @@ -817,6 +976,7 @@ pub trait Float /// /// assert!(abs_difference < 1e-10); /// ``` + #[cfg(feature = "std")] fn sinh(self) -> Self; /// Hyperbolic cosine function. @@ -835,6 +995,7 @@ pub trait Float /// // Same result /// assert!(abs_difference < 1.0e-10); /// ``` + #[cfg(feature = "std")] fn cosh(self) -> Self; /// Hyperbolic tangent function. @@ -853,6 +1014,7 @@ pub trait Float /// /// assert!(abs_difference < 1.0e-10); /// ``` + #[cfg(feature = "std")] fn tanh(self) -> Self; /// Inverse hyperbolic sine function. @@ -867,6 +1029,7 @@ pub trait Float /// /// assert!(abs_difference < 1.0e-10); /// ``` + #[cfg(feature = "std")] fn asinh(self) -> Self; /// Inverse hyperbolic cosine function. @@ -881,6 +1044,7 @@ pub trait Float /// /// assert!(abs_difference < 1.0e-10); /// ``` + #[cfg(feature = "std")] fn acosh(self) -> Self; /// Inverse hyperbolic tangent function. @@ -896,6 +1060,7 @@ pub trait Float /// /// assert!(abs_difference < 1.0e-10); /// ``` + #[cfg(feature = "std")] fn atanh(self) -> Self; @@ -924,21 +1089,21 @@ pub trait Float } macro_rules! float_impl { - ($T:ident $decode:ident) => ( + ($T:ident $decode:ident $classify:ident) => ( impl Float for $T { #[inline] fn nan() -> Self { - ::std::$T::NAN + ::core::$T::NAN } #[inline] fn infinity() -> Self { - ::std::$T::INFINITY + ::core::$T::INFINITY } #[inline] fn neg_infinity() -> Self { - ::std::$T::NEG_INFINITY + ::core::$T::NEG_INFINITY } #[inline] @@ -948,264 +1113,326 @@ macro_rules! float_impl { #[inline] fn min_value() -> Self { - ::std::$T::MIN + ::core::$T::MIN } #[inline] fn min_positive_value() -> Self { - ::std::$T::MIN_POSITIVE + ::core::$T::MIN_POSITIVE } #[inline] fn epsilon() -> Self { - ::std::$T::EPSILON + ::core::$T::EPSILON } #[inline] fn max_value() -> Self { - ::std::$T::MAX + ::core::$T::MAX } + #[cfg(feature = "std")] #[inline] fn is_nan(self) -> bool { <$T>::is_nan(self) } + #[cfg(feature = "std")] #[inline] fn is_infinite(self) -> bool { <$T>::is_infinite(self) } + #[cfg(feature = "std")] #[inline] fn is_finite(self) -> bool { <$T>::is_finite(self) } + #[cfg(feature = "std")] #[inline] fn is_normal(self) -> bool { <$T>::is_normal(self) } + #[cfg(feature = "std")] #[inline] fn classify(self) -> FpCategory { <$T>::classify(self) } + #[cfg(not(feature = "std"))] + #[inline] + fn classify(self) -> FpCategory { + $classify(self) + } + + #[cfg(feature = "std")] #[inline] fn floor(self) -> Self { <$T>::floor(self) } + #[cfg(feature = "std")] #[inline] fn ceil(self) -> Self { <$T>::ceil(self) } + #[cfg(feature = "std")] #[inline] fn round(self) -> Self { <$T>::round(self) } + #[cfg(feature = "std")] #[inline] fn trunc(self) -> Self { <$T>::trunc(self) } + #[cfg(feature = "std")] #[inline] fn fract(self) -> Self { <$T>::fract(self) } + #[cfg(feature = "std")] #[inline] fn abs(self) -> Self { <$T>::abs(self) } + #[cfg(feature = "std")] #[inline] fn signum(self) -> Self { <$T>::signum(self) } + #[cfg(feature = "std")] #[inline] fn is_sign_positive(self) -> bool { <$T>::is_sign_positive(self) } + #[cfg(feature = "std")] #[inline] fn is_sign_negative(self) -> bool { <$T>::is_sign_negative(self) } + #[cfg(feature = "std")] #[inline] fn mul_add(self, a: Self, b: Self) -> Self { <$T>::mul_add(self, a, b) } + #[cfg(feature = "std")] #[inline] fn recip(self) -> Self { <$T>::recip(self) } + #[cfg(feature = "std")] #[inline] fn powi(self, n: i32) -> Self { <$T>::powi(self, n) } + #[cfg(feature = "std")] #[inline] fn powf(self, n: Self) -> Self { <$T>::powf(self, n) } + #[cfg(feature = "std")] #[inline] fn sqrt(self) -> Self { <$T>::sqrt(self) } + #[cfg(feature = "std")] #[inline] fn exp(self) -> Self { <$T>::exp(self) } + #[cfg(feature = "std")] #[inline] fn exp2(self) -> Self { <$T>::exp2(self) } + #[cfg(feature = "std")] #[inline] fn ln(self) -> Self { <$T>::ln(self) } + #[cfg(feature = "std")] #[inline] fn log(self, base: Self) -> Self { <$T>::log(self, base) } + #[cfg(feature = "std")] #[inline] fn log2(self) -> Self { <$T>::log2(self) } + #[cfg(feature = "std")] #[inline] fn log10(self) -> Self { <$T>::log10(self) } + #[cfg(feature = "std")] #[inline] fn to_degrees(self) -> Self { - // NB: `f32` didn't stabilize this until 1.7 - // <$T>::to_degrees(self) - self * (180. / ::std::$T::consts::PI) + <$T>::to_degrees(self) } + #[cfg(feature = "std")] #[inline] fn to_radians(self) -> Self { - // NB: `f32` didn't stabilize this until 1.7 - // <$T>::to_radians(self) - self * (::std::$T::consts::PI / 180.) + <$T>::to_radians(self) } + #[cfg(not(feature = "std"))] + #[inline] + fn to_degrees(self) -> Self { + self * (180. / ::core::$T::consts::PI) + } + + #[cfg(not(feature = "std"))] + #[inline] + fn to_radians(self) -> Self { + self * (::core::$T::consts::PI / 180.) + } + + #[cfg(feature = "std")] #[inline] fn max(self, other: Self) -> Self { <$T>::max(self, other) } + #[cfg(feature = "std")] #[inline] fn min(self, other: Self) -> Self { <$T>::min(self, other) } + #[cfg(feature = "std")] #[inline] #[allow(deprecated)] fn abs_sub(self, other: Self) -> Self { <$T>::abs_sub(self, other) } + #[cfg(feature = "std")] #[inline] fn cbrt(self) -> Self { <$T>::cbrt(self) } + #[cfg(feature = "std")] #[inline] fn hypot(self, other: Self) -> Self { <$T>::hypot(self, other) } + #[cfg(feature = "std")] #[inline] fn sin(self) -> Self { <$T>::sin(self) } + #[cfg(feature = "std")] #[inline] fn cos(self) -> Self { <$T>::cos(self) } + #[cfg(feature = "std")] #[inline] fn tan(self) -> Self { <$T>::tan(self) } + #[cfg(feature = "std")] #[inline] fn asin(self) -> Self { <$T>::asin(self) } + #[cfg(feature = "std")] #[inline] fn acos(self) -> Self { <$T>::acos(self) } + #[cfg(feature = "std")] #[inline] fn atan(self) -> Self { <$T>::atan(self) } + #[cfg(feature = "std")] #[inline] fn atan2(self, other: Self) -> Self { <$T>::atan2(self, other) } + #[cfg(feature = "std")] #[inline] fn sin_cos(self) -> (Self, Self) { <$T>::sin_cos(self) } + #[cfg(feature = "std")] #[inline] fn exp_m1(self) -> Self { <$T>::exp_m1(self) } + #[cfg(feature = "std")] #[inline] fn ln_1p(self) -> Self { <$T>::ln_1p(self) } + #[cfg(feature = "std")] #[inline] fn sinh(self) -> Self { <$T>::sinh(self) } + #[cfg(feature = "std")] #[inline] fn cosh(self) -> Self { <$T>::cosh(self) } + #[cfg(feature = "std")] #[inline] fn tanh(self) -> Self { <$T>::tanh(self) } + #[cfg(feature = "std")] #[inline] fn asinh(self) -> Self { <$T>::asinh(self) } + #[cfg(feature = "std")] #[inline] fn acosh(self) -> Self { <$T>::acosh(self) } + #[cfg(feature = "std")] #[inline] fn atanh(self) -> Self { <$T>::atanh(self) @@ -1237,6 +1464,21 @@ fn integer_decode_f32(f: f32) -> (u64, i16, i8) { (mantissa as u64, exponent, sign) } +#[cfg(not(feature = "std"))] +fn classify_f32(f: f32) -> FpCategory { + const EXP_MASK: u32 = 0x7f800000; + const MAN_MASK: u32 = 0x007fffff; + + let bits: u32 = unsafe { mem::transmute(f) }; + 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, + } +} + fn integer_decode_f64(f: f64) -> (u64, i16, i8) { let bits: u64 = unsafe { mem::transmute(f) }; let sign: i8 = if bits >> 63 == 0 { @@ -1255,8 +1497,23 @@ fn integer_decode_f64(f: f64) -> (u64, i16, i8) { (mantissa, exponent, sign) } -float_impl!(f32 integer_decode_f32); -float_impl!(f64 integer_decode_f64); +#[cfg(not(feature = "std"))] +fn classify_f64(f: f64) -> FpCategory { + const EXP_MASK: u64 = 0x7ff0000000000000; + const MAN_MASK: u64 = 0x000fffffffffffff; + + let bits: u64 = unsafe { mem::transmute(f) }; + 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, + } +} + +float_impl!(f32 integer_decode_f32 classify_f32); +float_impl!(f64 integer_decode_f64 classify_f64); macro_rules! float_const_impl { ($(#[$doc:meta] $constant:ident,)+) => ( @@ -1272,7 +1529,7 @@ macro_rules! float_const_impl { $( #[inline] fn $constant() -> Self { - ::std::$T::consts::$constant + ::core::$T::consts::$constant } )+ } @@ -1317,20 +1574,34 @@ float_const_impl! { #[cfg(test)] mod tests { use Float; + use core::f64::consts; + + const DEG_RAD_PAIRS: [(f64, f64); 7] = [ + (0.0, 0.), + (22.5, consts::FRAC_PI_8), + (30.0, consts::FRAC_PI_6), + (45.0, consts::FRAC_PI_4), + (60.0, consts::FRAC_PI_3), + (90.0, consts::FRAC_PI_2), + (180.0, consts::PI), + ]; #[test] - fn convert_deg_rad() { - use std::f64::consts; + fn convert_deg_rad_core() { + for &(deg, rad) in &DEG_RAD_PAIRS { + assert!((Float::to_degrees(rad) - deg).abs() < 1e-6); + assert!((Float::to_radians(deg) - rad).abs() < 1e-6); - const DEG_RAD_PAIRS: [(f64, f64); 7] = [ - (0.0, 0.), - (22.5, consts::FRAC_PI_8), - (30.0, consts::FRAC_PI_6), - (45.0, consts::FRAC_PI_4), - (60.0, consts::FRAC_PI_3), - (90.0, consts::FRAC_PI_2), - (180.0, consts::PI), - ]; + let (deg, rad) = (deg as f32, rad as f32); + assert!((Float::to_degrees(rad) - deg).abs() < 1e-6); + assert!((Float::to_radians(deg) - rad).abs() < 1e-6); + } + } + + #[cfg(feature = "std")] + #[test] + fn convert_deg_rad_std() { + use Float; for &(deg, rad) in &DEG_RAD_PAIRS { assert!((Float::to_degrees(rad) - deg).abs() < 1e-6); diff --git a/src/identities.rs b/src/identities.rs index 79882ed..7ac424c 100644 --- a/src/identities.rs +++ b/src/identities.rs @@ -1,5 +1,5 @@ -use std::ops::{Add, Mul}; -use std::num::Wrapping; +use core::ops::{Add, Mul}; +use core::num::Wrapping; /// Defines an additive identity element for `Self`. pub trait Zero: Sized + Add { @@ -79,6 +79,10 @@ pub trait One: Sized + Mul { /// `static mut`s. // FIXME (#5527): This should be an associated constant fn one() -> Self; + + /// Returns `true` if `self` is equal to the multiplicative identity. + #[inline] + fn is_one(&self) -> bool; } macro_rules! one_impl { @@ -86,6 +90,9 @@ macro_rules! one_impl { impl One for $t { #[inline] fn one() -> $t { $v } + + #[inline] + fn is_one(&self) -> bool { *self == $v } } } } @@ -109,6 +116,10 @@ impl One for Wrapping where Wrapping: Mul> { fn one() -> Self { Wrapping(T::one()) } + + fn is_one(&self) -> bool { + self.0.is_one() + } } // Some helper functions provided for backwards compatibility. diff --git a/src/int.rs b/src/int.rs index 4f9221f..84fedc6 100644 --- a/src/int.rs +++ b/src/int.rs @@ -1,4 +1,4 @@ -use std::ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; +use core::ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use {Num, NumCast}; use bounds::Bounded; diff --git a/src/lib.rs b/src/lib.rs index 253f236..63b8105 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,12 +9,20 @@ // except according to those terms. //! Numeric traits for generic mathematics +#![doc(html_logo_url = "https://rust-num.github.io/num/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://rust-num.github.io/num/favicon.ico", + html_root_url = "https://rust-num.github.io/num/", + html_playground_url = "http://play.integer32.com/")] -#![doc(html_root_url = "https://docs.rs/num-traits/0.1")] +#![deny(unconditional_recursion)] -use std::ops::{Add, Sub, Mul, Div, Rem}; -use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; -use std::num::Wrapping; +#![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "std")] +extern crate core; + +use core::ops::{Add, Sub, Mul, Div, Rem}; +use core::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; +use core::num::Wrapping; pub use bounds::Bounded; pub use float::{Float, FloatConst}; @@ -127,10 +135,10 @@ impl NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {} macro_rules! int_trait_impl { ($name:ident for $($t:ty)*) => ($( impl $name for $t { - type FromStrRadixErr = ::std::num::ParseIntError; + type FromStrRadixErr = ::core::num::ParseIntError; #[inline] fn from_str_radix(s: &str, radix: u32) - -> Result + -> Result { <$t>::from_str_radix(s, radix) } @@ -156,7 +164,7 @@ pub enum FloatErrorKind { Empty, Invalid, } -// FIXME: std::num::ParseFloatError is stable in 1.0, but opaque to us, +// FIXME: core::num::ParseFloatError is stable in 1.0, but opaque to us, // so there's not really any way for us to reuse it. #[derive(Debug)] pub struct ParseFloatError { @@ -303,8 +311,8 @@ macro_rules! float_trait_impl { }; match (is_positive, exp) { - (true, Ok(exp)) => base.powi(exp as i32), - (false, Ok(exp)) => 1.0 / base.powi(exp as i32), + (true, Ok(exp)) => Float::powi(base, exp as i32), + (false, Ok(exp)) => 1.0 / Float::powi(base, exp as i32), (_, Err(_)) => return Err(PFE { kind: Invalid }), } }, diff --git a/src/ops/checked.rs b/src/ops/checked.rs index 45e6716..ce9a055 100644 --- a/src/ops/checked.rs +++ b/src/ops/checked.rs @@ -1,4 +1,4 @@ -use std::ops::{Add, Sub, Mul, Div}; +use core::ops::{Add, Sub, Mul, Div}; /// Performs addition that returns `None` instead of wrapping around on /// overflow. diff --git a/src/ops/wrapping.rs b/src/ops/wrapping.rs index f989058..24f3405 100644 --- a/src/ops/wrapping.rs +++ b/src/ops/wrapping.rs @@ -1,5 +1,5 @@ -use std::ops::{Add, Sub, Mul}; -use std::num::Wrapping; +use core::ops::{Add, Sub, Mul}; +use core::num::Wrapping; macro_rules! wrapping_impl { ($trait_name:ident, $method:ident, $t:ty) => { diff --git a/src/pow.rs b/src/pow.rs index b250ad4..a7bb9b7 100644 --- a/src/pow.rs +++ b/src/pow.rs @@ -1,4 +1,4 @@ -use std::ops::Mul; +use core::ops::Mul; use {One, CheckedMul}; /// Raises a value to the power of exp, using exponentiation by squaring. @@ -12,11 +12,14 @@ use {One, CheckedMul}; /// assert_eq!(pow(6u8, 3), 216); /// ``` #[inline] -pub fn pow>(mut base: T, mut exp: usize) -> T { +pub fn pow(mut base: T, mut exp: usize) -> T +where + for<'a> &'a T: Mul<&'a T, Output = T>, +{ if exp == 0 { return T::one() } while exp & 1 == 0 { - base = base.clone() * base; + base = &base * &base; exp >>= 1; } if exp == 1 { return base } @@ -24,9 +27,9 @@ pub fn pow>(mut base: T, mut exp: usize) -> let mut acc = base.clone(); while exp > 1 { exp >>= 1; - base = base.clone() * base; + base = &base * &base; if exp & 1 == 1 { - acc = acc * base.clone(); + acc = &acc * &base; } } acc diff --git a/src/sign.rs b/src/sign.rs index 4b43c89..bf45bd8 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -1,8 +1,8 @@ -use std::ops::Neg; -use std::{f32, f64}; -use std::num::Wrapping; +use core::ops::Neg; +use core::{f32, f64}; +use core::num::Wrapping; -use Num; +use {Num, Float}; /// Useful functions for signed numbers (i.e. numbers that can be negative). pub trait Signed: Sized + Num + Neg { @@ -104,16 +104,15 @@ macro_rules! signed_float_impl { /// Computes the absolute value. Returns `NAN` if the number is `NAN`. #[inline] fn abs(&self) -> $t { - <$t>::abs(*self) + (*self).abs() } /// The positive difference of two numbers. Returns `0.0` if the number is /// less than or equal to `other`, otherwise the difference between`self` /// and `other` is returned. #[inline] - #[allow(deprecated)] fn abs_sub(&self, other: &$t) -> $t { - <$t>::abs_sub(*self, *other) + if *self <= *other { 0. } else { *self - *other } } /// # Returns @@ -123,7 +122,7 @@ macro_rules! signed_float_impl { /// - `NAN` if the number is NaN #[inline] fn signum(&self) -> $t { - <$t>::signum(*self) + Float::signum(*self) } /// Returns `true` if the number is positive, including `+0.0` and `INFINITY`