Browse Source

Auto merge of #296 - vks:no_std, r=cuviper

traits: Introduce std feature

This makes it possible to build `traits` without `std`. For this a new
trait `BasicFloat` was introduced, implementing some basic functionality
that works with `core`. Most notably this is lacking functions like
`cos`, `sin`, etc.

`Float` is not available without `std`.

Refs #216.
Homu 7 years ago
parent
commit
8b5d4ac24e

+ 4 - 0
ci/test_full.sh

@@ -10,6 +10,10 @@ for package in bigint complex integer iter rational traits; do
   cargo test --manifest-path $package/Cargo.toml
 done
 
+# Only num-traits supports no_std at the moment.
+cargo build --manifest-path traits/Cargo.toml --no-default-features
+cargo test --manifest-path traits/Cargo.toml --no-default-features
+
 # Each isolated feature should also work everywhere.
 for feature in '' bigint rational complex; do
   cargo build --verbose --no-default-features --features="$feature"

+ 4 - 0
traits/Cargo.toml

@@ -10,3 +10,7 @@ name = "num-traits"
 version = "0.1.37"
 
 [dependencies]
+
+[features]
+default = ["std"]
+std = []

+ 4 - 4
traits/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 {

+ 7 - 6
traits/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<T: NumCast> NumCast for Wrapping<T> {
 
 #[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);

+ 297 - 47
traits/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};
+use {ToPrimitive, 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_sign_positive() {
+            return Self::one();
+        }
+        if self.is_sign_negative() {
+            return -Self::one();
+        }
+        Self::nan()
+    }
 
     /// Returns `true` if `self` is positive, including `+0.0` and
     /// `Float::infinity()`.
@@ -340,7 +386,10 @@ pub trait Float
     /// // Requires both tests to determine if is `NaN`
     /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
     /// ```
-    fn is_sign_positive(self) -> bool;
+    #[inline]
+    fn is_sign_positive(self) -> bool {
+        self > Self::zero() || (Self::one() / self) == Self::infinity()
+    }
 
     /// Returns `true` if `self` is negative, including `-0.0` and
     /// `Float::neg_infinity()`.
@@ -359,7 +408,10 @@ pub trait Float
     /// // Requires both tests to determine if is `NaN`.
     /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
     /// ```
-    fn is_sign_negative(self) -> bool;
+    #[inline]
+    fn is_sign_negative(self) -> bool {
+        self < Self::zero() || (Self::one() / self) == Self::neg_infinity()
+    }
 
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
     /// error. This produces a more accurate result with better performance than
@@ -377,7 +429,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`.
     ///
     /// ```
@@ -388,7 +442,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.
     ///
@@ -402,7 +459,15 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
-    fn powi(self, n: i32) -> Self;
+    #[inline]
+    fn powi(mut self, mut exp: i32) -> Self {
+        if exp < 0 {
+            self = self.recip();
+            exp = -exp;
+        }
+        // It should always be possible to convert a positive `i32` to a `usize`.
+        super::pow(self, exp.to_usize().unwrap())
+    }
 
     /// Raise a number to a floating point power.
     ///
@@ -414,6 +479,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.
@@ -431,6 +497,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).
@@ -447,6 +514,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn exp(self) -> Self;
 
     /// Returns `2^(self)`.
@@ -461,6 +529,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn exp2(self) -> Self;
 
     /// Returns the natural logarithm of the number.
@@ -477,6 +546,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.
@@ -496,6 +566,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.
@@ -510,6 +581,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn log2(self) -> Self;
 
     /// Returns the base 10 logarithm of the number.
@@ -524,6 +596,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn log10(self) -> Self;
 
     /// Converts radians to degrees.
@@ -537,6 +610,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg(feature = "std")]
     #[inline]
     fn to_degrees(self) -> Self {
         let halfpi = Self::zero().acos();
@@ -544,6 +618,20 @@ 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.
     ///
     /// ```
@@ -555,6 +643,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg(feature = "std")]
     #[inline]
     fn to_radians(self) -> Self {
         let halfpi = Self::zero().acos();
@@ -562,8 +651,24 @@ pub trait Float
         self * halfpi / ninety
     }
 
+    /// 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(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;
     ///
@@ -572,10 +677,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;
     ///
@@ -584,7 +700,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.
     ///
@@ -603,6 +728,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.
@@ -617,6 +743,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
@@ -633,6 +760,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).
@@ -647,6 +775,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn sin(self) -> Self;
 
     /// Computes the cosine of a number (in radians).
@@ -661,6 +790,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn cos(self) -> Self;
 
     /// Computes the tangent of a number (in radians).
@@ -674,6 +804,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
@@ -691,6 +822,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
@@ -708,6 +840,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
@@ -723,6 +856,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`).
@@ -752,6 +886,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
@@ -770,6 +905,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
@@ -785,6 +921,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
@@ -801,6 +938,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn ln_1p(self) -> Self;
 
     /// Hyperbolic sine function.
@@ -819,6 +957,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn sinh(self) -> Self;
 
     /// Hyperbolic cosine function.
@@ -837,6 +976,7 @@ pub trait Float
     /// // Same result
     /// assert!(abs_difference < 1.0e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn cosh(self) -> Self;
 
     /// Hyperbolic tangent function.
@@ -855,6 +995,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1.0e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn tanh(self) -> Self;
 
     /// Inverse hyperbolic sine function.
@@ -869,6 +1010,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1.0e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn asinh(self) -> Self;
 
     /// Inverse hyperbolic cosine function.
@@ -883,6 +1025,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1.0e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn acosh(self) -> Self;
 
     /// Inverse hyperbolic tangent function.
@@ -898,6 +1041,7 @@ pub trait Float
     ///
     /// assert!(abs_difference < 1.0e-10);
     /// ```
+    #[cfg(feature = "std")]
     fn atanh(self) -> Self;
 
 
@@ -926,21 +1070,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]
@@ -950,264 +1094,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)
@@ -1239,6 +1445,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 {
@@ -1257,8 +1478,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,)+) => (
@@ -1274,7 +1510,7 @@ macro_rules! float_const_impl {
             $(
                 #[inline]
                 fn $constant() -> Self {
-                    ::std::$T::consts::$constant
+                    ::core::$T::consts::$constant
                 }
             )+
         }
@@ -1319,20 +1555,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_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);
+
+            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() {
-        use std::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),
-        ];
+    fn convert_deg_rad_std() {
+        use Float;
 
         for &(deg, rad) in &DEG_RAD_PAIRS {
             assert!((Float::to_degrees(rad) - deg).abs() < 1e-6);

+ 2 - 2
traits/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<Self, Output = Self> {

+ 1 - 1
traits/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;

+ 14 - 8
traits/src/lib.rs

@@ -14,9 +14,15 @@
        html_root_url = "https://rust-num.github.io/num/",
        html_playground_url = "http://play.integer32.com/")]
 
-use std::ops::{Add, Sub, Mul, Div, Rem};
-use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
-use std::num::Wrapping;
+#![deny(unconditional_recursion)]
+
+#![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};
@@ -129,10 +135,10 @@ impl<T> 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<Self, ::std::num::ParseIntError>
+                              -> Result<Self, ::core::num::ParseIntError>
             {
                 <$t>::from_str_radix(s, radix)
             }
@@ -158,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 {
@@ -305,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 }),
                         }
                     },

+ 1 - 1
traits/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.

+ 2 - 2
traits/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) => {

+ 1 - 1
traits/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.

+ 7 - 8
traits/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<Output = Self> {
@@ -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`