From c54841995aae33d50524ab979a4be77b0849374b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 13 Nov 2020 18:26:06 -0800 Subject: [PATCH 1/7] Use libm in Float::{min,max} and in FloatCore --- src/float.rs | 354 +++++++++++++++----------------------------------- src/macros.rs | 9 +- 2 files changed, 113 insertions(+), 250 deletions(-) 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/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 { From 00b5a1d41ee38ebfeea33bf06d40e3aaf1097ba2 Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Fri, 5 Feb 2021 19:03:58 +0100 Subject: [PATCH 2/7] use standard library for float from_str_radix with radix 10 --- src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index a6c202c..0beed61 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -224,6 +224,13 @@ 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), From 3b7fd3af79d543eb0b4cc50d3589c10af008a41a Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Fri, 5 Feb 2021 19:18:57 +0100 Subject: [PATCH 3/7] match standard library float parsing of "-NaN" --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 0beed61..ca598f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -236,6 +236,7 @@ macro_rules! float_trait_impl { "inf" => return Ok(core::$t::INFINITY), "-inf" => return Ok(core::$t::NEG_INFINITY), "NaN" => return Ok(core::$t::NAN), + "-NaN" => return Ok(-core::$t::NAN), _ => {}, } From c235ad63f0ffac05a3998658b7e23a7f505f5f4a Mon Sep 17 00:00:00 2001 From: ltdk Date: Mon, 22 Mar 2021 15:22:47 -0400 Subject: [PATCH 4/7] Add LowerBounded/UpperBounded traits --- src/bounds.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) 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 { From 0196ef37dd947ec8ad828de33dff631ff79dce8d Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Wed, 24 Mar 2021 11:52:06 -0400 Subject: [PATCH 5/7] update readme for rust 2018 edition --- README.md | 6 ------ 1 file changed, 6 deletions(-) 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 From d989634fda04bc4cd92f73c1cd37693067bcd1f5 Mon Sep 17 00:00:00 2001 From: ltdk Date: Sun, 14 Mar 2021 19:02:34 -0400 Subject: [PATCH 6/7] Add leading_ones and trailing_ones to PrimInt --- build.rs | 2 ++ src/int.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/build.rs b/build.rs index 816ddad..7e4fcad 100644 --- a/build.rs +++ b/build.rs @@ -16,5 +16,7 @@ fn main() { "has_to_int_unchecked", ); + ac.emit_expression_cfg("1u32.trailing_ones()", "has_leading_trailing_ones"); + autocfg::rerun_path("build.rs"); } diff --git a/src/int.rs b/src/int.rs index 10e751a..e51d6bc 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`. /// @@ -319,11 +351,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) From 4154fb5af94033851d64cfb5beea630c0f3159a0 Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Thu, 15 Apr 2021 20:15:46 +0200 Subject: [PATCH 7/7] Ignore case for float parsing of text special values This copies some of the standard library fixes of . --- src/lib.rs | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ca598f7..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) @@ -232,12 +240,18 @@ macro_rules! float_trait_impl { } // Special values - match src { - "inf" => return Ok(core::$t::INFINITY), - "-inf" => return Ok(core::$t::NEG_INFINITY), - "NaN" => return Ok(core::$t::NAN), - "-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)> { @@ -516,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) {}