use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
pub trait Numeric:
Copy
+ Clone
+ PartialEq
+ PartialOrd
+ core::fmt::Debug
+ Add<Output = Self>
+ Sub<Output = Self>
+ Mul<Output = Self>
+ Div<Output = Self>
+ Neg<Output = Self>
+ AddAssign
+ SubAssign
+ MulAssign
+ DivAssign
{
const ZERO: Self;
const ONE: Self;
const TWO: Self;
const HALF: Self;
const HUNDRED: Self;
const PI: Self;
const TWO_PI: Self;
const EPSILON: Self;
const EPSILON_X4: Self;
const EPSILON_X30: Self;
const NAN: Self;
const INFINITY: Self;
const NEG_INFINITY: Self;
const MAX: Self;
const MIN_POSITIVE: Self;
fn from_f64(value: f64) -> Self;
fn from_u64(value: u64) -> Self;
fn from_usize(value: usize) -> Self;
fn abs(self) -> Self;
fn sqrt(self) -> Self;
fn sin(self) -> Self;
fn cos(self) -> Self;
fn tan(self) -> Self;
fn exp(self) -> Self;
fn ln(self) -> Self;
fn atan2(self, other: Self) -> Self;
fn copysign(self, sign: Self) -> Self;
fn floor(self) -> Self;
fn round(self) -> Self;
#[inline]
fn signum(self) -> Self {
if self < Self::ZERO {
-Self::ONE
} else if self > Self::ZERO {
Self::ONE
} else {
Self::ZERO
}
}
#[inline]
fn max(self, other: Self) -> Self {
if self > other { self } else { other }
}
#[inline]
fn min(self, other: Self) -> Self {
if self < other { self } else { other }
}
#[inline]
fn atan(self) -> Self {
self.atan2(Self::ONE)
}
#[inline]
fn asin(self) -> Self {
self.atan2((Self::ONE - self * self).sqrt())
}
#[inline]
fn acos(self) -> Self {
(Self::ONE - self * self).sqrt().atan2(self)
}
#[inline]
fn sinh(self) -> Self {
(self.exp() - (-self).exp()) * Self::HALF
}
#[inline]
fn cosh(self) -> Self {
(self.exp() + (-self).exp()) * Self::HALF
}
#[inline]
fn tanh(self) -> Self {
self.sinh() / self.cosh()
}
#[inline]
fn hypot(self, other: Self) -> Self {
let a = self.abs();
let b = other.abs();
let (max, min) = if a > b { (a, b) } else { (b, a) };
if max == Self::ZERO {
Self::ZERO
} else {
let ratio = min / max;
max * (Self::ONE + ratio * ratio).sqrt()
}
}
#[inline]
fn powf(self, n: Self) -> Self {
(n * self.ln()).exp()
}
#[inline]
fn mul_add(self, a: Self, b: Self) -> Self {
self * a + b
}
#[inline]
fn recip(self) -> Self {
Self::ONE / self
}
#[inline]
fn powi(self, n: i32) -> Self {
let mut exponent = n.unsigned_abs();
let mut base = self;
let mut acc = Self::ONE;
while exponent > 0 {
if exponent & 1 == 1 {
acc *= base;
}
exponent >>= 1;
if exponent > 0 {
base *= base;
}
}
if n < 0 { Self::ONE / acc } else { acc }
}
fn is_nan(self) -> bool;
fn is_finite(self) -> bool;
}
impl Numeric for f64 {
const ZERO: Self = 0.0;
const ONE: Self = 1.0;
const TWO: Self = 2.0;
const HALF: Self = 0.5;
const HUNDRED: Self = 100.0;
const PI: Self = core::f64::consts::PI;
const TWO_PI: Self = core::f64::consts::PI * 2.0;
const EPSILON: Self = f64::EPSILON;
const EPSILON_X4: Self = f64::EPSILON * 4.0;
const EPSILON_X30: Self = f64::EPSILON * 30.0;
const NAN: Self = f64::NAN;
const INFINITY: Self = f64::INFINITY;
const NEG_INFINITY: Self = f64::NEG_INFINITY;
const MAX: Self = f64::MAX;
const MIN_POSITIVE: Self = f64::MIN_POSITIVE;
#[inline]
fn from_f64(value: f64) -> Self {
value
}
#[inline]
fn from_u64(value: u64) -> Self {
value as f64
}
#[inline]
fn from_usize(value: usize) -> Self {
value as f64
}
#[inline]
fn abs(self) -> Self {
libm::fabs(self)
}
#[inline]
fn sqrt(self) -> Self {
libm::sqrt(self)
}
#[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 exp(self) -> Self {
libm::exp(self)
}
#[inline]
fn ln(self) -> Self {
libm::log(self)
}
#[inline]
fn atan2(self, other: Self) -> Self {
libm::atan2(self, other)
}
#[inline]
fn copysign(self, sign: Self) -> Self {
libm::copysign(self, sign)
}
#[inline]
fn floor(self) -> Self {
libm::floor(self)
}
#[inline]
fn round(self) -> Self {
libm::round(self)
}
#[inline]
fn max(self, other: Self) -> Self {
libm::fmax(self, other)
}
#[inline]
fn min(self, other: Self) -> Self {
libm::fmin(self, other)
}
#[inline]
fn signum(self) -> Self {
if f64::is_nan(self) {
f64::NAN
} else {
libm::copysign(1.0, self)
}
}
#[inline]
fn atan(self) -> Self {
libm::atan(self)
}
#[inline]
fn asin(self) -> Self {
libm::asin(self)
}
#[inline]
fn acos(self) -> Self {
libm::acos(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 hypot(self, other: Self) -> Self {
libm::hypot(self, other)
}
#[inline]
fn powf(self, n: Self) -> Self {
libm::pow(self, n)
}
#[inline]
fn mul_add(self, a: Self, b: Self) -> Self {
libm::fma(self, a, b)
}
#[inline]
fn recip(self) -> Self {
1.0 / self
}
#[inline]
fn is_nan(self) -> bool {
f64::is_nan(self)
}
#[inline]
fn is_finite(self) -> bool {
f64::is_finite(self)
}
}
impl Numeric for f32 {
const ZERO: Self = 0.0;
const ONE: Self = 1.0;
const TWO: Self = 2.0;
const HALF: Self = 0.5;
const HUNDRED: Self = 100.0;
const PI: Self = core::f32::consts::PI;
const TWO_PI: Self = core::f32::consts::PI * 2.0;
const EPSILON: Self = f32::EPSILON;
const EPSILON_X4: Self = f32::EPSILON * 4.0;
const EPSILON_X30: Self = f32::EPSILON * 30.0;
const NAN: Self = f32::NAN;
const INFINITY: Self = f32::INFINITY;
const NEG_INFINITY: Self = f32::NEG_INFINITY;
const MAX: Self = f32::MAX;
const MIN_POSITIVE: Self = f32::MIN_POSITIVE;
#[inline]
fn from_f64(value: f64) -> Self {
value as f32
}
#[inline]
fn from_u64(value: u64) -> Self {
value as f32
}
#[inline]
fn from_usize(value: usize) -> Self {
value as f32
}
#[inline]
fn abs(self) -> Self {
libm::fabsf(self)
}
#[inline]
fn sqrt(self) -> Self {
libm::sqrtf(self)
}
#[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 exp(self) -> Self {
libm::expf(self)
}
#[inline]
fn ln(self) -> Self {
libm::logf(self)
}
#[inline]
fn atan2(self, other: Self) -> Self {
libm::atan2f(self, other)
}
#[inline]
fn copysign(self, sign: Self) -> Self {
libm::copysignf(self, sign)
}
#[inline]
fn floor(self) -> Self {
libm::floorf(self)
}
#[inline]
fn round(self) -> Self {
libm::roundf(self)
}
#[inline]
fn max(self, other: Self) -> Self {
libm::fmaxf(self, other)
}
#[inline]
fn min(self, other: Self) -> Self {
libm::fminf(self, other)
}
#[inline]
fn signum(self) -> Self {
if f32::is_nan(self) {
f32::NAN
} else {
libm::copysignf(1.0, self)
}
}
#[inline]
fn atan(self) -> Self {
libm::atanf(self)
}
#[inline]
fn asin(self) -> Self {
libm::asinf(self)
}
#[inline]
fn acos(self) -> Self {
libm::acosf(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 hypot(self, other: Self) -> Self {
libm::hypotf(self, other)
}
#[inline]
fn powf(self, n: Self) -> Self {
libm::powf(self, n)
}
#[inline]
fn mul_add(self, a: Self, b: Self) -> Self {
libm::fmaf(self, a, b)
}
#[inline]
fn recip(self) -> Self {
1.0 / self
}
#[inline]
fn is_nan(self) -> bool {
f32::is_nan(self)
}
#[inline]
fn is_finite(self) -> bool {
f32::is_finite(self)
}
}