diff --git a/src/lib.rs b/src/lib.rs index b683ea4..c7ac9ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,6 +60,7 @@ //! # fn default_epsilon() -> T::Epsilon { T::default_epsilon() } //! # fn default_max_relative() -> T::Epsilon { T::default_max_relative() } //! # fn default_max_ulps() -> u32 { T::default_max_ulps() } +//! # fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool { T::abs_diff_eq(&self.x, &other.x, epsilon) && T::abs_diff_eq(&self.i, &other.i, epsilon) } //! # fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool { T::relative_eq(&self.x, &other.x, epsilon, max_relative) && T::relative_eq(&self.i, &other.i, epsilon, max_relative) } //! # fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool { T::ulps_eq(&self.x, &other.x, epsilon, max_ulps) && T::ulps_eq(&self.i, &other.i, epsilon, max_ulps) } //! # } @@ -98,6 +99,11 @@ //! T::default_max_ulps() //! } //! +//! fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool { +//! T::abs_diff_eq(&self.x, &other.x, epsilon) && +//! T::abs_diff_eq(&self.i, &other.i, epsilon) +//! } +//! //! fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool { //! T::relative_eq(&self.x, &other.x, epsilon, max_relative) && //! T::relative_eq(&self.i, &other.i, epsilon, max_relative) @@ -152,6 +158,13 @@ pub trait ApproxEq: Sized { /// This is used when no `max_relative` value is supplied to the `relative_eq` macro. fn default_max_ulps() -> u32; + /// A test for equality that uses the absolute difference to compute the approximate + /// equality of two numbers. + fn abs_diff_eq(&self, + other: &Self, + epsilon: Self::Epsilon) + -> bool; + /// A test for equality that uses a relative comparison if the values are far apart. fn relative_eq(&self, other: &Self, @@ -159,6 +172,17 @@ pub trait ApproxEq: Sized { max_relative: Self::Epsilon) -> bool; + /// A test for equality that uses units in the last place (ULP) if the values are far apart. + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool; + + /// The inverse of `ApproxEq::abs_diff_eq`. + fn abs_diff_ne(&self, + other: &Self, + epsilon: Self::Epsilon) + -> bool { + !Self::abs_diff_eq(self, other, epsilon) + } + /// The inverse of `ApproxEq::relative_eq`. fn relative_ne(&self, other: &Self, @@ -168,9 +192,6 @@ pub trait ApproxEq: Sized { !Self::relative_eq(self, other, epsilon, max_relative) } - /// A test for equality that uses units in the last place (ULP) if the values are far apart. - fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool; - /// The inverse of `ApproxEq::ulps_eq`. fn ulps_ne(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { !Self::ulps_eq(self, other, epsilon, max_ulps) @@ -191,6 +212,11 @@ macro_rules! impl_float_approx_eq { #[inline] fn default_max_ulps() -> u32 { 4 } + #[inline] + fn abs_diff_eq(&self, other: &$T, epsilon: $T) -> bool { + $T::abs(self - other) <= epsilon + } + #[inline] fn relative_eq(&self, other: &$T, epsilon: $T, max_relative: $T) -> bool { // Implementation based on: [Comparing Floating Point Numbers, 2012 Edition] @@ -227,10 +253,8 @@ macro_rules! impl_float_approx_eq { // Implementation based on: [Comparing Floating Point Numbers, 2012 Edition] // (https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/) - let abs_diff = $T::abs(self - other); - // For when the numbers are really close together - if abs_diff <= epsilon { + if $T::abs_diff_eq(self, other, epsilon) { return true; } @@ -271,6 +295,11 @@ impl<'a, T: ApproxEq> ApproxEq for &'a T { T::default_max_ulps() } + #[inline] + fn abs_diff_eq(&self, other: &&'a T, epsilon: T::Epsilon) -> bool { + T::abs_diff_eq(*self, *other, epsilon) + } + #[inline] fn relative_eq(&self, other: &&'a T, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool { T::relative_eq(*self, *other, epsilon, max_relative) @@ -300,6 +329,11 @@ impl<'a, T: ApproxEq> ApproxEq for &'a mut T { T::default_max_ulps() } + #[inline] + fn abs_diff_eq(&self, other: &&'a mut T, epsilon: T::Epsilon) -> bool { + T::abs_diff_eq(*self, *other, epsilon) + } + #[inline] fn relative_eq(&self, other: &&'a mut T, @@ -315,6 +349,62 @@ impl<'a, T: ApproxEq> ApproxEq for &'a mut T { } } +/// The requisite parameters for testing for approximate equality using a +/// absolute difference based comparison. +/// +/// This is not normally used directly, rather via the +/// `assert_abs_diff_{eq|ne}!` and `abs_diff_{eq|ne}!` macros. +/// +/// # Example +/// +/// ```rust +/// use std::f64; +/// use approx::AbsDiff; +/// +/// AbsDiff::default().eq(&1.0, &1.0); +/// AbsDiff::default().epsilon(f64::EPSILON).eq(&1.0, &1.0); +/// ``` +pub struct AbsDiff { + /// The tolerance to use when testing values that are close together. + pub epsilon: T::Epsilon, +} + +impl Default for AbsDiff + where T: ApproxEq +{ + #[inline] + fn default() -> AbsDiff { + AbsDiff { + epsilon: T::default_epsilon(), + } + } +} + +impl AbsDiff + where T: ApproxEq +{ + /// Replace the epsilon value with the one specified. + #[inline] + pub fn epsilon(self, epsilon: T::Epsilon) -> AbsDiff { + AbsDiff { + epsilon: epsilon, + ..self + } + } + + /// Peform the equality comparison + #[inline] + pub fn eq(self, lhs: &T, rhs: &T) -> bool { + T::abs_diff_eq(lhs, rhs, self.epsilon) + } + + /// Peform the inequality comparison + #[inline] + pub fn ne(self, lhs: &T, rhs: &T) -> bool { + T::abs_diff_ne(lhs, rhs, self.epsilon) + } +} + /// The requisite parameters for testing for approximate equality using a /// relative based comparison. /// diff --git a/src/macros.rs b/src/macros.rs index 46e349b..0d6b780 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -12,6 +12,111 @@ // See the License for the specific language governing permissions and // limitations under the License. +/// Predicate for testing the approximate equality of two values. +#[macro_export] +macro_rules! abs_diff_eq { + ($lhs:expr, $rhs:expr, $($opt:ident = $opt_val:expr),+) => {{ + $crate::AbsDiff::default()$(.$opt($opt_val))+.eq(&$lhs, &$rhs) + }}; + ($lhs:expr, $rhs:expr) => {{ + $crate::AbsDiff::default().eq(&$lhs, &$rhs) + }}; +} + +/// Predicate for testing the approximate inequality of two values. +#[macro_export] +macro_rules! abs_diff_ne { + ($lhs:expr, $rhs:expr, $($opt:ident = $opt_val:expr),+) => {{ + $crate::AbsDiff::default()$(.$opt($opt_val))+.ne(&$lhs, &$rhs) + }}; + ($lhs:expr, $rhs:expr) => {{ + $crate::AbsDiff::default().ne(&$lhs, &$rhs) + }}; +} + +#[macro_export] +macro_rules! assert_abs_diff_eq { + ($given:expr, $expected:expr) => {{ + let (given, expected) = (&($given), &($expected)); + + if !abs_diff_eq!(given, expected) { + panic!( +"assert_abs_diff_eq!({}, {}) + + left = {:?} + right = {:?} + +", + stringify!($given), stringify!($expected), + given, expected, + ); + } + }}; + ($given:expr, $expected:expr, $($opt:ident = $opt_val:expr),+) => {{ + let (given, expected) = (&($given), &($expected)); + + if !abs_diff_eq!(given, expected, $($opt = $opt_val),+) { + panic!( +"assert_abs_diff_eq!({}, {}, {}) + + left = {:?} + right = {:?} + +", + stringify!($given), stringify!($expected), + stringify!($($opt = $opt_val),+), + given, expected, + ); + } + }}; + ($given:expr, $expected:expr,) => { + assert_abs_diff_eq!($given, $expected) + }; + ($given:expr, $expected:expr, $($opt:ident = $opt_val:expr,)+) => { + assert_abs_diff_eq!($given, $expected, $($opt = $opt_val),+) + }; +} + +#[macro_export] +macro_rules! assert_abs_diff_ne { + ($given:expr, $expected:expr) => {{ + let (given, expected) = (&($given), &($expected)); + + if !abs_diff_ne!(given, expected) { + panic!( +"assert_abs_diff_ne!({}, {}) + + left = {:?} + right = {:?} + +", + stringify!($given), stringify!($expected), + given, expected, + ); + } + }}; + ($given:expr, $expected:expr, $($opt:ident = $opt_val:expr),+) => {{ + let (given, expected) = (&($given), &($expected)); + + if !abs_diff_ne!(given, expected, $($opt = $opt_val),+) { + panic!( +"assert_abs_diff_ne!({}, {}, {}) + + left = {:?} + right = {:?} + +", + stringify!($given), stringify!($expected), + stringify!($($opt = $opt_val),+), + given, expected, + ); + } + }}; + ($given:expr, $expected:expr,) => { + assert_abs_diff_ne!($given, $expected) + }; +} + /// Predicate for testing the approximate equality of two values. #[macro_export] macro_rules! relative_eq { @@ -224,3 +329,4 @@ macro_rules! assert_ulps_ne { assert_ulps_ne!($given, $expected) }; } + diff --git a/tests/abs_diff_eq.rs b/tests/abs_diff_eq.rs new file mode 100644 index 0000000..45c810d --- /dev/null +++ b/tests/abs_diff_eq.rs @@ -0,0 +1,320 @@ +// Copyright 2015 Brendan Zabarauskas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Test cases derived from https://github.com/Pybonacci/puntoflotante.org/blob/master/content/errors/NearlyEqualsTest.java + +#[macro_use] +extern crate approx; + +mod test_f32 { + use std::f32; + + #[test] + fn test_big() { + assert_abs_diff_eq!(100000000.0f32, 100000001.0f32); + assert_abs_diff_eq!(100000001.0f32, 100000000.0f32); + assert_abs_diff_ne!(10000.0f32, 10001.0f32); + assert_abs_diff_ne!(10001.0f32, 10000.0f32); + } + + #[test] + fn test_big_neg() { + assert_abs_diff_eq!(-100000000.0f32, -100000001.0f32); + assert_abs_diff_eq!(-100000001.0f32, -100000000.0f32); + assert_abs_diff_ne!(-10000.0f32, -10001.0f32); + assert_abs_diff_ne!(-10001.0f32, -10000.0f32); + } + + #[test] + fn test_mid() { + assert_abs_diff_eq!(1.0000001f32, 1.0000002f32); + assert_abs_diff_eq!(1.0000002f32, 1.0000001f32); + assert_abs_diff_ne!(1.000001f32, 1.000002f32); + assert_abs_diff_ne!(1.000002f32, 1.000001f32); + } + + #[test] + fn test_mid_neg() { + assert_abs_diff_eq!(-1.0000001f32, -1.0000002f32); + assert_abs_diff_eq!(-1.0000002f32, -1.0000001f32); + assert_abs_diff_ne!(-1.000001f32, -1.000002f32); + assert_abs_diff_ne!(-1.000002f32, -1.000001f32); + } + + #[test] + fn test_small() { + assert_abs_diff_eq!(0.000010001f32, 0.000010002f32); + assert_abs_diff_eq!(0.000010002f32, 0.000010001f32); + assert_abs_diff_ne!(0.000001002f32, 0.0000001001f32); + assert_abs_diff_ne!(0.000001001f32, 0.0000001002f32); + } + + #[test] + fn test_small_neg() { + assert_abs_diff_eq!(-0.000010001f32, -0.000010002f32); + assert_abs_diff_eq!(-0.000010002f32, -0.000010001f32); + assert_abs_diff_ne!(-0.000001002f32, -0.0000001001f32); + assert_abs_diff_ne!(-0.000001001f32, -0.0000001002f32); + } + + #[test] + fn test_zero() { + assert_abs_diff_eq!(0.0f32, 0.0f32); + assert_abs_diff_eq!(0.0f32, -0.0f32); + assert_abs_diff_eq!(-0.0f32, -0.0f32); + + assert_abs_diff_ne!(0.000001f32, 0.0f32); + assert_abs_diff_ne!(0.0f32, 0.000001f32); + assert_abs_diff_ne!(-0.000001f32, 0.0f32); + assert_abs_diff_ne!(0.0f32, -0.000001f32); + } + + #[test] + fn test_epsilon() { + assert_abs_diff_eq!(0.0f32, 1e-40f32, epsilon = 1e-40f32); + assert_abs_diff_eq!(1e-40f32, 0.0f32, epsilon = 1e-40f32); + assert_abs_diff_eq!(0.0f32, -1e-40f32, epsilon = 1e-40f32); + assert_abs_diff_eq!(-1e-40f32, 0.0f32, epsilon = 1e-40f32); + + assert_abs_diff_ne!(1e-40f32, 0.0f32, epsilon = 1e-41f32); + assert_abs_diff_ne!(0.0f32, 1e-40f32, epsilon = 1e-41f32); + assert_abs_diff_ne!(-1e-40f32, 0.0f32, epsilon = 1e-41f32); + assert_abs_diff_ne!(0.0f32, -1e-40f32, epsilon = 1e-41f32); + } + + #[test] + fn test_max() { + assert_abs_diff_eq!(f32::MAX, f32::MAX); + assert_abs_diff_ne!(f32::MAX, -f32::MAX); + assert_abs_diff_ne!(-f32::MAX, f32::MAX); + assert_abs_diff_ne!(f32::MAX, f32::MAX / 2.0); + assert_abs_diff_ne!(f32::MAX, -f32::MAX / 2.0); + assert_abs_diff_ne!(-f32::MAX, f32::MAX / 2.0); + } + + // NOTE: abs_diff_eq fails as numbers begin to get very large + + // #[test] + // fn test_infinity() { + // assert_abs_diff_eq!(f32::INFINITY, f32::INFINITY); + // assert_abs_diff_eq!(f32::NEG_INFINITY, f32::NEG_INFINITY); + // assert_abs_diff_ne!(f32::NEG_INFINITY, f32::INFINITY); + // assert_abs_diff_eq!(f32::INFINITY, f32::MAX); + // assert_abs_diff_eq!(f32::NEG_INFINITY, -f32::MAX); + // } + + #[test] + fn test_nan() { + assert_abs_diff_ne!(f32::NAN, f32::NAN); + + assert_abs_diff_ne!(f32::NAN, 0.0); + assert_abs_diff_ne!(-0.0, f32::NAN); + assert_abs_diff_ne!(f32::NAN, -0.0); + assert_abs_diff_ne!(0.0, f32::NAN); + + assert_abs_diff_ne!(f32::NAN, f32::INFINITY); + assert_abs_diff_ne!(f32::INFINITY, f32::NAN); + assert_abs_diff_ne!(f32::NAN, f32::NEG_INFINITY); + assert_abs_diff_ne!(f32::NEG_INFINITY, f32::NAN); + + assert_abs_diff_ne!(f32::NAN, f32::MAX); + assert_abs_diff_ne!(f32::MAX, f32::NAN); + assert_abs_diff_ne!(f32::NAN, -f32::MAX); + assert_abs_diff_ne!(-f32::MAX, f32::NAN); + + assert_abs_diff_ne!(f32::NAN, f32::MIN_POSITIVE); + assert_abs_diff_ne!(f32::MIN_POSITIVE, f32::NAN); + assert_abs_diff_ne!(f32::NAN, -f32::MIN_POSITIVE); + assert_abs_diff_ne!(-f32::MIN_POSITIVE, f32::NAN); + } + + #[test] + fn test_opposite_signs() { + assert_abs_diff_ne!(1.000000001f32, -1.0f32); + assert_abs_diff_ne!(-1.0f32, 1.000000001f32); + assert_abs_diff_ne!(-1.000000001f32, 1.0f32); + assert_abs_diff_ne!(1.0f32, -1.000000001f32); + + assert_abs_diff_eq!(10.0 * f32::MIN_POSITIVE, 10.0 * -f32::MIN_POSITIVE); + } + + #[test] + fn test_close_to_zero() { + assert_abs_diff_eq!(f32::MIN_POSITIVE, f32::MIN_POSITIVE); + assert_abs_diff_eq!(f32::MIN_POSITIVE, -f32::MIN_POSITIVE); + assert_abs_diff_eq!(-f32::MIN_POSITIVE, f32::MIN_POSITIVE); + + assert_abs_diff_eq!(f32::MIN_POSITIVE, 0.0f32); + assert_abs_diff_eq!(0.0f32, f32::MIN_POSITIVE); + assert_abs_diff_eq!(-f32::MIN_POSITIVE, 0.0f32); + assert_abs_diff_eq!(0.0f32, -f32::MIN_POSITIVE); + + assert_abs_diff_ne!(0.000001f32, -f32::MIN_POSITIVE); + assert_abs_diff_ne!(0.000001f32, f32::MIN_POSITIVE); + assert_abs_diff_ne!(f32::MIN_POSITIVE, 0.000001f32); + assert_abs_diff_ne!(-f32::MIN_POSITIVE, 0.000001f32); + } +} + +#[cfg(test)] +mod test_f64 { + use std::f64; + + #[test] + fn test_big() { + assert_abs_diff_eq!(10000000000000000.0f64, 10000000000000001.0f64); + assert_abs_diff_eq!(10000000000000001.0f64, 10000000000000000.0f64); + assert_abs_diff_ne!(1000000000000000.0f64, 1000000000000001.0f64); + assert_abs_diff_ne!(1000000000000001.0f64, 1000000000000000.0f64); + } + + #[test] + fn test_big_neg() { + assert_abs_diff_eq!(-10000000000000000.0f64, -10000000000000001.0f64); + assert_abs_diff_eq!(-10000000000000001.0f64, -10000000000000000.0f64); + assert_abs_diff_ne!(-1000000000000000.0f64, -1000000000000001.0f64); + assert_abs_diff_ne!(-1000000000000001.0f64, -1000000000000000.0f64); + } + + #[test] + fn test_mid() { + assert_abs_diff_eq!(1.0000000000000001f64, 1.0000000000000002f64); + assert_abs_diff_eq!(1.0000000000000002f64, 1.0000000000000001f64); + assert_abs_diff_ne!(1.000000000000001f64, 1.000000000000002f64); + assert_abs_diff_ne!(1.000000000000002f64, 1.000000000000001f64); + } + + #[test] + fn test_mid_neg() { + assert_abs_diff_eq!(-1.0000000000000001f64, -1.0000000000000002f64); + assert_abs_diff_eq!(-1.0000000000000002f64, -1.0000000000000001f64); + assert_abs_diff_ne!(-1.000000000000001f64, -1.000000000000002f64); + assert_abs_diff_ne!(-1.000000000000002f64, -1.000000000000001f64); + } + + #[test] + fn test_small() { + assert_abs_diff_eq!(0.0000000100000001f64, 0.0000000100000002f64); + assert_abs_diff_eq!(0.0000000100000002f64, 0.0000000100000001f64); + assert_abs_diff_ne!(0.0000000100000001f64, 0.0000000010000002f64); + assert_abs_diff_ne!(0.0000000100000002f64, 0.0000000010000001f64); + } + + #[test] + fn test_small_neg() { + assert_abs_diff_eq!(-0.0000000100000001f64, -0.0000000100000002f64); + assert_abs_diff_eq!(-0.0000000100000002f64, -0.0000000100000001f64); + assert_abs_diff_ne!(-0.0000000100000001f64, -0.0000000010000002f64); + assert_abs_diff_ne!(-0.0000000100000002f64, -0.0000000010000001f64); + } + + #[test] + fn test_zero() { + assert_abs_diff_eq!(0.0f64, 0.0f64); + assert_abs_diff_eq!(0.0f64, -0.0f64); + assert_abs_diff_eq!(-0.0f64, -0.0f64); + + assert_abs_diff_ne!(0.000000000000001f64, 0.0f64); + assert_abs_diff_ne!(0.0f64, 0.000000000000001f64); + assert_abs_diff_ne!(-0.000000000000001f64, 0.0f64); + assert_abs_diff_ne!(0.0f64, -0.000000000000001f64); + } + + #[test] + fn test_epsilon() { + assert_abs_diff_eq!(0.0f64, 1e-40f64, epsilon = 1e-40f64); + assert_abs_diff_eq!(1e-40f64, 0.0f64, epsilon = 1e-40f64); + assert_abs_diff_eq!(0.0f64, -1e-40f64, epsilon = 1e-40f64); + assert_abs_diff_eq!(-1e-40f64, 0.0f64, epsilon = 1e-40f64); + + assert_abs_diff_ne!(1e-40f64, 0.0f64, epsilon = 1e-41f64); + assert_abs_diff_ne!(0.0f64, 1e-40f64, epsilon = 1e-41f64); + assert_abs_diff_ne!(-1e-40f64, 0.0f64, epsilon = 1e-41f64); + assert_abs_diff_ne!(0.0f64, -1e-40f64, epsilon = 1e-41f64); + } + + + #[test] + fn test_max() { + assert_abs_diff_eq!(f64::MAX, f64::MAX); + assert_abs_diff_ne!(f64::MAX, -f64::MAX); + assert_abs_diff_ne!(-f64::MAX, f64::MAX); + assert_abs_diff_ne!(f64::MAX, f64::MAX / 2.0); + assert_abs_diff_ne!(f64::MAX, -f64::MAX / 2.0); + assert_abs_diff_ne!(-f64::MAX, f64::MAX / 2.0); + } + + // NOTE: abs_diff_eq fails as numbers begin to get very large + + // #[test] + // fn test_infinity() { + // assert_abs_diff_eq!(f64::INFINITY, f64::INFINITY); + // assert_abs_diff_eq!(f64::NEG_INFINITY, f64::NEG_INFINITY); + // assert_abs_diff_ne!(f64::NEG_INFINITY, f64::INFINITY); + // assert_abs_diff_eq!(f64::INFINITY, f64::MAX); + // assert_abs_diff_eq!(f64::NEG_INFINITY, -f64::MAX); + // } + + #[test] + fn test_nan() { + assert_abs_diff_ne!(f64::NAN, f64::NAN); + + assert_abs_diff_ne!(f64::NAN, 0.0); + assert_abs_diff_ne!(-0.0, f64::NAN); + assert_abs_diff_ne!(f64::NAN, -0.0); + assert_abs_diff_ne!(0.0, f64::NAN); + + assert_abs_diff_ne!(f64::NAN, f64::INFINITY); + assert_abs_diff_ne!(f64::INFINITY, f64::NAN); + assert_abs_diff_ne!(f64::NAN, f64::NEG_INFINITY); + assert_abs_diff_ne!(f64::NEG_INFINITY, f64::NAN); + + assert_abs_diff_ne!(f64::NAN, f64::MAX); + assert_abs_diff_ne!(f64::MAX, f64::NAN); + assert_abs_diff_ne!(f64::NAN, -f64::MAX); + assert_abs_diff_ne!(-f64::MAX, f64::NAN); + + assert_abs_diff_ne!(f64::NAN, f64::MIN_POSITIVE); + assert_abs_diff_ne!(f64::MIN_POSITIVE, f64::NAN); + assert_abs_diff_ne!(f64::NAN, -f64::MIN_POSITIVE); + assert_abs_diff_ne!(-f64::MIN_POSITIVE, f64::NAN); + } + + #[test] + fn test_opposite_signs() { + assert_abs_diff_ne!(1.000000001f64, -1.0f64); + assert_abs_diff_ne!(-1.0f64, 1.000000001f64); + assert_abs_diff_ne!(-1.000000001f64, 1.0f64); + assert_abs_diff_ne!(1.0f64, -1.000000001f64); + + assert_abs_diff_eq!(10.0 * f64::MIN_POSITIVE, 10.0 * -f64::MIN_POSITIVE); + } + + #[test] + fn test_close_to_zero() { + assert_abs_diff_eq!(f64::MIN_POSITIVE, f64::MIN_POSITIVE); + assert_abs_diff_eq!(f64::MIN_POSITIVE, -f64::MIN_POSITIVE); + assert_abs_diff_eq!(-f64::MIN_POSITIVE, f64::MIN_POSITIVE); + + assert_abs_diff_eq!(f64::MIN_POSITIVE, 0.0f64); + assert_abs_diff_eq!(0.0f64, f64::MIN_POSITIVE); + assert_abs_diff_eq!(-f64::MIN_POSITIVE, 0.0f64); + assert_abs_diff_eq!(0.0f64, -f64::MIN_POSITIVE); + + assert_abs_diff_ne!(0.000000000000001f64, -f64::MIN_POSITIVE); + assert_abs_diff_ne!(0.000000000000001f64, f64::MIN_POSITIVE); + assert_abs_diff_ne!(f64::MIN_POSITIVE, 0.000000000000001f64); + assert_abs_diff_ne!(-f64::MIN_POSITIVE, 0.000000000000001f64); + } +} diff --git a/tests/macros.rs b/tests/macros.rs index e8641cf..b9e1910 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -17,6 +17,18 @@ #[macro_use] extern crate approx; +#[test] +fn test_abs_diff_eq() { + let _: bool = abs_diff_eq!(1.0, 1.0); + let _: bool = abs_diff_eq!(1.0, 1.0, epsilon = 1.0); +} + +#[test] +fn test_abs_diff_ne() { + let _: bool = abs_diff_ne!(1.0, 1.0); + let _: bool = abs_diff_ne!(1.0, 1.0, epsilon = 1.0); +} + #[test] fn test_relative_eq() { let _: bool = relative_eq!(1.0, 1.0);