diff --git a/README.md b/README.md index 1ee1e1e..3633962 100644 --- a/README.md +++ b/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 diff --git a/build.rs b/build.rs index 1717ee5..3cf2eb8 100644 --- a/build.rs +++ b/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"); } diff --git a/src/bounds.rs b/src/bounds.rs index c9ff749..36e1bbd 100644 --- a/src/bounds.rs +++ b/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 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 UpperBounded for T { + fn max_value() -> T { + Bounded::max_value() + } +} + macro_rules! bounded_impl { ($t:ty, $min:expr, $max:expr) => { impl Bounded for $t { diff --git a/src/float.rs b/src/float.rs index 0e7b9db..ce1b4ac 100644 --- a/src/float.rs +++ b/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; } } diff --git a/src/int.rs b/src/int.rs index 086bd2e..339e5ee 100644 --- a/src/int.rs +++ b/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) diff --git a/src/lib.rs b/src/lib.rs index a6c202c..aa16770 100644 --- a/src/lib.rs +++ b/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) {} diff --git a/src/macros.rs b/src/macros.rs index 4330cdf..b97758e 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -23,7 +23,14 @@ macro_rules! forward { fn $method( $( $arg : $ty ),* ) -> $ret { ::$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 {