use core::ops::Rem;
pub(crate) trait Libm: Rem<Output = Self> + Sized {
fn cos(self) -> Self;
fn abs(self) -> Self;
fn copysign(self, other: Self) -> Self;
fn signum(self) -> Self;
fn exp(self) -> Self;
}
impl Libm for f32 {
#[inline(always)]
fn cos(self) -> Self {
libm::cosf(self)
}
#[inline(always)]
fn abs(self) -> Self {
libm::fabsf(self)
}
#[inline(always)]
fn copysign(self, other: Self) -> Self {
libm::copysignf(self, other)
}
#[inline(always)]
fn signum(self) -> Self {
if self.is_nan() {
Self::NAN
} else {
1.0_f32.copysign(self)
}
}
#[inline(always)]
fn exp(self) -> Self {
libm::expf(self)
}
}
#[cfg(test)]
mod tests {
#[test]
fn math_signum() {
let f = 3.5_f32;
assert_eq!(f.copysign(0.42), 3.5_f32);
assert_eq!(f.copysign(-0.42), -3.5_f32);
assert_eq!((-f).copysign(0.42), 3.5_f32);
assert_eq!((-f).copysign(-0.42), -3.5_f32);
assert!(f32::NAN.copysign(1.0).is_nan());
}
#[test]
fn math_exp() {
let one = 1.0f32;
let e = one.exp();
let abs_difference = (e.ln() - 1.0).abs();
assert!(abs_difference <= f32::EPSILON);
}
}