Sfoglia il codice sorgente

Merge branch 'master' into reverse-bits

Josh Stone 3 anni fa
parent
commit
4ca742a3e4
7 ha cambiato i file con 235 aggiunte e 263 eliminazioni
  1. 0 6
      README.md
  2. 1 0
      build.rs
  3. 28 2
      src/bounds.rs
  4. 105 249
      src/float.rs
  5. 44 0
      src/int.rs
  6. 49 5
      src/lib.rs
  7. 8 1
      src/macros.rs

+ 0 - 6
README.md

@@ -16,12 +16,6 @@ Add this to your `Cargo.toml`:
 num-traits = "0.2"
 ```
 
-and this to your crate root:
-
-```rust
-extern crate num_traits;
-```
-
 ## Features
 
 This crate can be used without the standard library (`#![no_std]`) by disabling

+ 1 - 0
build.rs

@@ -17,6 +17,7 @@ fn main() {
     );
 
     ac.emit_expression_cfg("1u32.reverse_bits()", "has_reverse_bits");
+    ac.emit_expression_cfg("1u32.trailing_ones()", "has_leading_trailing_ones");
 
     autocfg::rerun_path("build.rs");
 }

+ 28 - 2
src/bounds.rs

@@ -8,12 +8,38 @@ use core::{u16, u32, u64, u8, usize};
 /// Numbers which have upper and lower bounds
 pub trait Bounded {
     // FIXME (#5527): These should be associated constants
-    /// returns the smallest finite number this type can represent
+    /// Returns the smallest finite number this type can represent
     fn min_value() -> Self;
-    /// returns the largest finite number this type can represent
+    /// Returns the largest finite number this type can represent
     fn max_value() -> Self;
 }
 
+/// Numbers which have lower bounds
+pub trait LowerBounded {
+    /// Returns the smallest finite number this type can represent
+    fn min_value() -> Self;
+}
+
+// FIXME: With a major version bump, this should be a supertrait instead
+impl<T: Bounded> LowerBounded for T {
+    fn min_value() -> T {
+        Bounded::min_value()
+    }
+}
+
+/// Numbers which have upper bounds
+pub trait UpperBounded {
+    /// Returns the largest finite number this type can represent
+    fn max_value() -> Self;
+}
+
+// FIXME: With a major version bump, this should be a supertrait instead
+impl<T: Bounded> UpperBounded for T {
+    fn max_value() -> T {
+        Bounded::max_value()
+    }
+}
+
 macro_rules! bounded_impl {
     ($t:ty, $min:expr, $max:expr) => {
         impl Bounded for $t {

+ 105 - 249
src/float.rs

@@ -818,6 +818,23 @@ impl FloatCore for f32 {
         Self::to_degrees(self) -> Self;
         Self::to_radians(self) -> Self;
     }
+
+    #[cfg(all(not(feature = "std"), feature = "libm"))]
+    forward! {
+        libm::floorf as floor(self) -> Self;
+        libm::ceilf as ceil(self) -> Self;
+        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"))]
+    #[inline]
+    fn fract(self) -> Self {
+        self - libm::truncf(self)
+    }
 }
 
 impl FloatCore for f64 {
@@ -893,6 +910,23 @@ impl FloatCore for f64 {
         Self::to_degrees(self) -> Self;
         Self::to_radians(self) -> Self;
     }
+
+    #[cfg(all(not(feature = "std"), feature = "libm"))]
+    forward! {
+        libm::floor as floor(self) -> Self;
+        libm::ceil as ceil(self) -> Self;
+        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"))]
+    #[inline]
+    fn fract(self) -> Self {
+        self - libm::trunc(self)
+    }
 }
 
 // FIXME: these doctests aren't actually helpful, because they're using and
@@ -1908,7 +1942,7 @@ macro_rules! float_impl_libm {
 
         #[inline]
         fn fract(self) -> Self {
-            self - FloatCore::trunc(self)
+            self - Float::trunc(self)
         }
 
         #[inline]
@@ -1929,8 +1963,6 @@ macro_rules! float_impl_libm {
             FloatCore::powi(self, n: i32) -> Self;
             FloatCore::to_degrees(self) -> Self;
             FloatCore::to_radians(self) -> Self;
-            FloatCore::max(self, other: Self) -> Self;
-            FloatCore::min(self, other: Self) -> Self;
         }
     };
 }
@@ -1981,129 +2013,41 @@ impl Float for f32 {
     fn abs_sub(self, other: Self) -> Self {
         libm::fdimf(self, other)
     }
-    #[inline]
-    fn floor(self) -> Self {
-        libm::floorf(self)
-    }
-    #[inline]
-    fn ceil(self) -> Self {
-        libm::ceilf(self)
-    }
-    #[inline]
-    fn round(self) -> Self {
-        libm::roundf(self)
-    }
-    #[inline]
-    fn trunc(self) -> Self {
-        libm::truncf(self)
-    }
-    #[inline]
-    fn abs(self) -> Self {
-        libm::fabsf(self)
-    }
-    #[inline]
-    fn mul_add(self, a: Self, b: Self) -> Self {
-        libm::fmaf(self, a, b)
-    }
-    #[inline]
-    fn powf(self, n: Self) -> Self {
-        libm::powf(self, n)
-    }
-    #[inline]
-    fn sqrt(self) -> Self {
-        libm::sqrtf(self)
-    }
-    #[inline]
-    fn exp(self) -> Self {
-        libm::expf(self)
-    }
-    #[inline]
-    fn exp2(self) -> Self {
-        libm::exp2f(self)
-    }
-    #[inline]
-    fn ln(self) -> Self {
-        libm::logf(self)
-    }
-    #[inline]
-    fn log2(self) -> Self {
-        libm::log2f(self)
-    }
-    #[inline]
-    fn log10(self) -> Self {
-        libm::log10f(self)
-    }
-    #[inline]
-    fn cbrt(self) -> Self {
-        libm::cbrtf(self)
-    }
-    #[inline]
-    fn hypot(self, other: Self) -> Self {
-        libm::hypotf(self, other)
-    }
-    #[inline]
-    fn sin(self) -> Self {
-        libm::sinf(self)
-    }
-    #[inline]
-    fn cos(self) -> Self {
-        libm::cosf(self)
-    }
-    #[inline]
-    fn tan(self) -> Self {
-        libm::tanf(self)
-    }
-    #[inline]
-    fn asin(self) -> Self {
-        libm::asinf(self)
-    }
-    #[inline]
-    fn acos(self) -> Self {
-        libm::acosf(self)
-    }
-    #[inline]
-    fn atan(self) -> Self {
-        libm::atanf(self)
-    }
-    #[inline]
-    fn atan2(self, other: Self) -> Self {
-        libm::atan2f(self, other)
-    }
-    #[inline]
-    fn sin_cos(self) -> (Self, Self) {
-        libm::sincosf(self)
-    }
-    #[inline]
-    fn exp_m1(self) -> Self {
-        libm::expm1f(self)
-    }
-    #[inline]
-    fn ln_1p(self) -> Self {
-        libm::log1pf(self)
-    }
-    #[inline]
-    fn sinh(self) -> Self {
-        libm::sinhf(self)
-    }
-    #[inline]
-    fn cosh(self) -> Self {
-        libm::coshf(self)
-    }
-    #[inline]
-    fn tanh(self) -> Self {
-        libm::tanhf(self)
-    }
-    #[inline]
-    fn asinh(self) -> Self {
-        libm::asinhf(self)
-    }
-    #[inline]
-    fn acosh(self) -> Self {
-        libm::acoshf(self)
-    }
-    #[inline]
-    fn atanh(self) -> Self {
-        libm::atanhf(self)
+
+    forward! {
+        libm::floorf as floor(self) -> Self;
+        libm::ceilf as ceil(self) -> Self;
+        libm::roundf as round(self) -> Self;
+        libm::truncf as trunc(self) -> Self;
+        libm::fabsf as abs(self) -> Self;
+        libm::fmaf as mul_add(self, a: Self, b: Self) -> Self;
+        libm::powf as powf(self, n: Self) -> Self;
+        libm::sqrtf as sqrt(self) -> Self;
+        libm::expf as exp(self) -> Self;
+        libm::exp2f as exp2(self) -> Self;
+        libm::logf as ln(self) -> Self;
+        libm::log2f as log2(self) -> Self;
+        libm::log10f as log10(self) -> Self;
+        libm::cbrtf as cbrt(self) -> Self;
+        libm::hypotf as hypot(self, other: Self) -> Self;
+        libm::sinf as sin(self) -> Self;
+        libm::cosf as cos(self) -> Self;
+        libm::tanf as tan(self) -> Self;
+        libm::asinf as asin(self) -> Self;
+        libm::acosf as acos(self) -> Self;
+        libm::atanf as atan(self) -> Self;
+        libm::atan2f as atan2(self, other: Self) -> Self;
+        libm::sincosf as sin_cos(self) -> (Self, Self);
+        libm::expm1f as exp_m1(self) -> Self;
+        libm::log1pf as ln_1p(self) -> Self;
+        libm::sinhf as sinh(self) -> Self;
+        libm::coshf as cosh(self) -> Self;
+        libm::tanhf as tanh(self) -> Self;
+        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;
     }
 }
 
@@ -2116,129 +2060,41 @@ impl Float for f64 {
     fn abs_sub(self, other: Self) -> Self {
         libm::fdim(self, other)
     }
-    #[inline]
-    fn floor(self) -> Self {
-        libm::floor(self)
-    }
-    #[inline]
-    fn ceil(self) -> Self {
-        libm::ceil(self)
-    }
-    #[inline]
-    fn round(self) -> Self {
-        libm::round(self)
-    }
-    #[inline]
-    fn trunc(self) -> Self {
-        libm::trunc(self)
-    }
-    #[inline]
-    fn abs(self) -> Self {
-        libm::fabs(self)
-    }
-    #[inline]
-    fn mul_add(self, a: Self, b: Self) -> Self {
-        libm::fma(self, a, b)
-    }
-    #[inline]
-    fn powf(self, n: Self) -> Self {
-        libm::pow(self, n)
-    }
-    #[inline]
-    fn sqrt(self) -> Self {
-        libm::sqrt(self)
-    }
-    #[inline]
-    fn exp(self) -> Self {
-        libm::exp(self)
-    }
-    #[inline]
-    fn exp2(self) -> Self {
-        libm::exp2(self)
-    }
-    #[inline]
-    fn ln(self) -> Self {
-        libm::log(self)
-    }
-    #[inline]
-    fn log2(self) -> Self {
-        libm::log2(self)
-    }
-    #[inline]
-    fn log10(self) -> Self {
-        libm::log10(self)
-    }
-    #[inline]
-    fn cbrt(self) -> Self {
-        libm::cbrt(self)
-    }
-    #[inline]
-    fn hypot(self, other: Self) -> Self {
-        libm::hypot(self, other)
-    }
-    #[inline]
-    fn sin(self) -> Self {
-        libm::sin(self)
-    }
-    #[inline]
-    fn cos(self) -> Self {
-        libm::cos(self)
-    }
-    #[inline]
-    fn tan(self) -> Self {
-        libm::tan(self)
-    }
-    #[inline]
-    fn asin(self) -> Self {
-        libm::asin(self)
-    }
-    #[inline]
-    fn acos(self) -> Self {
-        libm::acos(self)
-    }
-    #[inline]
-    fn atan(self) -> Self {
-        libm::atan(self)
-    }
-    #[inline]
-    fn atan2(self, other: Self) -> Self {
-        libm::atan2(self, other)
-    }
-    #[inline]
-    fn sin_cos(self) -> (Self, Self) {
-        libm::sincos(self)
-    }
-    #[inline]
-    fn exp_m1(self) -> Self {
-        libm::expm1(self)
-    }
-    #[inline]
-    fn ln_1p(self) -> Self {
-        libm::log1p(self)
-    }
-    #[inline]
-    fn sinh(self) -> Self {
-        libm::sinh(self)
-    }
-    #[inline]
-    fn cosh(self) -> Self {
-        libm::cosh(self)
-    }
-    #[inline]
-    fn tanh(self) -> Self {
-        libm::tanh(self)
-    }
-    #[inline]
-    fn asinh(self) -> Self {
-        libm::asinh(self)
-    }
-    #[inline]
-    fn acosh(self) -> Self {
-        libm::acosh(self)
-    }
-    #[inline]
-    fn atanh(self) -> Self {
-        libm::atanh(self)
+
+    forward! {
+        libm::floor as floor(self) -> Self;
+        libm::ceil as ceil(self) -> Self;
+        libm::round as round(self) -> Self;
+        libm::trunc as trunc(self) -> Self;
+        libm::fabs as abs(self) -> Self;
+        libm::fma as mul_add(self, a: Self, b: Self) -> Self;
+        libm::pow as powf(self, n: Self) -> Self;
+        libm::sqrt as sqrt(self) -> Self;
+        libm::exp as exp(self) -> Self;
+        libm::exp2 as exp2(self) -> Self;
+        libm::log as ln(self) -> Self;
+        libm::log2 as log2(self) -> Self;
+        libm::log10 as log10(self) -> Self;
+        libm::cbrt as cbrt(self) -> Self;
+        libm::hypot as hypot(self, other: Self) -> Self;
+        libm::sin as sin(self) -> Self;
+        libm::cos as cos(self) -> Self;
+        libm::tan as tan(self) -> Self;
+        libm::asin as asin(self) -> Self;
+        libm::acos as acos(self) -> Self;
+        libm::atan as atan(self) -> Self;
+        libm::atan2 as atan2(self, other: Self) -> Self;
+        libm::sincos as sin_cos(self) -> (Self, Self);
+        libm::expm1 as exp_m1(self) -> Self;
+        libm::log1p as ln_1p(self) -> Self;
+        libm::sinh as sinh(self) -> Self;
+        libm::cosh as cosh(self) -> Self;
+        libm::tanh as tanh(self) -> Self;
+        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;
     }
 }
 

+ 44 - 0
src/int.rs

@@ -78,6 +78,22 @@ pub trait PrimInt:
     /// ```
     fn count_zeros(self) -> u32;
 
+    /// Returns the number of leading ones in the binary representation
+    /// of `self`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::PrimInt;
+    ///
+    /// let n = 0xF00Du16;
+    ///
+    /// assert_eq!(n.leading_ones(), 4);
+    /// ```
+    fn leading_ones(self) -> u32 {
+        (!self).leading_zeros()
+    }
+
     /// Returns the number of leading zeros in the binary representation
     /// of `self`.
     ///
@@ -92,6 +108,22 @@ pub trait PrimInt:
     /// ```
     fn leading_zeros(self) -> u32;
 
+    /// Returns the number of trailing ones in the binary representation
+    /// of `self`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::PrimInt;
+    ///
+    /// let n = 0xBEEFu16;
+    ///
+    /// assert_eq!(n.trailing_ones(), 4);
+    /// ```
+    fn trailing_ones(self) -> u32 {
+        (!self).trailing_zeros()
+    }
+
     /// Returns the number of trailing zeros in the binary representation
     /// of `self`.
     ///
@@ -372,11 +404,23 @@ macro_rules! prim_int_impl {
                 <$T>::count_zeros(self)
             }
 
+            #[cfg(has_leading_leading_ones)]
+            #[inline]
+            fn leading_ones(self) -> u32 {
+                <$T>::leading_ones(self)
+            }
+
             #[inline]
             fn leading_zeros(self) -> u32 {
                 <$T>::leading_zeros(self)
             }
 
+            #[cfg(has_leading_trailing_ones)]
+            #[inline]
+            fn trailing_ones(self) -> u32 {
+                <$T>::trailing_ones(self)
+            }
+
             #[inline]
             fn trailing_zeros(self) -> u32 {
                 <$T>::trailing_zeros(self)

+ 49 - 5
src/lib.rs

@@ -210,6 +210,14 @@ impl fmt::Display for ParseFloatError {
     }
 }
 
+fn str_to_ascii_lower_eq_str(a: &str, b: &str) -> bool {
+    a.len() == b.len()
+        && a.bytes().zip(b.bytes()).all(|(a, b)| {
+            let a_to_ascii_lower = a | (((b'A' <= a && a <= b'Z') as u8) << 5);
+            a_to_ascii_lower == b
+        })
+}
+
 // FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck
 // with this implementation ourselves until we want to make a breaking change.
 // (would have to drop it from `Num` though)
@@ -224,12 +232,26 @@ macro_rules! float_trait_impl {
                 use self::FloatErrorKind::*;
                 use self::ParseFloatError as PFE;
 
+                // Special case radix 10 to use more accurate standard library implementation
+                if radix == 10 {
+                    return src.parse().map_err(|_| PFE {
+                        kind: if src.is_empty() { Empty } else { Invalid },
+                    });
+                }
+
                 // Special values
-                match src {
-                    "inf"   => return Ok(core::$t::INFINITY),
-                    "-inf"  => return Ok(core::$t::NEG_INFINITY),
-                    "NaN"   => return Ok(core::$t::NAN),
-                    _       => {},
+                if str_to_ascii_lower_eq_str(src, "inf")
+                    || str_to_ascii_lower_eq_str(src, "infinity")
+                {
+                    return Ok(core::$t::INFINITY);
+                } else if str_to_ascii_lower_eq_str(src, "-inf")
+                    || str_to_ascii_lower_eq_str(src, "-infinity")
+                {
+                    return Ok(core::$t::NEG_INFINITY);
+                } else if str_to_ascii_lower_eq_str(src, "nan") {
+                    return Ok(core::$t::NAN);
+                } else if str_to_ascii_lower_eq_str(src, "-nan") {
+                    return Ok(-core::$t::NAN);
                 }
 
                 fn slice_shift_char(src: &str) -> Option<(char, &str)> {
@@ -508,6 +530,28 @@ fn from_str_radix_multi_byte_fail() {
     assert!(f32::from_str_radix("0.2E™1", 10).is_err());
 }
 
+#[test]
+fn from_str_radix_ignore_case() {
+    assert_eq!(
+        f32::from_str_radix("InF", 16).unwrap(),
+        ::core::f32::INFINITY
+    );
+    assert_eq!(
+        f32::from_str_radix("InfinitY", 16).unwrap(),
+        ::core::f32::INFINITY
+    );
+    assert_eq!(
+        f32::from_str_radix("-InF", 8).unwrap(),
+        ::core::f32::NEG_INFINITY
+    );
+    assert_eq!(
+        f32::from_str_radix("-InfinitY", 8).unwrap(),
+        ::core::f32::NEG_INFINITY
+    );
+    assert!(f32::from_str_radix("nAn", 4).unwrap().is_nan());
+    assert!(f32::from_str_radix("-nAn", 4).unwrap().is_nan());
+}
+
 #[test]
 fn wrapping_is_num() {
     fn require_num<T: Num>(_: &T) {}

+ 8 - 1
src/macros.rs

@@ -23,7 +23,14 @@ macro_rules! forward {
             fn $method( $( $arg : $ty ),* ) -> $ret {
                 <Self as $base>::$method( $( $arg ),* )
             }
-        )*}
+        )*};
+    ($( $imp:path as $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
+        => {$(
+            #[inline]
+            fn $method(self $( , $arg : $ty )* ) -> $ret {
+                $imp(self $( , $arg )* )
+            }
+        )*};
 }
 
 macro_rules! constant {