## no-std nearly

Compare IEEE floating point types

### 4 releases(breaking)

 0.4.0 Apr 8, 2024 Feb 19, 2024 May 15, 2023 Mar 14, 2023

#125 in Debugging

120KB
2K SLoC

# nearly

Compare IEEE floating point types by nearly comparisons.

When comparing floating point types, because of their limited precision, they might not be exactly identical. Consider the following example, where a and b appear to be identical, but they are not:

``````let a: f32 = 1.0 + 1.04 + 1.1;
let b: f32 = 3.14;

assert!(a == b); // <-- PANICS
``````

This crate provides macros to perform a comparison with some tolerance.

``````use nearly::nearly;
assert!( nearly!(a == b) ); // <-- OK
``````

## Usage

The easiest way to use nearly comparisons is by invoking the `nearly!` macro. The macro returns a boolean whether the comparison is true or false by using the provided tolerance.

The comparison can be:

• `a == b` for testing whether a is nearly equal to b
• `a != b` for testing whether a is not nearly equal to b
• `a < b` for testing whether a is strict less than b but not nearly equal to b
• `a <= b` for testing whether a is strict less than b or nearly equal to b
• `a > b` for testing whether a is strict greater than b but not nearly equal to b
• `a >= b` for testing whether a is strict greater than b or nearly equal to b

The tolerance used can be:

• `eps` for an absolute epsilon tolerance
• `ulps` for an ulps based tolerance
• `tol` for an absolute epsilon and ulps based tolerance
• `default` for an absolute epsilon and ulps based tolerance using default values

Here are some example calls:

``````use nearly::{nearly, Tolerance};

let a: f32 = 1.0 + 1.04 + 1.1;
let b: f32 = 3.14;

// use absolute epsilon tolerance
nearly!(a == b, eps = 0.001);

// use ulps based tolerance
nearly!(a == b, ulps = 5);

// use absolute epsilon and ulps based tolerance
nearly!(a == b, eps = 0.001, ulps = 5);
nearly!(a == b, tol = Tolerance::new(0.001, 5));

// use default absolute epsilon and default ulps based tolerance
nearly!(a == b);
``````

There is also an `assert_nearly!` and `debug_assert_nearly!` macro you can use that panic if the nearly comparison evaluates to false. The signature is the same as for the `nearly!` macro.

``````use nearly::{assert_nearly, debug_assert_nearly, Tolerance};

assert_nearly!(a == b, eps = 0.001);
assert_nearly!(a == b, ulps = 5);
assert_nearly!(a == b, eps = 0.001, ulps = 5);
assert_nearly!(a == b, tol = Tolerance::new(0.001, 5));
assert_nearly!(a == b);

debug_assert_nearly!(a == b, eps = 0.001);
debug_assert_nearly!(a == b, ulps = 5);
debug_assert_nearly!(a == b, eps = 0.001, ulps = 5);
debug_assert_nearly!(a == b, tol = Tolerance::new(0.001, 5));
debug_assert_nearly!(a == b);
``````

The nearly functionality is also implemented for a variety of other types holding floats like containers, maps, pointers or tuples. Here is an example of comparing two arrays of floats.

``````use nearly::nearly;

let a: [f32; 4] = [1.1, 2.2, 2.2, 4.4];
let b: [f32; 4] = [1.1, 2.2, 3.3, 4.4];

nearly!(a <= b, eps = 0.001, ulps = 5);
``````

## Derive the nearly traits

The easiest way to add nearly comparison to your own types is by deriving the nearly traits. Just derive `NearlyEq` and `NearlyOrd` to get full support on your type.

``````use nearly::{assert_nearly, NearlyEq, NearlyOrd};

#[derive(Debug, NearlyEq, NearlyOrd)]
struct Point {
x: f32,
y: f32,
}

let a = Point { x: 1.23, y: 4.56 };
let b = Point { x: 1.23, y: 4.567 };

assert_nearly!(a == b, eps = 0.01);
assert_nearly!(a <= b, eps = 0.01);
``````

To use the `assert_nearly!` and `debug_assert_nearly!` macros, your type must also implement the Debug trait.

You can derive the following traits:

• `NearlyEqEps`: enables nearly support with absolute epsilon tolerance
• `NearlyEqUlps`: enables nearly support with ulps based tolerance
• `NearlyEqTol`: enables nearly support with absolute epsilon and ulps based tolerances
• `NearlyEq`: enables nearly support with absolute epsilon and ulps based tolerances with default values
• `NearlyOrdEps`: enables nearly ordering support with absolute epsilon tolerance
• `NearlyOrdUlps`: enables nearly ordering support with ulps based tolerance
• `NearlyOrdTol`: enables nearly ordering support with absolute epsilon and ulps based tolerances
• `NearlyOrd`: enables nearly ordering support with absolute epsilon and ulps based tolerances with default values

~0.3–0.8MB
~19K SLoC