[][src]Crate almost

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:

  1. 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).

  2. 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.

  3. 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.

  4. 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.

  5. 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

F32_TOLERANCE

The default tolerance used for f32. Equivalent to f32::EPSILON.sqrt() (or 0.00034526698_f32), as we assume that around half of the precision bits of any arbitrary value have been rounded away.

F64_TOLERANCE

The default tolerance used for f64. Equivalent to f64::EPSILON.sqrt() (or 0.000000014901161193847656_f64), as we assume that around half of the precision bits of any arbitrary value have been rounded away.

Traits

AlmostEqual

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

equal

Returns true if lhs and rhs are almost equal.

equal_with_tolerance

Returns true if lhs and rhs are almost equal using the provided relative tolerance.

zero

Returns true if a is almost zero.

zero_with_tolerance

Returns true if a is almost zero, using the specified absolute tolerance.