[−][src]Trait float_eq::FloatEq
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
).
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
}
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.
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).