[][src]Trait float_eq::FloatEq

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

Compare IEEE floating point values for equality using per-field thresholds.

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

How can I implement FloatEq?

You will need some way to represent difference in ULPs for your type, following the same structure as the type itself. Implementation is then usually a matter of calling through to an underlying FloatEq method for each field in turn. If not, you will need to take a close look at the descriptions of the algorithms on a method by method basis:

#[derive(Copy, Clone)]
struct MyComplex32 {
    re: f32,
    im: f32,
}

#[derive(Copy, Clone)]
struct MyComplex32Ulps {
    re: <f32 as FloatDiff>::UlpsDiff,
    im: <f32 as FloatDiff>::UlpsDiff,
}

impl FloatEq for MyComplex32 {
    type Epsilon = MyComplex32;
    type UlpsEpsilon = MyComplex32Ulps;

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

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

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

let a = MyComplex32 { re: 1.0, im: 2.000_003_6, };
let b = MyComplex32 { re: 1.000_000_1, im: 2.0, };

assert!(a.eq_abs(&b, &MyComplex32 { re: 0.000_000_15, im: 0.000_003_6 }));
assert!(a.ne_abs(&b, &MyComplex32 { re: 0.000_000_05, im: 0.000_003_6 }));
assert!(a.ne_abs(&b, &MyComplex32 { re: 0.000_000_15, im: 0.000_003_5 }));

assert!(a.eq_rel(&b, &MyComplex32 { re: 0.000_000_15, im: 0.000_001_8 }));
assert!(a.ne_rel(&b, &MyComplex32 { re: 0.000_000_05, im: 0.000_001_8 }));
assert!(a.ne_rel(&b, &MyComplex32 { re: 0.000_000_15, im: 0.000_001_7 }));

assert!(a.eq_ulps(&b, &MyComplex32Ulps { re: 1, im: 15 }));
assert!(a.ne_ulps(&b, &MyComplex32Ulps { re: 0, im: 15 }));
assert!(a.ne_ulps(&b, &MyComplex32Ulps { re: 1, im: 14 }));

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:

impl FloatEq<f32> for MyComplex32 {
    type Epsilon = MyComplex32;
    type UlpsEpsilon = MyComplex32Ulps;

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

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

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

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

assert!(a.eq_abs(&b, &MyComplex32 { re: 0.000_000_8, im: 0.0 }));
assert!(a.ne_abs(&b, &MyComplex32 { re: 0.000_000_4, im: 0.0 }));

assert!(a.eq_rel(&b, &MyComplex32 { re: 0.000_000_12, im: 0.0 }));
assert!(a.ne_rel(&b, &MyComplex32 { re: 0.000_000_11, im: 0.0 }));

assert!(a.eq_ulps(&b, &MyComplex32Ulps { re: 1, im: 0 }));
assert!(a.ne_ulps(&b, &MyComplex32Ulps { re: 0, im: 0 }));

Examples

assert!(4.0_f32.eq_abs(&4.000_001_5, &0.000_001_6));
assert!(4.0_f32.ne_abs(&4.000_001_5, &0.000_001_4));

assert!(4.0_f32.eq_rel(&4.000_001_5, &0.000_000_4));
assert!(4.0_f32.ne_rel(&4.000_001_5, &0.000_000_3));

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

Associated Types

type Epsilon

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. This should be structurally similar to the most complex type being compared, most implementations will just use Self.

type UlpsEpsilon

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 should be structurally similar to the most complex type being compared, most implementations will define an Ulps type that mirrors the fields of Self.

Loading content...

Required methods

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

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

Implementations should be the equivalent of:

// the PartialEq check covers equality of infinities
self == other || (self - other).abs().le(max_diff)

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

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

The implementation should be the equivalent of:

// the PartialEq check covers equality of infinities
self == other || {
    let largest = self.abs().max(other.abs());
    let epsilon = largest * max_diff;
    (self - other).abs() <= epsilon
}

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

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

The implementation should be the equivalent of:

if self.is_nan() || other.is_nan() {
    false // NaNs are never equal
}
else if self.is_sign_positive() != other.is_sign_positive() {
    self == other // account for zero == negative zero
} else {
    let a = self.to_bits();
    let b = other.to_bits();
    let max = a.max(b);
    let min = a.min(b);
    (max - min).le(max_diff)
}
Loading content...

Provided methods

fn ne_abs(&self, other: &Rhs, max_diff: &Self::Epsilon) -> 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::Epsilon) -> 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::UlpsEpsilon) -> 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]

type Epsilon = [T::Epsilon; 0]

type UlpsEpsilon = [T::UlpsEpsilon; 0]

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

type Epsilon = [T::Epsilon; 1]

type UlpsEpsilon = [T::UlpsEpsilon; 1]

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

type Epsilon = [T::Epsilon; 2]

type UlpsEpsilon = [T::UlpsEpsilon; 2]

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

type Epsilon = [T::Epsilon; 3]

type UlpsEpsilon = [T::UlpsEpsilon; 3]

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

type Epsilon = [T::Epsilon; 4]

type UlpsEpsilon = [T::UlpsEpsilon; 4]

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

type Epsilon = [T::Epsilon; 5]

type UlpsEpsilon = [T::UlpsEpsilon; 5]

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

type Epsilon = [T::Epsilon; 6]

type UlpsEpsilon = [T::UlpsEpsilon; 6]

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

type Epsilon = [T::Epsilon; 7]

type UlpsEpsilon = [T::UlpsEpsilon; 7]

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

type Epsilon = [T::Epsilon; 8]

type UlpsEpsilon = [T::UlpsEpsilon; 8]

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

type Epsilon = [T::Epsilon; 9]

type UlpsEpsilon = [T::UlpsEpsilon; 9]

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

type Epsilon = [T::Epsilon; 10]

type UlpsEpsilon = [T::UlpsEpsilon; 10]

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

type Epsilon = [T::Epsilon; 11]

type UlpsEpsilon = [T::UlpsEpsilon; 11]

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

type Epsilon = [T::Epsilon; 12]

type UlpsEpsilon = [T::UlpsEpsilon; 12]

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

type Epsilon = [T::Epsilon; 13]

type UlpsEpsilon = [T::UlpsEpsilon; 13]

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

type Epsilon = [T::Epsilon; 14]

type UlpsEpsilon = [T::UlpsEpsilon; 14]

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

type Epsilon = [T::Epsilon; 15]

type UlpsEpsilon = [T::UlpsEpsilon; 15]

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

type Epsilon = [T::Epsilon; 16]

type UlpsEpsilon = [T::UlpsEpsilon; 16]

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

type Epsilon = [T::Epsilon; 17]

type UlpsEpsilon = [T::UlpsEpsilon; 17]

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

type Epsilon = [T::Epsilon; 18]

type UlpsEpsilon = [T::UlpsEpsilon; 18]

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

type Epsilon = [T::Epsilon; 19]

type UlpsEpsilon = [T::UlpsEpsilon; 19]

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

type Epsilon = [T::Epsilon; 20]

type UlpsEpsilon = [T::UlpsEpsilon; 20]

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

type Epsilon = [T::Epsilon; 21]

type UlpsEpsilon = [T::UlpsEpsilon; 21]

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

type Epsilon = [T::Epsilon; 22]

type UlpsEpsilon = [T::UlpsEpsilon; 22]

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

type Epsilon = [T::Epsilon; 23]

type UlpsEpsilon = [T::UlpsEpsilon; 23]

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

type Epsilon = [T::Epsilon; 24]

type UlpsEpsilon = [T::UlpsEpsilon; 24]

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

type Epsilon = [T::Epsilon; 25]

type UlpsEpsilon = [T::UlpsEpsilon; 25]

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

type Epsilon = [T::Epsilon; 26]

type UlpsEpsilon = [T::UlpsEpsilon; 26]

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

type Epsilon = [T::Epsilon; 27]

type UlpsEpsilon = [T::UlpsEpsilon; 27]

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

type Epsilon = [T::Epsilon; 28]

type UlpsEpsilon = [T::UlpsEpsilon; 28]

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

type Epsilon = [T::Epsilon; 29]

type UlpsEpsilon = [T::UlpsEpsilon; 29]

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

type Epsilon = [T::Epsilon; 30]

type UlpsEpsilon = [T::UlpsEpsilon; 30]

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

type Epsilon = [T::Epsilon; 31]

type UlpsEpsilon = [T::UlpsEpsilon; 31]

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

type Epsilon = [T::Epsilon; 32]

type UlpsEpsilon = [T::UlpsEpsilon; 32]

impl FloatEq<f32> for f32[src]

type Epsilon = f32

type UlpsEpsilon = u32

impl FloatEq<f64> for f64[src]

type Epsilon = f64

type UlpsEpsilon = u64

impl FloatEq<()> for ()[src]

type Epsilon = ()

type UlpsEpsilon = ()

impl<A> FloatEq<(A,)> for (A,) where
    A: FloatEq + ?Sized
[src]

type Epsilon = (A::Epsilon,)

type UlpsEpsilon = (A::UlpsEpsilon,)

impl<A: FloatEq, B> FloatEq<(A, B)> for (A, B) where
    B: FloatEq + ?Sized
[src]

type Epsilon = (A::Epsilon, B::Epsilon)

type UlpsEpsilon = (A::UlpsEpsilon, B::UlpsEpsilon)

impl<A: FloatEq, B: FloatEq, C> FloatEq<(A, B, C)> for (A, B, C) where
    C: FloatEq + ?Sized
[src]

type Epsilon = (A::Epsilon, B::Epsilon, C::Epsilon)

type UlpsEpsilon = (A::UlpsEpsilon, B::UlpsEpsilon, C::UlpsEpsilon)

impl<A: FloatEq, B: FloatEq, C: FloatEq, D> FloatEq<(A, B, C, D)> for (A, B, C, D) where
    D: FloatEq + ?Sized
[src]

type Epsilon = (A::Epsilon, B::Epsilon, C::Epsilon, D::Epsilon)

type UlpsEpsilon = (A::UlpsEpsilon, B::UlpsEpsilon, C::UlpsEpsilon, D::UlpsEpsilon)

impl<A: FloatEq, B: FloatEq, C: FloatEq, D: FloatEq, E> FloatEq<(A, B, C, D, E)> for (A, B, C, D, E) where
    E: FloatEq + ?Sized
[src]

type Epsilon = (A::Epsilon, B::Epsilon, C::Epsilon, D::Epsilon, E::Epsilon)

type UlpsEpsilon = (A::UlpsEpsilon, B::UlpsEpsilon, C::UlpsEpsilon, D::UlpsEpsilon, E::UlpsEpsilon)

impl<A: FloatEq, B: FloatEq, C: FloatEq, D: FloatEq, E: FloatEq, F> FloatEq<(A, B, C, D, E, F)> for (A, B, C, D, E, F) where
    F: FloatEq + ?Sized
[src]

type Epsilon = (A::Epsilon, B::Epsilon, C::Epsilon, D::Epsilon, E::Epsilon, F::Epsilon)

type UlpsEpsilon = (A::UlpsEpsilon, B::UlpsEpsilon, C::UlpsEpsilon, D::UlpsEpsilon, E::UlpsEpsilon, F::UlpsEpsilon)

impl<A: FloatEq, B: FloatEq, C: FloatEq, D: FloatEq, E: FloatEq, F: FloatEq, G> FloatEq<(A, B, C, D, E, F, G)> for (A, B, C, D, E, F, G) where
    G: FloatEq + ?Sized
[src]

type Epsilon = (A::Epsilon, B::Epsilon, C::Epsilon, D::Epsilon, E::Epsilon, F::Epsilon, G::Epsilon)

type UlpsEpsilon = (A::UlpsEpsilon, B::UlpsEpsilon, C::UlpsEpsilon, D::UlpsEpsilon, E::UlpsEpsilon, F::UlpsEpsilon, G::UlpsEpsilon)

impl<A: FloatEq, B: FloatEq, C: FloatEq, D: FloatEq, E: FloatEq, F: FloatEq, G: FloatEq, H> FloatEq<(A, B, C, D, E, F, G, H)> for (A, B, C, D, E, F, G, H) where
    H: FloatEq + ?Sized
[src]

type Epsilon = (A::Epsilon, B::Epsilon, C::Epsilon, D::Epsilon, E::Epsilon, F::Epsilon, G::Epsilon, H::Epsilon)

type UlpsEpsilon = (A::UlpsEpsilon, B::UlpsEpsilon, C::UlpsEpsilon, D::UlpsEpsilon, E::UlpsEpsilon, F::UlpsEpsilon, G::UlpsEpsilon, H::UlpsEpsilon)

impl<A: FloatEq, B: FloatEq, C: FloatEq, D: FloatEq, E: FloatEq, F: FloatEq, G: FloatEq, H: FloatEq, I> FloatEq<(A, B, C, D, E, F, G, H, I)> for (A, B, C, D, E, F, G, H, I) where
    I: FloatEq + ?Sized
[src]

type Epsilon = (A::Epsilon, B::Epsilon, C::Epsilon, D::Epsilon, E::Epsilon, F::Epsilon, G::Epsilon, H::Epsilon, I::Epsilon)

type UlpsEpsilon = (A::UlpsEpsilon, B::UlpsEpsilon, C::UlpsEpsilon, D::UlpsEpsilon, E::UlpsEpsilon, F::UlpsEpsilon, G::UlpsEpsilon, H::UlpsEpsilon, I::UlpsEpsilon)

impl<A: FloatEq, B: FloatEq, C: FloatEq, D: FloatEq, E: FloatEq, F: FloatEq, G: FloatEq, H: FloatEq, I: FloatEq, J> FloatEq<(A, B, C, D, E, F, G, H, I, J)> for (A, B, C, D, E, F, G, H, I, J) where
    J: FloatEq + ?Sized
[src]

type Epsilon = (A::Epsilon, B::Epsilon, C::Epsilon, D::Epsilon, E::Epsilon, F::Epsilon, G::Epsilon, H::Epsilon, I::Epsilon, J::Epsilon)

type UlpsEpsilon = (A::UlpsEpsilon, B::UlpsEpsilon, C::UlpsEpsilon, D::UlpsEpsilon, E::UlpsEpsilon, F::UlpsEpsilon, G::UlpsEpsilon, H::UlpsEpsilon, I::UlpsEpsilon, J::UlpsEpsilon)

impl<A: FloatEq, B: FloatEq, C: FloatEq, D: FloatEq, E: FloatEq, F: FloatEq, G: FloatEq, H: FloatEq, I: FloatEq, J: FloatEq, K> FloatEq<(A, B, C, D, E, F, G, H, I, J, K)> for (A, B, C, D, E, F, G, H, I, J, K) where
    K: FloatEq + ?Sized
[src]

type Epsilon = (A::Epsilon, B::Epsilon, C::Epsilon, D::Epsilon, E::Epsilon, F::Epsilon, G::Epsilon, H::Epsilon, I::Epsilon, J::Epsilon, K::Epsilon)

type UlpsEpsilon = (A::UlpsEpsilon, B::UlpsEpsilon, C::UlpsEpsilon, D::UlpsEpsilon, E::UlpsEpsilon, F::UlpsEpsilon, G::UlpsEpsilon, H::UlpsEpsilon, I::UlpsEpsilon, J::UlpsEpsilon, K::UlpsEpsilon)

impl<A: FloatEq, B: FloatEq, C: FloatEq, D: FloatEq, E: FloatEq, F: FloatEq, G: FloatEq, H: FloatEq, I: FloatEq, J: FloatEq, K: FloatEq, L> FloatEq<(A, B, C, D, E, F, G, H, I, J, K, L)> for (A, B, C, D, E, F, G, H, I, J, K, L) where
    L: FloatEq + ?Sized
[src]

type Epsilon = (A::Epsilon, B::Epsilon, C::Epsilon, D::Epsilon, E::Epsilon, F::Epsilon, G::Epsilon, H::Epsilon, I::Epsilon, J::Epsilon, K::Epsilon, L::Epsilon)

type UlpsEpsilon = (A::UlpsEpsilon, B::UlpsEpsilon, C::UlpsEpsilon, D::UlpsEpsilon, E::UlpsEpsilon, F::UlpsEpsilon, G::UlpsEpsilon, H::UlpsEpsilon, I::UlpsEpsilon, J::UlpsEpsilon, K::UlpsEpsilon, L::UlpsEpsilon)

impl<T: FloatEq> FloatEq<Complex<T>> for Complex<T>[src]

type Epsilon = Complex<T::Epsilon>

type UlpsEpsilon = ComplexUlps<T::UlpsEpsilon>

Loading content...

Implementors

Loading content...