[−][src]Trait float_eq::FloatEqDebug
Provides additional context for debugging when an assert fails.
This is used internally by the assert_float_eq!
family of macros to provide
debug context information to the user when they fail.
How can I implement FloatEqDebug
?
Implementing FloatEqDebug
on your types is straightfoward if they're already
composed of compatible fields. First, you will need to implement FloatEq
.
You will then need to choose the types of DebugEpsilon
and DebugUlpsEpsilon
to provide debug context when an assert fails. These ought to display the values
of DiffEpsilon
and UlpsDiffEpsilon
for each field of your type, following
the same structure so as to make it easier to see which values are being compared
for the checks. For example, MyComplex32
here has re
and im
fields and
MyComplex32UlpsDiff
follows that layout:
#[derive(Debug)] struct MyComplex32 { re: f32, im: f32, } #[derive(Debug)] struct MyComplex32UlpsDiff { re: <f32 as FloatDiff>::UlpsDiff, im: <f32 as FloatDiff>::UlpsDiff, } 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) } } impl FloatEqDebug for MyComplex32 { type DebugEpsilon = Self; type DebugUlpsEpsilon = MyComplex32UlpsDiff; fn debug_abs_epsilon( &self, other: &Self, max_diff: &Self::DiffEpsilon ) -> Self::DebugEpsilon { MyComplex32 { re: self.re.debug_abs_epsilon(&other.re, max_diff), im: self.im.debug_abs_epsilon(&other.im, max_diff), } } fn debug_rel_epsilon( &self, other: &Self, max_diff: &Self::DiffEpsilon ) -> Self::DebugEpsilon { MyComplex32 { re: self.re.debug_rel_epsilon(&other.re, max_diff), im: self.im.debug_rel_epsilon(&other.im, max_diff), } } fn debug_ulps_epsilon( &self, other: &Self, max_diff: &Self::UlpsDiffEpsilon, ) -> Self::DebugUlpsEpsilon { MyComplex32UlpsDiff { re: self.re.debug_ulps_epsilon(&other.re, max_diff), im: self.im.debug_ulps_epsilon(&other.im, max_diff), } } } let a = MyComplex32 { re: 1.0, im: 200.0 }; let b = MyComplex32 { re: 50.0, im: 1.0 }; let abs_epsilon = a.debug_abs_epsilon(&b, &0.1); assert_eq!(abs_epsilon.re, 0.1); assert_eq!(abs_epsilon.im, 0.1); let rel_epsilon = a.debug_rel_epsilon(&b, &0.1); assert_eq!(rel_epsilon.re, 5.0); assert_eq!(rel_epsilon.im, 20.0); let ulps_epsilon = a.debug_ulps_epsilon(&b, &42); assert_eq!(ulps_epsilon.re, 42); assert_eq!(ulps_epsilon.im, 42);
If your type does not already have an underlying implementation of FloatEqDebug
,
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 FloatEqDebug
'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
:
#[derive(Debug)] struct MyComplex32 { re: f32, im: f32, } #[derive(Debug)] struct MyComplex32UlpsDiff { re: <f32 as FloatDiff>::UlpsDiff, im: <f32 as FloatDiff>::UlpsDiff, } 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) } } impl FloatEqDebug<f32> for MyComplex32 { type DebugEpsilon = Self; type DebugUlpsEpsilon = MyComplex32UlpsDiff; fn debug_abs_epsilon( &self, other: &f32, max_diff: &Self::DiffEpsilon ) -> Self::DebugEpsilon { MyComplex32 { re: self.re.debug_abs_epsilon(other, max_diff), im: self.im.debug_abs_epsilon(&0.0, max_diff), } } fn debug_rel_epsilon( &self, other: &f32, max_diff: &Self::DiffEpsilon ) -> Self::DebugEpsilon { MyComplex32 { re: self.re.debug_rel_epsilon(other, max_diff), im: self.im.debug_rel_epsilon(&0.0, max_diff), } } fn debug_ulps_epsilon( &self, other: &f32, max_diff: &Self::UlpsDiffEpsilon, ) -> Self::DebugUlpsEpsilon { MyComplex32UlpsDiff { re: self.re.debug_ulps_epsilon(other, max_diff), im: self.im.debug_ulps_epsilon(&0.0, max_diff), } } } impl FloatEqDebug<MyComplex32> for f32 { type DebugEpsilon = <MyComplex32 as FloatEqDebug<f32>>::DebugEpsilon; type DebugUlpsEpsilon = <MyComplex32 as FloatEqDebug<f32>>::DebugUlpsEpsilon; fn debug_abs_epsilon( &self, other: &MyComplex32, max_diff: &Self::DiffEpsilon, ) -> Self::DebugEpsilon { other.debug_abs_epsilon(self, max_diff) } fn debug_rel_epsilon( &self, other: &MyComplex32, max_diff: &Self::DiffEpsilon, ) -> Self::DebugEpsilon { other.debug_rel_epsilon(self, max_diff) } fn debug_ulps_epsilon( &self, other: &MyComplex32, max_diff: &Self::UlpsDiffEpsilon, ) -> Self::DebugUlpsEpsilon { other.debug_ulps_epsilon(self, max_diff) } } let a = MyComplex32 { re: 1.0, im: 200.0 }; let b = 9000.0_f32; let abs_epsilon = a.debug_abs_epsilon(&b, &0.1); assert_eq!(abs_epsilon.re, 0.1); assert_eq!(abs_epsilon.im, 0.1); let rel_epsilon = a.debug_rel_epsilon(&b, &0.1); assert_eq!(rel_epsilon.re, 900.0); assert_eq!(rel_epsilon.im, 20.0); let ulps_epsilon = a.debug_ulps_epsilon(&b, &42); assert_eq!(ulps_epsilon.re, 42); assert_eq!(ulps_epsilon.im, 42);
Associated Types
type DebugEpsilon: Debug
Displayed to the user when an assert fails, using fmt::Debug
.
This should display Self::DiffEpsilon
in an appropriate form to the
user. For example, when implemented for an array type, it should be an
array of the epsilon values so the user can see the link between the diff
items to the values tested against.
type DebugUlpsEpsilon: Debug
Displayed to the user when an assert fails, using fmt::Debug
.
This should display Self::UlpsDiffEpsilon
in an appropriate form to the
user. For example, when implemented for an array type, it should be an
array of the epsilon values so the user can see the link between the diff
items to the values tested against.
Required methods
fn debug_abs_epsilon(
&self,
other: &Rhs,
max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
&self,
other: &Rhs,
max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
The epsilon used by an absolute epsilon comparison, displayed when an assert fails.
fn debug_rel_epsilon(
&self,
other: &Rhs,
max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
&self,
other: &Rhs,
max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
The epsilon used by a relative epsilon comparison, displayed when an assert fails.
fn debug_ulps_epsilon(
&self,
other: &Rhs,
max_diff: &Self::UlpsDiffEpsilon
) -> Self::DebugUlpsEpsilon
&self,
other: &Rhs,
max_diff: &Self::UlpsDiffEpsilon
) -> Self::DebugUlpsEpsilon
The epsilon used by an ULPs comparison, displayed when an assert fails.
Implementations on Foreign Types
impl<T: FloatEqDebug> FloatEqDebug<[T; 0]> for [T; 0]
[src]
This is also implemented on other arrays up to size 32 (inclusive).
type DebugEpsilon = [<T as FloatEqDebug>::DebugEpsilon; 0]
type DebugUlpsEpsilon = [<T as FloatEqDebug>::DebugUlpsEpsilon; 0]
fn debug_abs_epsilon(
&self,
_other: &Self,
_max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
[src]
&self,
_other: &Self,
_max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
fn debug_rel_epsilon(
&self,
_other: &Self,
_max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
[src]
&self,
_other: &Self,
_max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
fn debug_ulps_epsilon(
&self,
_other: &Self,
_max_diff: &Self::UlpsDiffEpsilon
) -> Self::DebugUlpsEpsilon
[src]
&self,
_other: &Self,
_max_diff: &Self::UlpsDiffEpsilon
) -> Self::DebugUlpsEpsilon
impl FloatEqDebug<f32> for f32
[src]
type DebugEpsilon = Self::DiffEpsilon
type DebugUlpsEpsilon = Self::UlpsDiffEpsilon
fn debug_abs_epsilon(
&self,
_other: &Self,
max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
[src]
&self,
_other: &Self,
max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
fn debug_rel_epsilon(
&self,
other: &Self,
max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
[src]
&self,
other: &Self,
max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
fn debug_ulps_epsilon(
&self,
_other: &Self,
max_diff: &Self::UlpsDiffEpsilon
) -> Self::DebugUlpsEpsilon
[src]
&self,
_other: &Self,
max_diff: &Self::UlpsDiffEpsilon
) -> Self::DebugUlpsEpsilon
impl FloatEqDebug<f64> for f64
[src]
type DebugEpsilon = Self::DiffEpsilon
type DebugUlpsEpsilon = Self::UlpsDiffEpsilon
fn debug_abs_epsilon(
&self,
_other: &Self,
max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
[src]
&self,
_other: &Self,
max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
fn debug_rel_epsilon(
&self,
other: &Self,
max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
[src]
&self,
other: &Self,
max_diff: &Self::DiffEpsilon
) -> Self::DebugEpsilon
fn debug_ulps_epsilon(
&self,
_other: &Self,
max_diff: &Self::UlpsDiffEpsilon
) -> Self::DebugUlpsEpsilon
[src]
&self,
_other: &Self,
max_diff: &Self::UlpsDiffEpsilon
) -> Self::DebugUlpsEpsilon