Consider this small example:
let diff: f32 = 1.0e-7;
let x: f32 = 1.0e-5;
let y = x - diff;
assert_ne!(x, y);
relative_eq!(x, y) // returns true, but should be false
Note that x and y are normal, full-precision floating-point values (not "subnormals"), above the epsilon threshold, and their relative error is (x - y)/x, which equals 0.01, far above the default threshold. However, they are marked as "relatively equal" in the current implementation.
The problem is in the logic of the provided implementation of RelativeEq::relative_eq() for f32 and f64, namely these lines:
|
let abs_diff = $T::abs(self - other); |
|
|
|
// For when the numbers are really close together |
|
if abs_diff <= epsilon { |
|
return true; |
|
} |
While the precise definition of relative equality and the parameters epsilon and max_relative are never clearly specified in the documentation, based on the referenced blog posts, it seems that the intention is to use epsilon as a zero-closeness threshold, and max_relative as the relative error threshold.
The issue stems from not checking the two input numbers (self and other in this case) individually against epsilon for a zero-threshold, but instead testing their absolute difference against epsilon. As a result, relative equality works as expected for large numbers, but in practice defaults to absolute-difference equality for values less than 1.
Consider this small example:
Note that
xandyare normal, full-precision floating-point values (not "subnormals"), above theepsilonthreshold, and their relative error is (x - y)/x, which equals 0.01, far above the default threshold. However, they are marked as "relatively equal" in the current implementation.The problem is in the logic of the provided implementation of
RelativeEq::relative_eq()forf32andf64, namely these lines:approx/src/relative_eq.rs
Lines 65 to 70 in 308176d
While the precise definition of relative equality and the parameters
epsilonandmax_relativeare never clearly specified in the documentation, based on the referenced blog posts, it seems that the intention is to useepsilonas a zero-closeness threshold, andmax_relativeas the relative error threshold.The issue stems from not checking the two input numbers (
selfandotherin this case) individually againstepsilonfor a zero-threshold, but instead testing their absolute difference againstepsilon. As a result, relative equality works as expected for large numbers, but in practice defaults to absolute-difference equality for values less than 1.