#[cfg(feature = "std")]
use std::mem;
#[cfg(feature = "std")]
use std::ops::Neg;
#[cfg(feature = "std")]
use std::num::FpCategory;
#[cfg(feature = "std")]
use std::f32;
#[cfg(feature = "std")]
use {Num, NumCast};
#[cfg(feature = "std")]
pub trait Float
: Num
+ Copy
+ NumCast
+ PartialOrd
+ Neg<Output = Self>
{
fn nan() -> Self;
fn infinity() -> Self;
fn neg_infinity() -> Self;
fn neg_zero() -> Self;
fn min_value() -> Self;
fn min_positive_value() -> Self;
fn epsilon() -> Self {
Self::from(f32::EPSILON).expect("Unable to cast from f32::EPSILON")
}
fn max_value() -> Self;
fn is_nan(self) -> bool;
fn is_infinite(self) -> bool;
fn is_finite(self) -> bool;
fn is_normal(self) -> bool;
fn classify(self) -> FpCategory;
fn floor(self) -> Self;
fn ceil(self) -> Self;
fn round(self) -> Self;
fn trunc(self) -> Self;
fn fract(self) -> Self;
fn abs(self) -> Self;
fn signum(self) -> Self;
fn is_sign_positive(self) -> bool;
fn is_sign_negative(self) -> bool;
fn mul_add(self, a: Self, b: Self) -> Self;
fn recip(self) -> Self;
fn powi(self, n: i32) -> Self;
fn powf(self, n: Self) -> Self;
fn sqrt(self) -> Self;
fn exp(self) -> Self;
fn exp2(self) -> Self;
fn ln(self) -> Self;
fn log(self, base: Self) -> Self;
fn log2(self) -> Self;
fn log10(self) -> Self;
#[inline]
fn to_degrees(self) -> Self {
let halfpi = Self::zero().acos();
let ninety = Self::from(90u8).unwrap();
self * ninety / halfpi
}
#[inline]
fn to_radians(self) -> Self {
let halfpi = Self::zero().acos();
let ninety = Self::from(90u8).unwrap();
self * halfpi / ninety
}
fn max(self, other: Self) -> Self;
fn min(self, other: Self) -> Self;
fn abs_sub(self, other: Self) -> Self;
fn cbrt(self) -> Self;
fn hypot(self, other: Self) -> Self;
fn sin(self) -> Self;
fn cos(self) -> Self;
fn tan(self) -> Self;
fn asin(self) -> Self;
fn acos(self) -> Self;
fn atan(self) -> Self;
fn atan2(self, other: Self) -> Self;
fn sin_cos(self) -> (Self, Self);
fn exp_m1(self) -> Self;
fn ln_1p(self) -> Self;
fn sinh(self) -> Self;
fn cosh(self) -> Self;
fn tanh(self) -> Self;
fn asinh(self) -> Self;
fn acosh(self) -> Self;
fn atanh(self) -> Self;
fn integer_decode(self) -> (u64, i16, i8);
}
#[cfg(feature = "std")]
macro_rules! float_impl {
($T:ident $decode:ident) => (
impl Float for $T {
#[inline]
fn nan() -> Self {
::std::$T::NAN
}
#[inline]
fn infinity() -> Self {
::std::$T::INFINITY
}
#[inline]
fn neg_infinity() -> Self {
::std::$T::NEG_INFINITY
}
#[inline]
fn neg_zero() -> Self {
-0.0
}
#[inline]
fn min_value() -> Self {
::std::$T::MIN
}
#[inline]
fn min_positive_value() -> Self {
::std::$T::MIN_POSITIVE
}
#[inline]
fn epsilon() -> Self {
::std::$T::EPSILON
}
#[inline]
fn max_value() -> Self {
::std::$T::MAX
}
#[inline]
fn is_nan(self) -> bool {
<$T>::is_nan(self)
}
#[inline]
fn is_infinite(self) -> bool {
<$T>::is_infinite(self)
}
#[inline]
fn is_finite(self) -> bool {
<$T>::is_finite(self)
}
#[inline]
fn is_normal(self) -> bool {
<$T>::is_normal(self)
}
#[inline]
fn classify(self) -> FpCategory {
<$T>::classify(self)
}
#[inline]
fn floor(self) -> Self {
<$T>::floor(self)
}
#[inline]
fn ceil(self) -> Self {
<$T>::ceil(self)
}
#[inline]
fn round(self) -> Self {
<$T>::round(self)
}
#[inline]
fn trunc(self) -> Self {
<$T>::trunc(self)
}
#[inline]
fn fract(self) -> Self {
<$T>::fract(self)
}
#[inline]
fn abs(self) -> Self {
<$T>::abs(self)
}
#[inline]
fn signum(self) -> Self {
<$T>::signum(self)
}
#[inline]
fn is_sign_positive(self) -> bool {
<$T>::is_sign_positive(self)
}
#[inline]
fn is_sign_negative(self) -> bool {
<$T>::is_sign_negative(self)
}
#[inline]
fn mul_add(self, a: Self, b: Self) -> Self {
<$T>::mul_add(self, a, b)
}
#[inline]
fn recip(self) -> Self {
<$T>::recip(self)
}
#[inline]
fn powi(self, n: i32) -> Self {
<$T>::powi(self, n)
}
#[inline]
fn powf(self, n: Self) -> Self {
<$T>::powf(self, n)
}
#[inline]
fn sqrt(self) -> Self {
<$T>::sqrt(self)
}
#[inline]
fn exp(self) -> Self {
<$T>::exp(self)
}
#[inline]
fn exp2(self) -> Self {
<$T>::exp2(self)
}
#[inline]
fn ln(self) -> Self {
<$T>::ln(self)
}
#[inline]
fn log(self, base: Self) -> Self {
<$T>::log(self, base)
}
#[inline]
fn log2(self) -> Self {
<$T>::log2(self)
}
#[inline]
fn log10(self) -> Self {
<$T>::log10(self)
}
#[inline]
fn to_degrees(self) -> Self {
self * (180. / ::std::$T::consts::PI)
}
#[inline]
fn to_radians(self) -> Self {
self * (::std::$T::consts::PI / 180.)
}
#[inline]
fn max(self, other: Self) -> Self {
<$T>::max(self, other)
}
#[inline]
fn min(self, other: Self) -> Self {
<$T>::min(self, other)
}
#[inline]
#[allow(deprecated)]
fn abs_sub(self, other: Self) -> Self {
<$T>::abs_sub(self, other)
}
#[inline]
fn cbrt(self) -> Self {
<$T>::cbrt(self)
}
#[inline]
fn hypot(self, other: Self) -> Self {
<$T>::hypot(self, other)
}
#[inline]
fn sin(self) -> Self {
<$T>::sin(self)
}
#[inline]
fn cos(self) -> Self {
<$T>::cos(self)
}
#[inline]
fn tan(self) -> Self {
<$T>::tan(self)
}
#[inline]
fn asin(self) -> Self {
<$T>::asin(self)
}
#[inline]
fn acos(self) -> Self {
<$T>::acos(self)
}
#[inline]
fn atan(self) -> Self {
<$T>::atan(self)
}
#[inline]
fn atan2(self, other: Self) -> Self {
<$T>::atan2(self, other)
}
#[inline]
fn sin_cos(self) -> (Self, Self) {
<$T>::sin_cos(self)
}
#[inline]
fn exp_m1(self) -> Self {
<$T>::exp_m1(self)
}
#[inline]
fn ln_1p(self) -> Self {
<$T>::ln_1p(self)
}
#[inline]
fn sinh(self) -> Self {
<$T>::sinh(self)
}
#[inline]
fn cosh(self) -> Self {
<$T>::cosh(self)
}
#[inline]
fn tanh(self) -> Self {
<$T>::tanh(self)
}
#[inline]
fn asinh(self) -> Self {
<$T>::asinh(self)
}
#[inline]
fn acosh(self) -> Self {
<$T>::acosh(self)
}
#[inline]
fn atanh(self) -> Self {
<$T>::atanh(self)
}
#[inline]
fn integer_decode(self) -> (u64, i16, i8) {
$decode(self)
}
}
)
}
#[cfg(feature = "std")]
fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
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;
let mantissa = if exponent == 0 {
(bits & 0x7fffff) << 1
} else {
(bits & 0x7fffff) | 0x800000
};
exponent -= 127 + 23;
(mantissa as u64, exponent, sign)
}
#[cfg(feature = "std")]
fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
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;
let mantissa = if exponent == 0 {
(bits & 0xfffffffffffff) << 1
} else {
(bits & 0xfffffffffffff) | 0x10000000000000
};
exponent -= 1023 + 52;
(mantissa, exponent, sign)
}
#[cfg(feature = "std")]
float_impl!(f32 integer_decode_f32);
#[cfg(feature = "std")]
float_impl!(f64 integer_decode_f64);
macro_rules! float_const_impl {
($(#[$doc:meta] $constant:ident,)+) => (
#[allow(non_snake_case)]
pub trait FloatConst {
$(#[$doc] fn $constant() -> Self;)+
}
float_const_impl! { @float f32, $($constant,)+ }
float_const_impl! { @float f64, $($constant,)+ }
);
(@float $T:ident, $($constant:ident,)+) => (
impl FloatConst for $T {
$(
#[inline]
fn $constant() -> Self {
::core::$T::consts::$constant
}
)+
}
);
}
float_const_impl! {
#[doc = "Return Euler’s number."]
E,
#[doc = "Return `1.0 / π`."]
FRAC_1_PI,
#[doc = "Return `1.0 / sqrt(2.0)`."]
FRAC_1_SQRT_2,
#[doc = "Return `2.0 / π`."]
FRAC_2_PI,
#[doc = "Return `2.0 / sqrt(π)`."]
FRAC_2_SQRT_PI,
#[doc = "Return `π / 2.0`."]
FRAC_PI_2,
#[doc = "Return `π / 3.0`."]
FRAC_PI_3,
#[doc = "Return `π / 4.0`."]
FRAC_PI_4,
#[doc = "Return `π / 6.0`."]
FRAC_PI_6,
#[doc = "Return `π / 8.0`."]
FRAC_PI_8,
#[doc = "Return `ln(10.0)`."]
LN_10,
#[doc = "Return `ln(2.0)`."]
LN_2,
#[doc = "Return `log10(e)`."]
LOG10_E,
#[doc = "Return `log2(e)`."]
LOG2_E,
#[doc = "Return Archimedes’ constant."]
PI,
#[doc = "Return `sqrt(2.0)`."]
SQRT_2,
}
#[cfg(all(test, feature = "std"))]
mod tests {
use Float;
#[test]
fn convert_deg_rad() {
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),
];
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);
}
}
}