use crate::{Matrix, Quaternion};
use num::{traits::{float::FloatCore, NumAssign, NumCast}, Zero};
pub const EPSILON: f32 = 128. * f32::EPSILON;
pub fn epsilon<T: NumCast + Zero>() -> T {
NumCast::from(EPSILON).unwrap_or(T::zero())
}
pub trait FloatOps: Copy {
fn acos(self) -> Self;
fn cos(self) -> Self;
fn sin(self) -> Self;
fn sqrt(self) -> Self;
fn tan(self) -> Self;
}
#[cfg(all(any(feature = "std", feature = "libm"), not(all(target_arch = "wasm32", feature = "jsmath"))))]
impl<T: num::traits::Float> FloatOps for T {
#[inline]
fn acos(self) -> T {
T::acos(self)
}
#[inline]
fn cos(self) -> T {
T::cos(self)
}
#[inline]
fn sin(self) -> T {
T::sin(self)
}
#[inline]
fn sqrt(self) -> T {
T::sqrt(self)
}
#[inline]
fn tan(self) -> T {
T::tan(self)
}
}
pub trait FloatEq<T: Copy> {
fn float_eq(&self, rhs: Self, epsilon: T) -> bool;
}
impl FloatEq<f32> for f32 {
fn float_eq(&self, rhs: Self, epsilon: f32) -> bool {
FloatCore::abs(*self - rhs) < epsilon
}
}
impl FloatEq<f64> for f64 {
fn float_eq(&self, rhs: Self, epsilon: f64) -> bool {
FloatCore::abs(*self - rhs) < epsilon
}
}
impl<T: Copy, V: Copy + FloatEq<T>> FloatEq<T> for &[V] {
fn float_eq(&self, rhs: Self, epsilon: T) -> bool {
if self.len() != rhs.len() {
return false;
}
for i in 0..self.len() {
if !self[i].float_eq(rhs[i], epsilon) {
return false;
}
}
true
}
}
impl<T: Copy + FloatEq<T> + NumAssign, const R: usize, const C: usize> FloatEq<T>
for Matrix<T, R, C>
{
#[inline]
fn float_eq(&self, rhs: Self, epsilon: T) -> bool {
self.as_ref().float_eq(rhs.as_ref(), epsilon)
}
}
impl<T: Copy + FloatEq<T> + NumAssign> FloatEq<T> for Quaternion<T> {
#[inline]
fn float_eq(&self, rhs: Self, epsilon: T) -> bool {
self.as_ref().float_eq(rhs.as_ref(), epsilon)
}
}
#[macro_export]
macro_rules! assert_float_eq {
($left:expr, $right:expr) => {
assert_float_eq!(($left), ($right), $crate::float::epsilon())
};
($left:expr, $right:expr, $epsilon:expr) => {
match (&($left), &($right), ($epsilon)) {
(left_val, right_val, epsilon_val) => {
if !$crate::FloatEq::float_eq(left_val, *right_val, epsilon_val) {
panic!(
"assertion failed: `left.float_eq(right, epsilon)` \
(left: `{:?}`, right: `{:?}`, epsilon: `{:?}`)",
*left_val, *right_val, epsilon_val
);
}
}
}
};
}