approx 0.1.1

Approximate floating point equality comparisons and assertions.

Crate approx [] [src]

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;

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;
#[derive(Debug)]
struct Complex<T> {
    x: T,
    i: T,
}

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 ApproxEq generically in terms of a type parameter that also implements ApproxEq. This means that we can make comparisons for either Complex<f32> or Complex<f64>:

impl<T: ApproxEq> ApproxEq for Complex<T> where
    T::Epsilon: Copy,
{
    type Epsilon = T::Epsilon;

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

References

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

Macros

assert_relative_eq!
assert_relative_ne!
assert_ulps_eq!
assert_ulps_ne!
relative_eq!

Predicate for testing the approximate equality of two values.

relative_ne!

Predicate for testing the approximate inequality of two values.

ulps_eq!

Predicate for testing the approximate equality of two values using a maximum ULPs (Units in Last Place).

ulps_ne!

Predicate for testing the approximate inequality of two values using a maximum ULPs (Units in Last Place).

Structs

Relative

The requisite parameters for testing for approximate equality.

Ulps

The requisite parameters for testing for approximate equality.

Traits

ApproxEq

Equality comparisons based on floating point tolerances.