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 THREE: Self;
const HALF: Self;
const TEN: Self;
const HUNDRED: Self;
const ONE_HUNDRED_EIGHTY: 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;
type Constant: Numeric;
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 cbrt(self) -> Self;
fn sin(self) -> Self;
fn cos(self) -> Self;
fn tan(self) -> Self;
fn exp(self) -> Self;
fn ln(self) -> Self;
fn expm1(self) -> Self {
self.exp() - Self::ONE
}
fn ln_1p(self) -> Self {
(self + Self::ONE).ln()
}
fn log2(self) -> Self {
self.ln() / Self::TWO.ln()
}
fn log10(self) -> Self {
self.ln() / Self::TEN.ln()
}
fn atan2(self, other: Self) -> Self;
fn copysign(self, sign: Self) -> Self;
fn floor(self) -> Self;
fn ceil(self) -> Self;
fn round(self) -> Self;
fn trunc(self) -> Self;
fn clamp(self, min: Self::Constant, max: Self::Constant) -> 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 wrap_to_pi(self) -> Self {
self - Self::TWO_PI * (self / Self::TWO_PI).round()
}
#[inline]
fn to_radians(self) -> Self {
self / Self::ONE_HUNDRED_EIGHTY * Self::PI
}
#[inline]
fn to_degrees(self) -> Self {
self / Self::PI * Self::ONE_HUNDRED_EIGHTY
}
#[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().safe_div(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.safe_div(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 }
}
#[inline]
fn safe_div(self, other: Self) -> Self {
if other == Self::ZERO {
if self.is_nan() {
return Self::NAN;
} else if self < Self::ZERO {
return Self::NEG_INFINITY;
} else if Self::ZERO < self {
return Self::INFINITY;
} else {
return Self::NAN;
}
}
self / other
}
fn is_nan(self) -> bool;
fn is_finite(self) -> bool;
fn is_infinite(self) -> bool;
}
impl Numeric for f64 {
const ZERO: Self = 0.0;
const ONE: Self = 1.0;
const TWO: Self = 2.0;
const THREE: Self = 3.0;
const HALF: Self = 0.5;
const TEN: Self = 10.0;
const HUNDRED: Self = 100.0;
const ONE_HUNDRED_EIGHTY: Self = 180.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;
type Constant = f64;
#[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 cbrt(self) -> Self {
libm::cbrt(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 expm1(self) -> Self {
libm::expm1(self)
}
#[inline]
fn ln(self) -> Self {
libm::log(self)
}
#[inline]
fn ln_1p(self) -> Self {
libm::log1p(self)
}
#[inline]
fn log2(self) -> Self {
libm::log2(self)
}
#[inline]
fn log10(self) -> Self {
libm::log10(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 ceil(self) -> Self {
libm::ceil(self)
}
#[inline]
fn round(self) -> Self {
libm::round(self)
}
#[inline]
fn trunc(self) -> Self {
libm::trunc(self)
}
#[inline]
fn clamp(self, min: Self::Constant, max: Self::Constant) -> Self {
self.clamp(min, max)
}
#[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)
}
#[inline]
fn is_infinite(self) -> bool {
f64::is_infinite(self)
}
}
impl Numeric for f32 {
const ZERO: Self = 0.0;
const ONE: Self = 1.0;
const TWO: Self = 2.0;
const THREE: Self = 3.0;
const HALF: Self = 0.5;
const TEN: Self = 10.0;
const HUNDRED: Self = 100.0;
const ONE_HUNDRED_EIGHTY: Self = 180.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;
type Constant = f32;
#[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 cbrt(self) -> Self {
libm::cbrtf(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 expm1(self) -> Self {
libm::expm1f(self)
}
#[inline]
fn ln(self) -> Self {
libm::logf(self)
}
#[inline]
fn ln_1p(self) -> Self {
libm::log1pf(self)
}
#[inline]
fn log2(self) -> Self {
libm::log2f(self)
}
#[inline]
fn log10(self) -> Self {
libm::log10f(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 ceil(self) -> Self {
libm::ceilf(self)
}
#[inline]
fn round(self) -> Self {
libm::roundf(self)
}
#[inline]
fn trunc(self) -> Self {
libm::truncf(self)
}
#[inline]
fn clamp(self, min: Self::Constant, max: Self::Constant) -> Self {
self.clamp(min, max)
}
#[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)
}
#[inline]
fn is_infinite(self) -> bool {
f32::is_infinite(self)
}
}