use core::mem;
use core::ops::Neg;
use core::num::FpCategory;
use core::f32;
use {ToPrimitive, Num, NumCast};
pub trait Float
: Num
+ Copy
+ NumCast
+ PartialOrd
+ Neg<Output = Self>
{
fn nan() -> Self;
fn infinity() -> Self;
fn neg_infinity() -> Self;
#[inline]
fn neg_zero() -> Self {
-Self::zero()
}
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;
#[inline]
fn is_nan(self) -> bool {
self != self
}
#[inline]
fn is_infinite(self) -> bool {
self == Self::infinity() || self == Self::neg_infinity()
}
#[inline]
fn is_finite(self) -> bool {
!(self.is_nan() || self.is_infinite())
}
#[inline]
fn is_normal(self) -> bool {
self.classify() == FpCategory::Normal
}
fn classify(self) -> FpCategory;
#[cfg(feature = "std")]
fn floor(self) -> Self;
#[cfg(feature = "std")]
fn ceil(self) -> Self;
#[cfg(feature = "std")]
fn round(self) -> Self;
#[cfg(feature = "std")]
fn trunc(self) -> Self;
#[cfg(feature = "std")]
fn fract(self) -> Self;
#[inline]
fn abs(self) -> Self {
if self.is_sign_positive() {
return self;
}
if self.is_sign_negative() {
return -self;
}
Self::nan()
}
#[inline]
fn signum(self) -> Self {
if self.is_sign_positive() {
return Self::one();
}
if self.is_sign_negative() {
return -Self::one();
}
Self::nan()
}
#[inline]
fn is_sign_positive(self) -> bool {
self > Self::zero() || (Self::one() / self) == Self::infinity()
}
#[inline]
fn is_sign_negative(self) -> bool {
self < Self::zero() || (Self::one() / self) == Self::neg_infinity()
}
#[cfg(feature = "std")]
fn mul_add(self, a: Self, b: Self) -> Self;
#[inline]
fn recip(self) -> Self {
Self::one() / self
}
#[inline]
fn powi(mut self, mut exp: i32) -> Self {
if exp < 0 {
self = self.recip();
exp = -exp;
}
super::pow(self, exp.to_usize().unwrap())
}
#[cfg(feature = "std")]
fn powf(self, n: Self) -> Self;
#[cfg(feature = "std")]
fn sqrt(self) -> Self;
#[cfg(feature = "std")]
fn exp(self) -> Self;
#[cfg(feature = "std")]
fn exp2(self) -> Self;
#[cfg(feature = "std")]
fn ln(self) -> Self;
#[cfg(feature = "std")]
fn log(self, base: Self) -> Self;
#[cfg(feature = "std")]
fn log2(self) -> Self;
#[cfg(feature = "std")]
fn log10(self) -> Self;
#[cfg(feature = "std")]
#[inline]
fn to_degrees(self) -> Self {
let halfpi = Self::zero().acos();
let ninety = Self::from(90u8).unwrap();
self * ninety / halfpi
}
#[cfg(not(feature = "std"))]
fn to_degrees(self) -> Self;
#[cfg(feature = "std")]
#[inline]
fn to_radians(self) -> Self {
let halfpi = Self::zero().acos();
let ninety = Self::from(90u8).unwrap();
self * halfpi / ninety
}
#[cfg(not(feature = "std"))]
fn to_radians(self) -> Self;
#[inline]
fn max(self, other: Self) -> Self {
if self.is_nan() {
return other;
}
if other.is_nan() {
return self;
}
if self > other { self } else { other }
}
#[inline]
fn min(self, other: Self) -> Self {
if self.is_nan() {
return other;
}
if other.is_nan() {
return self;
}
if self < other { self } else { other }
}
#[cfg(feature = "std")]
fn abs_sub(self, other: Self) -> Self;
#[cfg(feature = "std")]
fn cbrt(self) -> Self;
#[cfg(feature = "std")]
fn hypot(self, other: Self) -> Self;
#[cfg(feature = "std")]
fn sin(self) -> Self;
#[cfg(feature = "std")]
fn cos(self) -> Self;
#[cfg(feature = "std")]
fn tan(self) -> Self;
#[cfg(feature = "std")]
fn asin(self) -> Self;
#[cfg(feature = "std")]
fn acos(self) -> Self;
#[cfg(feature = "std")]
fn atan(self) -> Self;
#[cfg(feature = "std")]
fn atan2(self, other: Self) -> Self;
#[cfg(feature = "std")]
fn sin_cos(self) -> (Self, Self);
#[cfg(feature = "std")]
fn exp_m1(self) -> Self;
#[cfg(feature = "std")]
fn ln_1p(self) -> Self;
#[cfg(feature = "std")]
fn sinh(self) -> Self;
#[cfg(feature = "std")]
fn cosh(self) -> Self;
#[cfg(feature = "std")]
fn tanh(self) -> Self;
#[cfg(feature = "std")]
fn asinh(self) -> Self;
#[cfg(feature = "std")]
fn acosh(self) -> Self;
#[cfg(feature = "std")]
fn atanh(self) -> Self;
fn integer_decode(self) -> (u64, i16, i8);
}
macro_rules! float_impl {
($T:ident $decode:ident $classify:ident) => (
impl Float for $T {
#[inline]
fn nan() -> Self {
::core::$T::NAN
}
#[inline]
fn infinity() -> Self {
::core::$T::INFINITY
}
#[inline]
fn neg_infinity() -> Self {
::core::$T::NEG_INFINITY
}
#[inline]
fn neg_zero() -> Self {
-0.0
}
#[inline]
fn min_value() -> Self {
::core::$T::MIN
}
#[inline]
fn min_positive_value() -> Self {
::core::$T::MIN_POSITIVE
}
#[inline]
fn epsilon() -> Self {
::core::$T::EPSILON
}
#[inline]
fn max_value() -> Self {
::core::$T::MAX
}
#[cfg(feature = "std")]
#[inline]
fn is_nan(self) -> bool {
<$T>::is_nan(self)
}
#[cfg(feature = "std")]
#[inline]
fn is_infinite(self) -> bool {
<$T>::is_infinite(self)
}
#[cfg(feature = "std")]
#[inline]
fn is_finite(self) -> bool {
<$T>::is_finite(self)
}
#[cfg(feature = "std")]
#[inline]
fn is_normal(self) -> bool {
<$T>::is_normal(self)
}
#[cfg(feature = "std")]
#[inline]
fn classify(self) -> FpCategory {
<$T>::classify(self)
}
#[cfg(not(feature = "std"))]
#[inline]
fn classify(self) -> FpCategory {
$classify(self)
}
#[cfg(feature = "std")]
#[inline]
fn floor(self) -> Self {
<$T>::floor(self)
}
#[cfg(feature = "std")]
#[inline]
fn ceil(self) -> Self {
<$T>::ceil(self)
}
#[cfg(feature = "std")]
#[inline]
fn round(self) -> Self {
<$T>::round(self)
}
#[cfg(feature = "std")]
#[inline]
fn trunc(self) -> Self {
<$T>::trunc(self)
}
#[cfg(feature = "std")]
#[inline]
fn fract(self) -> Self {
<$T>::fract(self)
}
#[cfg(feature = "std")]
#[inline]
fn abs(self) -> Self {
<$T>::abs(self)
}
#[cfg(feature = "std")]
#[inline]
fn signum(self) -> Self {
<$T>::signum(self)
}
#[cfg(feature = "std")]
#[inline]
fn is_sign_positive(self) -> bool {
<$T>::is_sign_positive(self)
}
#[cfg(feature = "std")]
#[inline]
fn is_sign_negative(self) -> bool {
<$T>::is_sign_negative(self)
}
#[cfg(feature = "std")]
#[inline]
fn mul_add(self, a: Self, b: Self) -> Self {
<$T>::mul_add(self, a, b)
}
#[cfg(feature = "std")]
#[inline]
fn recip(self) -> Self {
<$T>::recip(self)
}
#[cfg(feature = "std")]
#[inline]
fn powi(self, n: i32) -> Self {
<$T>::powi(self, n)
}
#[cfg(feature = "std")]
#[inline]
fn powf(self, n: Self) -> Self {
<$T>::powf(self, n)
}
#[cfg(feature = "std")]
#[inline]
fn sqrt(self) -> Self {
<$T>::sqrt(self)
}
#[cfg(feature = "std")]
#[inline]
fn exp(self) -> Self {
<$T>::exp(self)
}
#[cfg(feature = "std")]
#[inline]
fn exp2(self) -> Self {
<$T>::exp2(self)
}
#[cfg(feature = "std")]
#[inline]
fn ln(self) -> Self {
<$T>::ln(self)
}
#[cfg(feature = "std")]
#[inline]
fn log(self, base: Self) -> Self {
<$T>::log(self, base)
}
#[cfg(feature = "std")]
#[inline]
fn log2(self) -> Self {
<$T>::log2(self)
}
#[cfg(feature = "std")]
#[inline]
fn log10(self) -> Self {
<$T>::log10(self)
}
#[cfg(feature = "std")]
#[inline]
fn to_degrees(self) -> Self {
<$T>::to_degrees(self)
}
#[cfg(feature = "std")]
#[inline]
fn to_radians(self) -> Self {
<$T>::to_radians(self)
}
#[cfg(not(feature = "std"))]
#[inline]
fn to_degrees(self) -> Self {
self * (180. / ::core::$T::consts::PI)
}
#[cfg(not(feature = "std"))]
#[inline]
fn to_radians(self) -> Self {
self * (::core::$T::consts::PI / 180.)
}
#[cfg(feature = "std")]
#[inline]
fn max(self, other: Self) -> Self {
<$T>::max(self, other)
}
#[cfg(feature = "std")]
#[inline]
fn min(self, other: Self) -> Self {
<$T>::min(self, other)
}
#[cfg(feature = "std")]
#[inline]
#[allow(deprecated)]
fn abs_sub(self, other: Self) -> Self {
<$T>::abs_sub(self, other)
}
#[cfg(feature = "std")]
#[inline]
fn cbrt(self) -> Self {
<$T>::cbrt(self)
}
#[cfg(feature = "std")]
#[inline]
fn hypot(self, other: Self) -> Self {
<$T>::hypot(self, other)
}
#[cfg(feature = "std")]
#[inline]
fn sin(self) -> Self {
<$T>::sin(self)
}
#[cfg(feature = "std")]
#[inline]
fn cos(self) -> Self {
<$T>::cos(self)
}
#[cfg(feature = "std")]
#[inline]
fn tan(self) -> Self {
<$T>::tan(self)
}
#[cfg(feature = "std")]
#[inline]
fn asin(self) -> Self {
<$T>::asin(self)
}
#[cfg(feature = "std")]
#[inline]
fn acos(self) -> Self {
<$T>::acos(self)
}
#[cfg(feature = "std")]
#[inline]
fn atan(self) -> Self {
<$T>::atan(self)
}
#[cfg(feature = "std")]
#[inline]
fn atan2(self, other: Self) -> Self {
<$T>::atan2(self, other)
}
#[cfg(feature = "std")]
#[inline]
fn sin_cos(self) -> (Self, Self) {
<$T>::sin_cos(self)
}
#[cfg(feature = "std")]
#[inline]
fn exp_m1(self) -> Self {
<$T>::exp_m1(self)
}
#[cfg(feature = "std")]
#[inline]
fn ln_1p(self) -> Self {
<$T>::ln_1p(self)
}
#[cfg(feature = "std")]
#[inline]
fn sinh(self) -> Self {
<$T>::sinh(self)
}
#[cfg(feature = "std")]
#[inline]
fn cosh(self) -> Self {
<$T>::cosh(self)
}
#[cfg(feature = "std")]
#[inline]
fn tanh(self) -> Self {
<$T>::tanh(self)
}
#[cfg(feature = "std")]
#[inline]
fn asinh(self) -> Self {
<$T>::asinh(self)
}
#[cfg(feature = "std")]
#[inline]
fn acosh(self) -> Self {
<$T>::acosh(self)
}
#[cfg(feature = "std")]
#[inline]
fn atanh(self) -> Self {
<$T>::atanh(self)
}
#[inline]
fn integer_decode(self) -> (u64, i16, i8) {
$decode(self)
}
}
)
}
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(not(feature = "std"))]
fn classify_f32(f: f32) -> FpCategory {
const EXP_MASK: u32 = 0x7f800000;
const MAN_MASK: u32 = 0x007fffff;
let bits: u32 = unsafe { mem::transmute(f) };
match (bits & MAN_MASK, bits & EXP_MASK) {
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
(0, EXP_MASK) => FpCategory::Infinite,
(_, EXP_MASK) => FpCategory::Nan,
_ => FpCategory::Normal,
}
}
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(not(feature = "std"))]
fn classify_f64(f: f64) -> FpCategory {
const EXP_MASK: u64 = 0x7ff0000000000000;
const MAN_MASK: u64 = 0x000fffffffffffff;
let bits: u64 = unsafe { mem::transmute(f) };
match (bits & MAN_MASK, bits & EXP_MASK) {
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
(0, EXP_MASK) => FpCategory::Infinite,
(_, EXP_MASK) => FpCategory::Nan,
_ => FpCategory::Normal,
}
}
float_impl!(f32 integer_decode_f32 classify_f32);
float_impl!(f64 integer_decode_f64 classify_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(test)]
mod tests {
use Float;
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),
];
#[test]
fn convert_deg_rad_core() {
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);
}
}
#[cfg(feature = "std")]
#[test]
fn convert_deg_rad_std() {
use Float;
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);
}
}
}