#approximate #assert #comparison #equality #float

approx

Approximate floating point equality comparisons and assertions

8 releases

0.3.2 Mar 17, 2019
0.3.1 Dec 13, 2018
0.3.0 Jul 16, 2018
0.2.1 Jul 16, 2018
0.0.1 Nov 15, 2015

#7 in Testing

Download history 9754/week @ 2019-01-21 10258/week @ 2019-01-28 9048/week @ 2019-02-04 10045/week @ 2019-02-11 9932/week @ 2019-02-18 9263/week @ 2019-02-25 8716/week @ 2019-03-04 10042/week @ 2019-03-11 11003/week @ 2019-03-18 10261/week @ 2019-03-25 11208/week @ 2019-04-01 12631/week @ 2019-04-08 13004/week @ 2019-04-15 12881/week @ 2019-04-22 38308/week @ 2019-04-29

41,742 downloads per month
Used in 822 crates (115 directly)

Apache-2.0

36KB
681 lines

approx

Build Status Version Documentation Downloads License

Approximate floating point equality comparisons and assertions for the Rust Programming Language.


lib.rs:

A crate that provides facilities for testing the approximate equality of floating-point based types, using either relative difference, or units in the last place (ULPs) comparisons.

You can also use the approx_{eq, ne}! assert_approx_{eq, ne}! macros to test for equality using a more positional style.

#[macro_use]
extern crate approx;

use std::f64;

# fn main() {
abs_diff_eq!(1.0, 1.0);
abs_diff_eq!(1.0, 1.0, epsilon = f64::EPSILON);

relative_eq!(1.0, 1.0);
relative_eq!(1.0, 1.0, epsilon = f64::EPSILON);
relative_eq!(1.0, 1.0, max_relative = 1.0);
relative_eq!(1.0, 1.0, epsilon = f64::EPSILON, max_relative = 1.0);
relative_eq!(1.0, 1.0, max_relative = 1.0, epsilon = f64::EPSILON);

ulps_eq!(1.0, 1.0);
ulps_eq!(1.0, 1.0, epsilon = f64::EPSILON);
ulps_eq!(1.0, 1.0, max_ulps = 4);
ulps_eq!(1.0, 1.0, epsilon = f64::EPSILON, max_ulps = 4);
ulps_eq!(1.0, 1.0, max_ulps = 4, epsilon = f64::EPSILON);
# }

Implementing approximate equality for custom types

The ApproxEq trait allows approximate equalities to be implemented on types, based on the fundamental floating point implementations.

For example, we might want to be able to do approximate assertions on a complex number type:

#[macro_use]
extern crate approx;
# use approx::{AbsDiffEq, RelativeEq, UlpsEq};

#[derive(Debug, PartialEq)]
struct Complex<T> {
    x: T,
    i: T,
}
# impl<T: AbsDiffEq> AbsDiffEq for Complex<T> where T::Epsilon: Copy {
#     type Epsilon = T::Epsilon;
#     fn default_epsilon() -> T::Epsilon { T::default_epsilon() }
#     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)
#     }
# }
# impl<T: RelativeEq> RelativeEq for Complex<T> where T::Epsilon: Copy {
#     fn default_max_relative() -> T::Epsilon { T::default_max_relative() }
#     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)
#     }
# }
# impl<T: UlpsEq> UlpsEq for Complex<T> where T::Epsilon: Copy {
#     fn default_max_ulps() -> u32 { T::default_max_ulps() }
#     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)
#     }
# }

# fn main() {
let x = Complex { x: 1.2, i: 2.3 };

assert_relative_eq!(x, x);
assert_ulps_eq!(x, x, max_ulps = 4);
# }

To do this we can implement AbsDiffEq, RelativeEq and UlpsEq generically in terms of a type parameter that also implements ApproxEq, RelativeEq and UlpsEq respectively. This means that we can make comparisons for either Complex<f32> or Complex<f64>:

# use approx::{AbsDiffEq, RelativeEq, UlpsEq};
# #[derive(Debug, PartialEq)]
# struct Complex<T> { x: T, i: T, }
#
impl<T: AbsDiffEq> AbsDiffEq for Complex<T> where
    T::Epsilon: Copy,
{
    type Epsilon = T::Epsilon;

    fn default_epsilon() -> T::Epsilon {
        T::default_epsilon()
    }

    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)
    }
}

impl<T: RelativeEq> RelativeEq for Complex<T> where
    T::Epsilon: Copy,
{
    fn default_max_relative() -> T::Epsilon {
        T::default_max_relative()
    }

    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)
    }
}

impl<T: UlpsEq> UlpsEq for Complex<T> where
    T::Epsilon: Copy,
{
    fn default_max_ulps() -> u32 {
        T::default_max_ulps()
    }

    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)
    }
}

References

Floating point is hard! Thanks goes to these links for helping to make things a little easier to understand:

Dependencies

~136KB