use crate::helpers::*;
pub trait NumEq: PartialEq {
type Eps;
fn num_eq(&self, other: &Self, _eps: &Self::Eps) -> bool {
self == other
}
fn num_ne(&self, other: &Self, eps: &Self::Eps) -> bool {
!self.num_eq(other, eps)
}
}
macro_rules! float_num_eq {
($type:ty, $min:expr) => {
impl NumEq for $type {
type Eps = Self;
fn num_eq(&self, other: &Self, eps: &$type) -> bool {
let delta = (*self - *other).abs();
if self == other {
return true
};
if *self == 0.0 || *other == 0.0 {
return delta < *eps
}
if self.abs() + other.abs() <= $min {
return delta < *eps
}
delta / (self.abs() + other.abs()) < *eps
}
fn num_ne(&self, other: &Self, eps: &$type) -> bool {
!self.num_eq(other, eps)
}
}
};
}
float_num_eq! {f32, std::f32::MIN_POSITIVE}
float_num_eq! {f64, std::f64::MIN_POSITIVE}
macro_rules! tuple_num_equal {
($tuple:ty) => {
impl<T: NumEq> NumEq for $tuple {
type Eps = T::Eps;
fn num_eq(&self, other: &Self, eps: &Self::Eps) -> bool {
self.all_with(other, &|x, y| x.num_eq(y, eps))
}
fn num_ne(&self, other: &Self, eps: &Self::Eps) -> bool {
self.any_with(other, &|x, y| x.num_ne(y, eps))
}
}
};
($tuple:ty, $($others:ty),+) => {
tuple_num_equal! {$tuple}
tuple_num_equal! {$($others),+}
};
}
tuple_num_equal! {(T, ), (T, T), (T, T, T), (T, T, T, T)}
macro_rules! array_num_eq {
($size:expr) => {
impl<T: NumEq + Copy> NumEq for [T; $size] {
type Eps = T::Eps;
fn num_eq(&self, other: &Self, eps: &Self::Eps) -> bool {
self.all_with(other, &|x, y| x.num_eq(y, eps))
}
fn num_ne(&self, other: &Self, eps: &Self::Eps) -> bool {
self.any_with(other, &|x, y| x.num_ne(y, eps))
}
}
};
($size:expr, $($others:expr),+) => {
array_num_eq! {$size}
array_num_eq! {$($others),+}
};
}
array_num_eq! {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
}