pub mod macro_support;
mod macros;
pub trait ApproxEq: Sized {
type Epsilon: Copy;
fn default_epsilon() -> Self::Epsilon;
fn default_max_relative() -> Self::Epsilon;
fn default_max_ulps() -> u32;
fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool;
fn relative_ne(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
!Self::relative_eq(self, other, epsilon, max_relative)
}
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool;
fn ulps_ne(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
!Self::ulps_eq(self, other, epsilon, max_ulps)
}
}
macro_rules! impl_float_relative_eq {
($T:ident, $U:ident) => {
impl ApproxEq for $T {
type Epsilon = $T;
#[inline]
fn default_epsilon() -> $T { std::$T::EPSILON }
#[inline]
fn default_max_relative() -> $T { std::$T::EPSILON }
#[inline]
fn default_max_ulps() -> u32 { 4 }
fn relative_eq(&self, other: &$T, epsilon: $T, max_relative: $T) -> bool {
if self == other { return true; }
let abs_diff = $T::abs(self - other);
if abs_diff <= epsilon { return true };
let abs_self = $T::abs(*self);
let abs_other = $T::abs(*other);
let largest = if abs_other > abs_self { abs_other } else { abs_self };
abs_diff <= largest * max_relative
}
fn ulps_eq(&self, other: &$T, epsilon: $T, max_ulps: u32) -> bool {
if $T::abs(self - other) <= epsilon { return true }
if self.signum() != other.signum() {
return self == other;
}
let int_self: $U = unsafe { std::mem::transmute(*self) };
let int_other: $U = unsafe { std::mem::transmute(*other) };
$U::abs(int_self - int_other) < max_ulps as $U
}
}
}
}
impl_float_relative_eq!(f32, i32);
impl_float_relative_eq!(f64, i64);
impl<'a, T: ApproxEq> ApproxEq for &'a T {
type Epsilon = T::Epsilon;
#[inline]
fn default_epsilon() -> Self::Epsilon {
T::default_epsilon()
}
#[inline]
fn default_max_relative() -> Self::Epsilon {
T::default_max_relative()
}
#[inline]
fn default_max_ulps() -> u32 {
T::default_max_ulps()
}
#[inline]
fn relative_eq(&self, other: &&'a T, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool {
T::relative_eq(*self, *other, epsilon, max_relative)
}
#[inline]
fn ulps_eq(&self, other: &&'a T, epsilon: T::Epsilon, max_ulps: u32) -> bool {
T::ulps_eq(*self, *other, epsilon, max_ulps)
}
}
impl<'a, T: ApproxEq> ApproxEq for &'a mut T {
type Epsilon = T::Epsilon;
#[inline]
fn default_epsilon() -> Self::Epsilon {
T::default_epsilon()
}
#[inline]
fn default_max_relative() -> Self::Epsilon {
T::default_max_relative()
}
#[inline]
fn default_max_ulps() -> u32 {
T::default_max_ulps()
}
#[inline]
fn relative_eq(&self, other: &&'a mut T, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool {
T::relative_eq(*self, *other, epsilon, max_relative)
}
#[inline]
fn ulps_eq(&self, other: &&'a mut T, epsilon: T::Epsilon, max_ulps: u32) -> bool {
T::ulps_eq(*self, *other, epsilon, max_ulps)
}
}