Expand description
A crate to test if floats are almost equal.
// Compare two variables.
if almost::equal(x, y) {
println!("They're almost equal!");
}
// Or, if you need need to compare with a constant zero:
if almost::zero(z) {
println!("It's almost zero!");
}
§Why another crate?
There are a lot of crates for doing this already.
The author crate has fairly strong opinions on how this should be done, and thinks most of the similar crates in the wild make dubious choices, make it easy for the user to misuse, or follow poor numerical robustness practices.
Specific differences / benefits compared to other crates:
-
Better choice of default tolerances for unknown inputs. Often the value of the
EPSILON
is used as a value for tolerance, or its use is encouraged by the API).This is the wrong choice more often than it is right. The machine epsilon is a quite strict bound for comparison, and after just a few arithmetic operations you will no longer be within it.
This library chooses a default tolerance value that is much more forgiving while still tight enough for it to be unlikely to cause false positives (specifically, it assumes roughly half of the bits have been lost to rounding, e.g. the square root of the machine epsilon).
-
Relative comparison by default. Most of the crates in the wild seem to use a hybrid between relative and absolute comparison. This is bad for arbitrary numbers which may have any scale, and gives up a number of desirable properties of the floating point number system.
-
Absolute comparison with zero. The only downside to using relative comparison by default is that it is essentially never useful to use relative comparison where one of the values is known in advance to be zero.
As a result, this library provides
almost::zero(v)
as well, which uses absolute comparison. -
Properly handling both overflow and underflow.
Because this library uses relative comparison, denormal numbers behave properly, as well as comparisons where one of the values has overflowed to infinity. The second might sound impossible, but we can just rescale both values, and compare with the same tolerance.
-
Simple API. We don’t expose other ways of comparing numbers, most of which are either dubious choices for non-niche use cases.
That said, there’s no one size fits all here. Numerical robustness is full of tradeoffs, and while I believe the ones made by this library are good for most cases, they do not and cannot satisfy every possible case.
Constants§
- The default tolerance used for
f32
. Equivalent tof32::EPSILON.sqrt()
(or0.00034526698_f32
), as we assume that around half of the precision bits of any arbitrary value have been rounded away. - The default tolerance used for
f64
. Equivalent tof64::EPSILON.sqrt()
(or0.000000014901161193847656_f64
), as we assume that around half of the precision bits of any arbitrary value have been rounded away.
Traits§
- A trait for comparing floating point numbers. Not broadly intended to be used by most code (instead, use the functions at the crate root), however it could be useful for generic code too.
Functions§
- Returns
true
iflhs
andrhs
are almost equal. - Returns
true
iflhs
andrhs
are almost equal using the provided relative tolerance. - Returns
true
ifa
is almost zero. - Returns
true
ifa
is almost zero, using the specified absolute tolerance.