[][src]Trait float_eq::FloatEq

pub trait FloatEq<Rhs: ?Sized = Self> {
    type DiffEpsilon;
    type UlpsDiffEpsilon;
    fn eq_abs(&self, other: &Rhs, max_diff: &Self::DiffEpsilon) -> bool;
fn eq_rel(&self, other: &Rhs, max_diff: &Self::DiffEpsilon) -> bool;
fn eq_ulps(&self, other: &Rhs, max_diff: &Self::UlpsDiffEpsilon) -> bool; fn ne_abs(&self, other: &Rhs, max_diff: &Self::DiffEpsilon) -> bool { ... }
fn ne_rel(&self, other: &Rhs, max_diff: &Self::DiffEpsilon) -> bool { ... }
fn ne_ulps(&self, other: &Rhs, max_diff: &Self::UlpsDiffEpsilon) -> bool { ... } }

Algorithms to compare IEEE floating point values for equality.

This trait is used in the implementation of the float_eq! and assert_float_eq! families of macros. It may be called directly, but the macros usually provide a friendlier interface.

How can I implement FloatEq?

Implementing FloatEq on your types is straightfoward if they're already composed of compatible fields. You will need to choose the types of DiffEpsilon and UlpsDiffEpsilon that users will specify to provide bounds on their comparisons. For example, MyComplex32 uses the same types as a single f32 comparison does, and passes them through to each individual components' comparisons. This means that only a single number is needed to bound both real and imaginary parts in a check:

struct MyComplex32 {
    re: f32,
    im: f32,
}

impl FloatEq for MyComplex32 {
    type DiffEpsilon = <f32 as FloatEq>::DiffEpsilon;
    type UlpsDiffEpsilon = <f32 as FloatEq>::UlpsDiffEpsilon;

    fn eq_abs(&self, other: &Self, max_diff: &Self::DiffEpsilon) -> bool {
        self.re.eq_abs(&other.re, max_diff) && self.im.eq_abs(&other.im, max_diff)
    }

    fn eq_rel(&self, other: &Self, max_diff: &Self::DiffEpsilon) -> bool {
        self.re.eq_rel(&other.re, max_diff) && self.im.eq_rel(&other.im, max_diff)
    }

    fn eq_ulps(&self, other: &Self, max_diff: &Self::UlpsDiffEpsilon) -> bool {
        self.re.eq_ulps(&other.re, max_diff) && self.im.eq_ulps(&other.im, max_diff)
    }
}

let a = MyComplex32 { re: 1.0, im: 2.0000036, };
let b = MyComplex32 { re: 1.0000001, im: 2.0, };

assert!(float_eq!(a, b, abs <= 0.0000036));
assert!(float_ne!(a, b, abs <= 0.0000035));

assert!(float_eq!(a, b, rel <= 0.0000018));
assert!(float_ne!(a, b, rel <= 0.0000017));

assert!(float_eq!(a, b, ulps <= 15));
assert!(float_ne!(a, b, ulps <= 14));

If your type does not already have an underlying implementation of FloatEq, then you will need to take a close look at the descriptions of the algorithms on a method by method basis.

How can I compare two different types?

The type to be compared with is controlled by FloatEq's parameter. Following on from our previous example, if we wanted to treat f32 as a complex number with an imaginary component of 0.0:

struct MyComplex32 {
    re: f32,
    im: f32,
}

impl FloatEq<f32> for MyComplex32 {
    type DiffEpsilon = <f32 as FloatEq>::DiffEpsilon;
    type UlpsDiffEpsilon = <f32 as FloatEq>::UlpsDiffEpsilon;

    fn eq_abs(&self, other: &f32, max_diff: &Self::DiffEpsilon) -> bool {
        self.re.eq_abs(other, max_diff) && self.im.eq_abs(&0.0, max_diff)
    }

    fn eq_rel(&self, other: &f32, max_diff: &Self::DiffEpsilon) -> bool {
        self.re.eq_rel(other, max_diff) && self.im.eq_rel(&0.0, max_diff)
    }

    fn eq_ulps(&self, other: &f32, max_diff: &Self::UlpsDiffEpsilon) -> bool {
        self.re.eq_ulps(other, max_diff) && self.im.eq_ulps(&0.0, max_diff)
    }
}

impl FloatEq<MyComplex32> for f32 {
    type DiffEpsilon = <MyComplex32 as FloatEq<f32>>::DiffEpsilon;
    type UlpsDiffEpsilon = <MyComplex32 as FloatEq<f32>>::UlpsDiffEpsilon;

    fn eq_abs(&self, other: &MyComplex32, max_diff: &Self::DiffEpsilon) -> bool {
        other.eq_abs(self, max_diff)
    }

    fn eq_rel(&self, other: &MyComplex32, max_diff: &Self::DiffEpsilon) -> bool {
        other.eq_rel(self, max_diff)
    }

    fn eq_ulps(&self, other: &MyComplex32, max_diff: &Self::UlpsDiffEpsilon) -> bool {
        other.eq_ulps(self, max_diff)
    }
}

let a = 4.0_f32;
let b = MyComplex32 { re: 4.0000005, im: 0.0, };

assert!(float_eq!(a, b, abs <= 0.0000008));
assert!(float_ne!(a, b, abs <= 0.0000004));

assert!(float_eq!(a, b, rel <= 0.00000012));
assert!(float_ne!(a, b, rel <= 0.00000011));

assert!(float_eq!(a, b, ulps <= 1));
assert!(float_ne!(a, b, ulps <= 0));

Examples

assert!(4.0_f32.eq_abs(&4.0000015, &0.0000016));
assert!(4.0_f32.ne_abs(&4.0000015, &0.0000014));

assert!(4.0_f32.eq_rel(&4.0000015, &0.0000004));
assert!(4.0_f32.ne_rel(&4.0000015, &0.0000003));

assert!(4.0_f32.eq_ulps(&4.0000015, &3));
assert!(4.0_f32.ne_ulps(&4.0000015, &2));

Associated Types

type DiffEpsilon

Type of the maximum allowed difference between two values for them to be considered equal in terms of their native type.

This is the type of the max_diff parameter passed to abs and rel checks in methods and via the float_eq! macros.

type UlpsDiffEpsilon

Type of the maximum allowed difference between two values for them to be considered equal in terms of an ULPs comparison.

This is the type of the max_diff parameter passed to ulps checks in methods and via the float_eq! macros. This is usually an unsigned integer of the same width as the float value (e.g. f32 uses u32).

Loading content...

Required methods

fn eq_abs(&self, other: &Rhs, max_diff: &Self::DiffEpsilon) -> bool

Check whether self is equal to other, using an absolute epsilon comparison.

Implementations should be the equivalent of (using FloatDiff):

self.abs_diff(other) <= *max_diff

fn eq_rel(&self, other: &Rhs, max_diff: &Self::DiffEpsilon) -> bool

Check whether self is equal to other, using a relative epsilon comparison.

The implementation should be the equivalent of (using FloatDiff):

let largest = self.abs().max(other.abs());
let epsilon = largest * max_diff;
self.abs_diff(other) <= epsilon

fn eq_ulps(&self, other: &Rhs, max_diff: &Self::UlpsDiffEpsilon) -> bool

Check whether self is equal to other, using an ULPs comparison.

The implementation should be the equivalent of (using FloatDiff):

if self.is_sign_positive() != other.is_sign_positive() {
    self == other // account for zero == negative zero
} else {
    self.ulps_diff(other) <= *max_diff
}
Loading content...

Provided methods

fn ne_abs(&self, other: &Rhs, max_diff: &Self::DiffEpsilon) -> bool

Check whether self is not equal to other, using an absolute epsilon comparison.

Equal to !self.eq_abs(other, max_diff), there is no need to reimplement this for your own types.

fn ne_rel(&self, other: &Rhs, max_diff: &Self::DiffEpsilon) -> bool

Check whether self is not equal to other, using a relative epsilon comparison.

Equal to !self.eq_rel(other, max_diff), there is no need to reimplement this for your own types.

fn ne_ulps(&self, other: &Rhs, max_diff: &Self::UlpsDiffEpsilon) -> bool

Check whether self is not equal to other, using an ULPs comparison.

Equal to !self.eq_ulps(other, max_diff), there is no need to reimplement this for your own types.

Loading content...

Implementations on Foreign Types

impl<T: FloatEq> FloatEq<[T; 0]> for [T; 0][src]

This is also implemented on other arrays up to size 32 (inclusive).

type DiffEpsilon = T::DiffEpsilon

type UlpsDiffEpsilon = T::UlpsDiffEpsilon

impl FloatEq<f32> for f32[src]

type DiffEpsilon = f32

type UlpsDiffEpsilon = u32

impl FloatEq<f64> for f64[src]

type DiffEpsilon = f64

type UlpsDiffEpsilon = u64

Loading content...

Implementors

Loading content...