[−][src]Trait float_eq::FloatEqAll
Compare IEEE floating point values for equality using a uniform threshold.
This trait is used in the implementation of the float_eq!
and assert_float_eq!
families of macros to provide abs_all
, rel_all
and ulps_all
checks. It
may be called directly, but the macros usually provide a friendlier interface.
Comparison via this trait may not fit every composite type. For example, it
likely ought not to be implemented for (f32, f64)
, which has a big difference
in precision between its fields.
How can I implement FloatEqAll
?
You will need some way to represent difference in ULPs for your type, which
is likely to be either u32
or u64
. Implementation is then usually a matter
of calling through to an underlying FloatEqAll
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, } impl FloatEqAll for MyComplex32 { type Epsilon = f32; type UlpsEpsilon = u32; fn eq_abs_all(&self, other: &Self, max_diff: &f32) -> bool { self.re.eq_abs_all(&other.re, max_diff) && self.im.eq_abs_all(&other.im, max_diff) } fn eq_rel_all(&self, other: &Self, max_diff: &f32) -> bool { self.re.eq_rel_all(&other.re, max_diff) && self.im.eq_rel_all(&other.im, max_diff) } fn eq_ulps_all(&self, other: &Self, max_diff: &u32) -> bool { self.re.eq_ulps_all(&other.re, max_diff) && self.im.eq_ulps_all(&other.im, max_diff) } } 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_all(&b, &0.000_003_6)); assert!(a.ne_abs_all(&b, &0.000_003_5)); assert!(a.eq_rel_all(&b, &0.000_001_8)); assert!(a.ne_rel_all(&b, &0.000_001_7)); assert!(a.eq_ulps_all(&b, &15)); assert!(a.ne_ulps_all(&b, &14));
How can I compare two different types?
The type to be compared with is controlled by FloatEqAll
'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 FloatEqAll<f32> for MyComplex32 { type Epsilon = f32; type UlpsEpsilon = u32; fn eq_abs_all(&self, other: &f32, max_diff: &f32) -> bool { self.re.eq_abs_all(other, max_diff) && self.im.eq_abs_all(&0.0, max_diff) } fn eq_rel_all(&self, other: &f32, max_diff: &f32) -> bool { self.re.eq_rel_all(other, max_diff) && self.im.eq_rel_all(&0.0, max_diff) } fn eq_ulps_all(&self, other: &f32, max_diff: &u32) -> bool { self.re.eq_ulps_all(other, max_diff) && self.im.eq_ulps_all(&0.0, max_diff) } } let a = MyComplex32 { re: 4.000_000_5, im: 0.0 }; let b = 4.0_f32; assert!(a.eq_abs_all(&b, &0.000_000_8)); assert!(a.ne_abs_all(&b, &0.000_000_4)); assert!(a.eq_rel_all(&b, &0.000_000_12)); assert!(a.ne_rel_all(&b, &0.000_000_11)); assert!(a.eq_ulps_all(&b, &1)); assert!(a.ne_ulps_all(&b, &0));
Examples
let a = [1.000_000_2f32, -2.0]; let b = [1.0f32, -2.000_002]; assert!(a.eq_abs_all(&b, &0.000_002)); assert!(a.ne_abs_all(&b, &0.000_001)); assert!(a.eq_rel_all(&b, &0.000_001)); assert!(a.ne_rel_all(&b, &0.000_000_5)); assert!(a.eq_ulps_all(&b, &8)); assert!(a.ne_ulps_all(&b, &7));
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_all
and rel_all
checks in methods and via the float_eq!
macros. This should be a single
floating point value so is often f32
or f64
.
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_all
checks in
methods and via the float_eq!
macros. This should be a single value
so is often u32
or u64
.
Required methods
fn eq_abs_all(&self, other: &Rhs, max_diff: &Self::Epsilon) -> bool
Check whether self
is equal to other
, using an absolute epsilon
comparison.
This must use the same algorithm as FloatEq::eq_abs
.
fn eq_rel_all(&self, other: &Rhs, max_diff: &Self::Epsilon) -> bool
Check whether self
is equal to other
, using a relative epsilon
comparison.
This must use the same algorithm as FloatEq::eq_rel
.
fn eq_ulps_all(&self, other: &Rhs, max_diff: &Self::UlpsEpsilon) -> bool
Check whether self
is equal to other
, using an ULPs comparison.
This must use the same algorithm as FloatEq::eq_ulps
.
Provided methods
fn ne_abs_all(&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_all(other, max_diff)
, there is no need to reimplement
this for your own types.
fn ne_rel_all(&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_all(other, max_diff)
, there is no need to reimplement
this for your own types.
fn ne_ulps_all(&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_all(other, max_diff)
, there is no need to reimplement
this for your own types.