use crate::math::Math;
use core::cmp::PartialOrd;
use core::ops::Neg;
use num_traits::{Num, NumAssignOps};
pub use num_traits::{One, Zero};
pub const EPS_F32: f32 = 1.0 / (1024.0 * 1024.0);
pub const EPS_F64: f64 = 1.0 / (1024.0 * 1024.0 * 1024.0 * 1024.0);
pub trait Scalar:
Num + NumAssignOps + Neg<Output = Self> + PartialOrd + Clone + Copy + Sized
{
fn two() -> Self;
fn min(l: Self, r: Self) -> Self;
fn max(l: Self, r: Self) -> Self;
fn squared(self) -> Self {
self * self
}
fn tabs(self) -> Self;
}
pub trait FloatScalar: Scalar {
fn epsilon() -> Self;
fn half() -> Self;
fn quarter() -> Self;
fn infinity() -> Self;
fn tsqrt(self) -> Self;
fn tsin(self) -> Self;
fn tcos(self) -> Self;
fn ttan(self) -> Self;
fn tacos(self) -> Self;
}
impl Scalar for i32 {
fn two() -> Self {
2
}
fn min(l: Self, r: Self) -> Self {
if l < r {
l
} else {
r
}
}
fn max(l: Self, r: Self) -> Self {
if l > r {
l
} else {
r
}
}
fn tabs(self) -> Self {
self.abs()
}
}
impl Scalar for i64 {
fn two() -> Self {
2
}
fn min(l: Self, r: Self) -> Self {
if l < r {
l
} else {
r
}
}
fn max(l: Self, r: Self) -> Self {
if l > r {
l
} else {
r
}
}
fn tabs(self) -> Self {
self.abs()
}
}
impl Scalar for f32 {
fn two() -> Self {
2.0
}
fn min(l: Self, r: Self) -> Self {
if l < r {
l
} else {
r
}
}
fn max(l: Self, r: Self) -> Self {
if l > r {
l
} else {
r
}
}
fn tabs(self) -> Self {
self.abs()
}
}
impl Scalar for f64 {
fn two() -> Self {
2.0
}
fn min(l: Self, r: Self) -> Self {
if l < r {
l
} else {
r
}
}
fn max(l: Self, r: Self) -> Self {
if l > r {
l
} else {
r
}
}
fn tabs(self) -> Self {
self.abs()
}
}
impl FloatScalar for f32 {
fn epsilon() -> Self {
EPS_F32
}
fn half() -> Self {
0.5
}
fn quarter() -> Self {
0.25
}
fn infinity() -> Self {
f32::INFINITY
}
fn tsqrt(self) -> Self {
Math::sqrt_f32(self)
}
fn tsin(self) -> Self {
Math::sin_f32(self)
}
fn tcos(self) -> Self {
Math::cos_f32(self)
}
fn ttan(self) -> Self {
Math::tan_f32(self)
}
fn tacos(self) -> Self {
Math::acos_f32(self)
}
}
impl FloatScalar for f64 {
fn epsilon() -> Self {
EPS_F64
}
fn half() -> Self {
0.5
}
fn quarter() -> Self {
0.25
}
fn infinity() -> Self {
f64::INFINITY
}
fn tsqrt(self) -> Self {
Math::sqrt_f64(self)
}
fn tsin(self) -> Self {
Math::sin_f64(self)
}
fn tcos(self) -> Self {
Math::cos_f64(self)
}
fn ttan(self) -> Self {
Math::tan_f64(self)
}
fn tacos(self) -> Self {
Math::acos_f64(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn test() {
let out = -1.0;
let f = out.tabs();
assert_eq!(f, 1.0);
}
#[test]
fn test_float_scalar_ops_f32() {
let v = 4.0f32;
assert!((v.tsqrt() - 2.0).abs() < 0.0001);
assert!(0.0f32.tsin().abs() < 0.0001);
assert!((0.0f32.tcos() - 1.0).abs() < 0.0001);
assert!(0.0f32.ttan().abs() < 0.0001);
assert!(1.0f32.tacos().abs() < 0.0001);
}
#[test]
fn test_float_scalar_ops_f64() {
let v = 4.0f64;
assert!((v.tsqrt() - 2.0).abs() < 0.0000001);
assert!(0.0f64.tsin().abs() < 0.0000001);
assert!((0.0f64.tcos() - 1.0).abs() < 0.0000001);
assert!(0.0f64.ttan().abs() < 0.0000001);
assert!(1.0f64.tacos().abs() < 0.0000001);
}
}