Compare commits
43 Commits
num-traits
...
master
Author | SHA1 | Date |
---|---|---|
bors[bot] | 2f0cffd522 | |
bors[bot] | 4fc3d8f72d | |
Josh Stone | 06b3f854d4 | |
bors[bot] | 5b9f6e4c47 | |
Josh Stone | 93328dfc90 | |
Josh Stone | c4256bd4df | |
Josh Stone | b64ee3809c | |
Josh Stone | 27b9202ff3 | |
Yoan Lecoq | f050c60df9 | |
Yoan Lecoq | 2d113f56c8 | |
Yoan Lecoq | 63047365be | |
Yoan Lecoq | 0547a355ee | |
Yoan Lecoq | 4b1ea5fb12 | |
Yoan Lecoq | 1b28e6182d | |
Yoan Lecoq | 55c5b7455a | |
Yoan Lecoq | c28e2fe062 | |
Yoan Lecoq | aaf3c267bd | |
Yoan Lecoq | 849e2a0b1b | |
Yoan Lecoq | 4234eb76aa | |
Yoan Lecoq | 4d3cb0a4ba | |
Yoan Lecoq | f523f532e6 | |
Yoan Lecoq | b4558d1c49 | |
Yoan Lecoq | fec6c3610c | |
bors[bot] | d394467906 | |
Jim Turner | 987ed8fd38 | |
Jim Turner | d02f166765 | |
Jim Turner | 33b74618b6 | |
bors[bot] | 428f89a7d5 | |
Toshiki Teramura | 0e7c2a4a00 | |
bors[bot] | 3add713434 | |
Sergey "Shnatsel" Davidoff | 40898e5071 | |
Toshiki Teramura | 973ba72e4f | |
Toshiki Teramura | e7ba9b62dc | |
Toshiki Teramura | 2fb8a6e8a9 | |
Josh Stone | b8906eff1b | |
Josh Stone | 7a61e79757 | |
bors[bot] | 45067c1357 | |
Andreas Molzer | cd0da1ae5e | |
Toshiki Teramura | f20d74fce8 | |
Toshiki Teramura | e8dce19146 | |
bors[bot] | 58f02a8677 | |
Bruce Mitchener | d1f5658bfe | |
Bruce Mitchener | 107a326745 |
13
.travis.yml
13
.travis.yml
|
@ -14,6 +14,18 @@ script:
|
|||
- ./ci/test_full.sh
|
||||
matrix:
|
||||
include:
|
||||
# i586 presents floating point challenges for lack of SSE/SSE2
|
||||
- name: "i586"
|
||||
rust: stable
|
||||
env: TARGET=i586-unknown-linux-gnu
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
before_script:
|
||||
- rustup target add $TARGET
|
||||
script:
|
||||
- cargo test --verbose --target $TARGET --all-features
|
||||
# try a target that doesn't have std at all
|
||||
- name: "no_std"
|
||||
rust: stable
|
||||
|
@ -22,6 +34,7 @@ matrix:
|
|||
- rustup target add $TARGET
|
||||
script:
|
||||
- cargo build --verbose --target $TARGET --no-default-features --features i128
|
||||
- cargo build --verbose --target $TARGET --no-default-features --features libm
|
||||
- name: "rustfmt"
|
||||
rust: 1.31.0
|
||||
before_script:
|
||||
|
|
|
@ -17,6 +17,7 @@ exclude = ["/ci/*", "/.travis.yml", "/bors.toml"]
|
|||
features = ["std"]
|
||||
|
||||
[dependencies]
|
||||
libm = { version = "0.1.4", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
|
|
|
@ -31,11 +31,14 @@ the default `std` feature. Use this in `Cargo.toml`:
|
|||
[dependencies.num-traits]
|
||||
version = "0.2"
|
||||
default-features = false
|
||||
# features = ["libm"] # <--- Uncomment if you wish to use `Float` and `Real` without `std`
|
||||
```
|
||||
|
||||
The `Float` and `Real` traits are only available when `std` is enabled. The
|
||||
`FloatCore` trait is always available. `MulAdd` and `MulAddAssign` for `f32`
|
||||
and `f64` also require `std`, as do implementations of signed and floating-
|
||||
The `Float` and `Real` traits are only available when either `std` or `libm` is enabled.
|
||||
The `libm` feature is only available with Rust 1.31 and later ([see PR #99](https://github.com/rust-num/num-traits/pull/99)).
|
||||
|
||||
The `FloatCore` trait is always available. `MulAdd` and `MulAddAssign` for `f32`
|
||||
and `f64` also require `std` or `libm`, as do implementations of signed and floating-
|
||||
point exponents in `Pow`.
|
||||
|
||||
Implementations for `i128` and `u128` are only available with Rust 1.26 and
|
||||
|
|
|
@ -12,8 +12,16 @@ cargo test --verbose
|
|||
cargo build --verbose --no-default-features
|
||||
cargo test --verbose --no-default-features
|
||||
|
||||
# test `i128`
|
||||
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable)$ ]]; then
|
||||
# test `i128`
|
||||
cargo build --verbose --features=i128
|
||||
cargo test --verbose --features=i128
|
||||
|
||||
# test with std and libm (libm build fails on Rust 1.26 and earlier)
|
||||
cargo build --verbose --features "libm"
|
||||
cargo test --verbose --features "libm"
|
||||
|
||||
# test `no_std` with libm (libm build fails on Rust 1.26 and earlier)
|
||||
cargo build --verbose --no-default-features --features "libm"
|
||||
cargo test --verbose --no-default-features --features "libm"
|
||||
fi
|
||||
|
|
|
@ -95,8 +95,8 @@ fn wrapping_bounded() {
|
|||
macro_rules! test_wrapping_bounded {
|
||||
($($t:ty)+) => {
|
||||
$(
|
||||
assert_eq!(Wrapping::<$t>::min_value().0, <$t>::min_value());
|
||||
assert_eq!(Wrapping::<$t>::max_value().0, <$t>::max_value());
|
||||
assert_eq!(<Wrapping<$t> as Bounded>::min_value().0, <$t>::min_value());
|
||||
assert_eq!(<Wrapping<$t> as Bounded>::max_value().0, <$t>::max_value());
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
@ -110,8 +110,8 @@ fn wrapping_bounded_i128() {
|
|||
macro_rules! test_wrapping_bounded {
|
||||
($($t:ty)+) => {
|
||||
$(
|
||||
assert_eq!(Wrapping::<$t>::min_value().0, <$t>::min_value());
|
||||
assert_eq!(Wrapping::<$t>::max_value().0, <$t>::max_value());
|
||||
assert_eq!(<Wrapping<$t> as Bounded>::min_value().0, <$t>::min_value());
|
||||
assert_eq!(<Wrapping<$t> as Bounded>::max_value().0, <$t>::max_value());
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
|
|
@ -682,7 +682,7 @@ impl<T: NumCast> NumCast for Wrapping<T> {
|
|||
|
||||
/// A generic interface for casting between machine scalars with the
|
||||
/// `as` operator, which admits narrowing and precision loss.
|
||||
/// Implementers of this trait AsPrimitive should behave like a primitive
|
||||
/// Implementers of this trait `AsPrimitive` should behave like a primitive
|
||||
/// numeric type (e.g. a newtype around another primitive), and the
|
||||
/// intended conversion must never fail.
|
||||
///
|
||||
|
|
107
src/float.rs
107
src/float.rs
|
@ -7,6 +7,9 @@ use core::f64;
|
|||
|
||||
use {Num, NumCast, ToPrimitive};
|
||||
|
||||
#[cfg(all(not(feature = "std"), feature = "libm"))]
|
||||
use libm::{F32Ext, F64Ext};
|
||||
|
||||
/// Generic trait for floating point numbers that works with `no_std`.
|
||||
///
|
||||
/// This trait implements a subset of the `Float` trait.
|
||||
|
@ -766,6 +769,8 @@ impl FloatCore for f32 {
|
|||
const EXP_MASK: u32 = 0x7f800000;
|
||||
const MAN_MASK: u32 = 0x007fffff;
|
||||
|
||||
// Safety: this identical to the implementation of f32::to_bits(),
|
||||
// which is only available starting at Rust 1.20
|
||||
let bits: u32 = unsafe { mem::transmute(self) };
|
||||
match (bits & MAN_MASK, bits & EXP_MASK) {
|
||||
(0, 0) => FpCategory::Zero,
|
||||
|
@ -838,6 +843,8 @@ impl FloatCore for f64 {
|
|||
const EXP_MASK: u64 = 0x7ff0000000000000;
|
||||
const MAN_MASK: u64 = 0x000fffffffffffff;
|
||||
|
||||
// Safety: this identical to the implementation of f64::to_bits(),
|
||||
// which is only available starting at Rust 1.20
|
||||
let bits: u64 = unsafe { mem::transmute(self) };
|
||||
match (bits & MAN_MASK, bits & EXP_MASK) {
|
||||
(0, 0) => FpCategory::Zero,
|
||||
|
@ -893,8 +900,8 @@ impl FloatCore for f64 {
|
|||
|
||||
/// Generic trait for floating point numbers
|
||||
///
|
||||
/// This trait is only available with the `std` feature.
|
||||
#[cfg(feature = "std")]
|
||||
/// This trait is only available with the `std` feature, or with the `libm` feature otherwise.
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
|
||||
/// Returns the `NaN` value.
|
||||
///
|
||||
|
@ -1802,7 +1809,7 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
|
|||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
macro_rules! float_impl {
|
||||
macro_rules! float_impl_std {
|
||||
($T:ident $decode:ident) => {
|
||||
impl Float for $T {
|
||||
constant! {
|
||||
|
@ -1880,7 +1887,88 @@ macro_rules! float_impl {
|
|||
};
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "std"), feature = "libm"))]
|
||||
macro_rules! float_impl_libm {
|
||||
($T:ident $decode:ident $LibmImpl:ident) => {
|
||||
impl Float for $T {
|
||||
constant! {
|
||||
nan() -> $T::NAN;
|
||||
infinity() -> $T::INFINITY;
|
||||
neg_infinity() -> $T::NEG_INFINITY;
|
||||
neg_zero() -> -0.0;
|
||||
min_value() -> $T::MIN;
|
||||
min_positive_value() -> $T::MIN_POSITIVE;
|
||||
epsilon() -> $T::EPSILON;
|
||||
max_value() -> $T::MAX;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(deprecated)]
|
||||
fn abs_sub(self, other: Self) -> Self {
|
||||
<$T as $LibmImpl>::fdim(self, other)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn integer_decode(self) -> (u64, i16, i8) {
|
||||
$decode(self)
|
||||
}
|
||||
|
||||
forward! {
|
||||
FloatCore::is_nan(self) -> bool;
|
||||
FloatCore::is_infinite(self) -> bool;
|
||||
FloatCore::is_finite(self) -> bool;
|
||||
FloatCore::is_normal(self) -> bool;
|
||||
FloatCore::classify(self) -> FpCategory;
|
||||
$LibmImpl::floor(self) -> Self;
|
||||
$LibmImpl::ceil(self) -> Self;
|
||||
$LibmImpl::round(self) -> Self;
|
||||
$LibmImpl::trunc(self) -> Self;
|
||||
$LibmImpl::fract(self) -> Self;
|
||||
$LibmImpl::abs(self) -> Self;
|
||||
FloatCore::signum(self) -> Self;
|
||||
FloatCore::is_sign_positive(self) -> bool;
|
||||
FloatCore::is_sign_negative(self) -> bool;
|
||||
$LibmImpl::mul_add(self, a: Self, b: Self) -> Self;
|
||||
FloatCore::recip(self) -> Self;
|
||||
FloatCore::powi(self, n: i32) -> Self;
|
||||
$LibmImpl::powf(self, n: Self) -> Self;
|
||||
$LibmImpl::sqrt(self) -> Self;
|
||||
$LibmImpl::exp(self) -> Self;
|
||||
$LibmImpl::exp2(self) -> Self;
|
||||
$LibmImpl::ln(self) -> Self;
|
||||
$LibmImpl::log(self, base: Self) -> Self;
|
||||
$LibmImpl::log2(self) -> Self;
|
||||
$LibmImpl::log10(self) -> Self;
|
||||
FloatCore::to_degrees(self) -> Self;
|
||||
FloatCore::to_radians(self) -> Self;
|
||||
FloatCore::max(self, other: Self) -> Self;
|
||||
FloatCore::min(self, other: Self) -> Self;
|
||||
$LibmImpl::cbrt(self) -> Self;
|
||||
$LibmImpl::hypot(self, other: Self) -> Self;
|
||||
$LibmImpl::sin(self) -> Self;
|
||||
$LibmImpl::cos(self) -> Self;
|
||||
$LibmImpl::tan(self) -> Self;
|
||||
$LibmImpl::asin(self) -> Self;
|
||||
$LibmImpl::acos(self) -> Self;
|
||||
$LibmImpl::atan(self) -> Self;
|
||||
$LibmImpl::atan2(self, other: Self) -> Self;
|
||||
$LibmImpl::sin_cos(self) -> (Self, Self);
|
||||
$LibmImpl::exp_m1(self) -> Self;
|
||||
$LibmImpl::ln_1p(self) -> Self;
|
||||
$LibmImpl::sinh(self) -> Self;
|
||||
$LibmImpl::cosh(self) -> Self;
|
||||
$LibmImpl::tanh(self) -> Self;
|
||||
$LibmImpl::asinh(self) -> Self;
|
||||
$LibmImpl::acosh(self) -> Self;
|
||||
$LibmImpl::atanh(self) -> Self;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
|
||||
// Safety: this identical to the implementation of f32::to_bits(),
|
||||
// which is only available starting at Rust 1.20
|
||||
let bits: u32 = unsafe { mem::transmute(f) };
|
||||
let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
|
||||
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
|
||||
|
@ -1895,6 +1983,8 @@ fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
|
|||
}
|
||||
|
||||
fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
|
||||
// Safety: this identical to the implementation of f64::to_bits(),
|
||||
// which is only available starting at Rust 1.20
|
||||
let bits: u64 = unsafe { mem::transmute(f) };
|
||||
let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
|
||||
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
|
||||
|
@ -1909,9 +1999,14 @@ fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
|
|||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
float_impl!(f32 integer_decode_f32);
|
||||
float_impl_std!(f32 integer_decode_f32);
|
||||
#[cfg(feature = "std")]
|
||||
float_impl!(f64 integer_decode_f64);
|
||||
float_impl_std!(f64 integer_decode_f64);
|
||||
|
||||
#[cfg(all(not(feature = "std"), feature = "libm"))]
|
||||
float_impl_libm!(f32 integer_decode_f32 F32Ext);
|
||||
#[cfg(all(not(feature = "std"), feature = "libm"))]
|
||||
float_impl_libm!(f64 integer_decode_f64 F64Ext);
|
||||
|
||||
macro_rules! float_const_impl {
|
||||
($(#[$doc:meta] $constant:ident,)+) => (
|
||||
|
@ -1994,7 +2089,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
#[test]
|
||||
fn convert_deg_rad_std() {
|
||||
for &(deg, rad) in &DEG_RAD_PAIRS {
|
||||
|
|
105
src/lib.rs
105
src/lib.rs
|
@ -20,13 +20,17 @@
|
|||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
// Only `no_std` builds actually use `libm`.
|
||||
#[cfg(all(not(feature = "std"), feature = "libm"))]
|
||||
extern crate libm;
|
||||
|
||||
use core::fmt;
|
||||
use core::num::Wrapping;
|
||||
use core::ops::{Add, Div, Mul, Rem, Sub};
|
||||
use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
|
||||
|
||||
pub use bounds::Bounded;
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
pub use float::Float;
|
||||
pub use float::FloatConst;
|
||||
// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`.
|
||||
|
@ -53,7 +57,6 @@ pub mod identities;
|
|||
pub mod int;
|
||||
pub mod ops;
|
||||
pub mod pow;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod real;
|
||||
pub mod sign;
|
||||
|
||||
|
@ -216,7 +219,12 @@ macro_rules! float_trait_impl {
|
|||
}
|
||||
|
||||
fn slice_shift_char(src: &str) -> Option<(char, &str)> {
|
||||
src.chars().nth(0).map(|ch| (ch, &src[1..]))
|
||||
let mut chars = src.chars();
|
||||
if let Some(ch) = chars.next() {
|
||||
Some((ch, chars.as_str()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
let (is_positive, src) = match slice_shift_char(src) {
|
||||
|
@ -359,6 +367,8 @@ float_trait_impl!(Num for f32 f64);
|
|||
/// If input is less than min then this returns min.
|
||||
/// If input is greater than max then this returns max.
|
||||
/// Otherwise this returns input.
|
||||
///
|
||||
/// **Panics** in debug mode if `!(min <= max)`.
|
||||
#[inline]
|
||||
pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
|
||||
debug_assert!(min <= max, "min must be less than or equal to max");
|
||||
|
@ -371,17 +381,97 @@ pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
|
|||
}
|
||||
}
|
||||
|
||||
/// A value bounded by a minimum value
|
||||
///
|
||||
/// If input is less than min then this returns min.
|
||||
/// Otherwise this returns input.
|
||||
/// `clamp_min(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::min(std::f32::NAN, 1.0)`.
|
||||
///
|
||||
/// **Panics** in debug mode if `!(min == min)`. (This occurs if `min` is `NAN`.)
|
||||
#[inline]
|
||||
pub fn clamp_min<T: PartialOrd>(input: T, min: T) -> T {
|
||||
debug_assert!(min == min, "min must not be NAN");
|
||||
if input < min {
|
||||
min
|
||||
} else {
|
||||
input
|
||||
}
|
||||
}
|
||||
|
||||
/// A value bounded by a maximum value
|
||||
///
|
||||
/// If input is greater than max then this returns max.
|
||||
/// Otherwise this returns input.
|
||||
/// `clamp_max(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::max(std::f32::NAN, 1.0)`.
|
||||
///
|
||||
/// **Panics** in debug mode if `!(max == max)`. (This occurs if `max` is `NAN`.)
|
||||
#[inline]
|
||||
pub fn clamp_max<T: PartialOrd>(input: T, max: T) -> T {
|
||||
debug_assert!(max == max, "max must not be NAN");
|
||||
if input > max {
|
||||
max
|
||||
} else {
|
||||
input
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clamp_test() {
|
||||
// Int test
|
||||
assert_eq!(1, clamp(1, -1, 2));
|
||||
assert_eq!(-1, clamp(-2, -1, 2));
|
||||
assert_eq!(2, clamp(3, -1, 2));
|
||||
assert_eq!(1, clamp_min(1, -1));
|
||||
assert_eq!(-1, clamp_min(-2, -1));
|
||||
assert_eq!(-1, clamp_max(1, -1));
|
||||
assert_eq!(-2, clamp_max(-2, -1));
|
||||
|
||||
// Float test
|
||||
assert_eq!(1.0, clamp(1.0, -1.0, 2.0));
|
||||
assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0));
|
||||
assert_eq!(2.0, clamp(3.0, -1.0, 2.0));
|
||||
assert_eq!(1.0, clamp_min(1.0, -1.0));
|
||||
assert_eq!(-1.0, clamp_min(-2.0, -1.0));
|
||||
assert_eq!(-1.0, clamp_max(1.0, -1.0));
|
||||
assert_eq!(-2.0, clamp_max(-2.0, -1.0));
|
||||
assert!(clamp(::core::f32::NAN, -1.0, 1.0).is_nan());
|
||||
assert!(clamp_min(::core::f32::NAN, 1.0).is_nan());
|
||||
assert!(clamp_max(::core::f32::NAN, 1.0).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(debug_assertions)]
|
||||
fn clamp_nan_min() {
|
||||
clamp(0., ::core::f32::NAN, 1.);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(debug_assertions)]
|
||||
fn clamp_nan_max() {
|
||||
clamp(0., -1., ::core::f32::NAN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(debug_assertions)]
|
||||
fn clamp_nan_min_max() {
|
||||
clamp(0., ::core::f32::NAN, ::core::f32::NAN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(debug_assertions)]
|
||||
fn clamp_min_nan_min() {
|
||||
clamp_min(0., ::core::f32::NAN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(debug_assertions)]
|
||||
fn clamp_max_nan_max() {
|
||||
clamp_max(0., ::core::f32::NAN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -395,6 +485,15 @@ fn from_str_radix_unwrap() {
|
|||
assert_eq!(f, 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str_radix_multi_byte_fail() {
|
||||
// Ensure parsing doesn't panic, even on invalid sign characters
|
||||
assert!(f32::from_str_radix("™0.2", 10).is_err());
|
||||
|
||||
// Even when parsing the exponent sign
|
||||
assert!(f32::from_str_radix("0.2E™1", 10).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping_is_num() {
|
||||
fn require_num<T: Num>(_: &T) {}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
/// // 100.0
|
||||
/// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs();
|
||||
///
|
||||
/// assert!(abs_difference <= f32::EPSILON);
|
||||
/// assert!(abs_difference <= 100.0 * f32::EPSILON);
|
||||
/// ```
|
||||
pub trait MulAdd<A = Self, B = Self> {
|
||||
/// The resulting type after applying the fused multiply-add.
|
||||
|
@ -34,23 +34,23 @@ pub trait MulAddAssign<A = Self, B = Self> {
|
|||
fn mul_add_assign(&mut self, a: A, b: B);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
impl MulAdd<f32, f32> for f32 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self::Output {
|
||||
f32::mul_add(self, a, b)
|
||||
<Self as ::Float>::mul_add(self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
impl MulAdd<f64, f64> for f64 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self::Output {
|
||||
f64::mul_add(self, a, b)
|
||||
<Self as ::Float>::mul_add(self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,19 +71,19 @@ mul_add_impl!(MulAdd for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
|
|||
#[cfg(has_i128)]
|
||||
mul_add_impl!(MulAdd for i128 u128);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
impl MulAddAssign<f32, f32> for f32 {
|
||||
#[inline]
|
||||
fn mul_add_assign(&mut self, a: Self, b: Self) {
|
||||
*self = f32::mul_add(*self, a, b)
|
||||
*self = <Self as ::Float>::mul_add(*self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
impl MulAddAssign<f64, f64> for f64 {
|
||||
#[inline]
|
||||
fn mul_add_assign(&mut self, a: Self, b: Self) {
|
||||
*self = f64::mul_add(*self, a, b)
|
||||
*self = <Self as ::Float>::mul_add(*self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,7 @@ mod tests {
|
|||
|
||||
let abs_difference = (MulAdd::mul_add(m, x, b) - (m*x + b)).abs();
|
||||
|
||||
assert!(abs_difference <= $t::EPSILON);
|
||||
assert!(abs_difference <= 46.4 * $t::EPSILON);
|
||||
}
|
||||
)+
|
||||
};
|
||||
|
|
33
src/pow.rs
33
src/pow.rs
|
@ -152,28 +152,29 @@ pow_impl!(Wrapping<isize>);
|
|||
// pow_impl!(usize, u64);
|
||||
// pow_impl!(isize, u64);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
mod float_impls {
|
||||
use super::Pow;
|
||||
use Float;
|
||||
|
||||
pow_impl!(f32, i8, i32, f32::powi);
|
||||
pow_impl!(f32, u8, i32, f32::powi);
|
||||
pow_impl!(f32, i16, i32, f32::powi);
|
||||
pow_impl!(f32, u16, i32, f32::powi);
|
||||
pow_impl!(f32, i32, i32, f32::powi);
|
||||
pow_impl!(f64, i8, i32, f64::powi);
|
||||
pow_impl!(f64, u8, i32, f64::powi);
|
||||
pow_impl!(f64, i16, i32, f64::powi);
|
||||
pow_impl!(f64, u16, i32, f64::powi);
|
||||
pow_impl!(f64, i32, i32, f64::powi);
|
||||
pow_impl!(f32, f32, f32, f32::powf);
|
||||
pow_impl!(f64, f32, f64, f64::powf);
|
||||
pow_impl!(f64, f64, f64, f64::powf);
|
||||
pow_impl!(f32, i8, i32, <f32 as Float>::powi);
|
||||
pow_impl!(f32, u8, i32, <f32 as Float>::powi);
|
||||
pow_impl!(f32, i16, i32, <f32 as Float>::powi);
|
||||
pow_impl!(f32, u16, i32, <f32 as Float>::powi);
|
||||
pow_impl!(f32, i32, i32, <f32 as Float>::powi);
|
||||
pow_impl!(f64, i8, i32, <f64 as Float>::powi);
|
||||
pow_impl!(f64, u8, i32, <f64 as Float>::powi);
|
||||
pow_impl!(f64, i16, i32, <f64 as Float>::powi);
|
||||
pow_impl!(f64, u16, i32, <f64 as Float>::powi);
|
||||
pow_impl!(f64, i32, i32, <f64 as Float>::powi);
|
||||
pow_impl!(f32, f32, f32, <f32 as Float>::powf);
|
||||
pow_impl!(f64, f32, f64, <f64 as Float>::powf);
|
||||
pow_impl!(f64, f64, f64, <f64 as Float>::powf);
|
||||
}
|
||||
|
||||
/// Raises a value to the power of exp, using exponentiation by squaring.
|
||||
///
|
||||
/// Note that `0⁰` (`pow(0, 0)`) returnes `1`. Mathematically this is undefined.
|
||||
/// Note that `0⁰` (`pow(0, 0)`) returns `1`. Mathematically this is undefined.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -211,7 +212,7 @@ pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) ->
|
|||
|
||||
/// Raises a value to the power of exp, returning `None` if an overflow occurred.
|
||||
///
|
||||
/// Note that `0⁰` (`checked_pow(0, 0)`) returnes `Some(1)`. Mathematically this is undefined.
|
||||
/// Note that `0⁰` (`checked_pow(0, 0)`) returns `Some(1)`. Mathematically this is undefined.
|
||||
///
|
||||
/// Otherwise same as the `pow` function.
|
||||
///
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use std::ops::Neg;
|
||||
#![cfg(any(feature = "std", feature = "libm"))]
|
||||
|
||||
use core::ops::Neg;
|
||||
|
||||
use {Float, Num, NumCast};
|
||||
|
||||
|
@ -11,7 +13,7 @@ use {Float, Num, NumCast};
|
|||
/// See [this Wikipedia article](https://en.wikipedia.org/wiki/Real_data_type)
|
||||
/// for a list of data types that could meaningfully implement this trait.
|
||||
///
|
||||
/// This trait is only available with the `std` feature.
|
||||
/// This trait is only available with the `std` feature, or with the `libm` feature otherwise.
|
||||
pub trait Real: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
|
||||
/// Returns the smallest finite value that this type can represent.
|
||||
///
|
||||
|
|
Loading…
Reference in New Issue