1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//! Assertions for floating-point numbers.

#![no_std]

extern crate alloc;

use alloc::format;
use alloc::string::String;

/// Asserts that the quotient of the difference between the two floats over the largest (by magnitude)
/// of the two floats, taken as an absolute value, is within the supplied `delta` threshold.
///
/// # Panics
/// If the quotient (`gamma`) exceeds `delta`.
pub fn assert_relative(left: f64, right: f64, delta: f64) {
    check_relative(left, right, delta)
        .map_err(|err| String::from("assertion failed: ") + &err)
        .unwrap();
}

/// The absolute value of an `f64`. This is not available in a `no_std` context.
fn abs(val: f64) -> f64 {
    if val >= 0.0 {
        val
    } else {
        -val
    }
}

/// Checks whether the quotient of the difference between the two floats over the largest (by magnitude)
/// of the two floats, taken as an absolute value, is within the supplied `delta` threshold.
///
/// # Errors
/// If the quotient (`gamma`) exceeds `delta`.
pub fn check_relative(left: f64, right: f64, delta: f64) -> Result<(), String> {
    if left != 0.0 || right != 0.0 {
        let denom = f64::max(abs(left), abs(right));
        let gamma = abs((left - right) / denom);
        if gamma > delta {
            return Err(format!(
                "(left ≉ right) left: {}, right: {}, gamma: {}",
                left, right, gamma
            ));
        }
    }
    Ok(())
}

#[cfg(test)]
mod tests;