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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/// Asserts that two float expressions are not (approximately) equal to each other.
///
/// On panic, this macro will print the values of the expressions with their
/// debug representations.
///
/// Like [`assert_ne!`], this macro has a second form, where a custom
/// panic message can be provided.
///
/// # Examples
///
/// ```rust
/// use assert_eq_float::assert_ne_float;
///
/// let a = 3.01;
/// let b = 1.0 + 2.0;
///
/// assert_ne_float!(a, b);
///
/// assert_ne_float!(a, b; "we are testing addition with {} and {}", a, b);
///
/// assert_ne_float!(a, b, 1e-7); // use a fixed error
/// ```
///
/// Note that when setting a custom panic message, you should use a semicolon `;` instead of a comma `,`.
#[macro_export]
macro_rules! assert_ne_float {
    (@standard $left:ident, $right:ident, $error:ident) => {
        {
            use $crate::num_traits::float::FloatCore;

            let d_abs = ($left - $right).abs();

            if $left == $right || d_abs < $error {
                panic!(
                    "assertion failed: `(left != right)`\n  left: `{:?}`,\n right: `{:?}`\n  diff: `{:?}`\n error: `{:?}`",
                    $left,
                    $right,
                    d_abs,
                    $error,
                );
            }
        }
    };
    (@custom $left:ident, $right:ident, $error:ident; $($arg:tt)+) => {
        if $left == $right {
            panic!($($arg)+);
        }

        {
            use $crate::num_traits::float::FloatCore;

            let d_abs = ($left - $right).abs();

            assert!(
                d_abs >= $error,
                $($arg)+
            );
        }
    };
    ($left:expr, $right:expr $(,)?) => {{
        let left = $left;
        let right = $right;
        let error = $crate::get_error(left, right);

        $crate::assert_ne_float!(@standard left, right, error);
    }};
    ($left:expr, $right:expr; $($arg:tt)+) => {{
        let left = $left;
        let right = $right;
        let error = $crate::get_error(left, right);

        $crate::assert_ne_float!(@custom left, right, error; $($arg)+);
    }};
    ($left:expr, $right:expr, $error:expr $(,)?) => {{
        let left = $left;
        let right = $right;
        let error = $error;

        $crate::assert_ne_float!(@standard left, right, error);
    }};
    ($left:expr, $right:expr, $error:expr; $($arg:tt)+) => {{
        let left = $left;
        let right = $right;
        let error = $error;

        $crate::assert_ne_float!(@custom left, right, error; $($arg)+);
    }};
}

/// Asserts that two float expressions are not (approximately) equal to each other.
///
/// Unlike [`assert_ne_float!`], `debug_assert_ne_float!` statements are only enabled in non
/// optimized builds by default. An optimized build will not execute
/// `debug_assert_ne_float!` statements unless `-C debug-assertions` is passed to the
/// compiler. This makes `debug_assert_ne_float!` useful for checks that are too
/// expensive to be present in a release build but may be helpful during
/// development. The result of expanding `debug_assert_ne_float!` is always type checked.
#[macro_export]
macro_rules! debug_assert_ne_float {
    ($left:expr, $right:expr $(,)?) => {
        #[cfg(debug_assertions)]
        $crate::assert_ne_float!($left, $right);
    };
    ($left:expr, $right:expr; $($arg:tt)+) => {
        #[cfg(debug_assertions)]
        $crate::assert_ne_float!($left, $right; $($arg)+);
    };
    ($left:expr, $right:expr, $error:expr $(,)?) => {
        #[cfg(debug_assertions)]
        $crate::assert_ne_float!($left, $right, $error);
    };
    ($left:expr, $right:expr, $error:expr; $($arg:tt)+) => {
        #[cfg(debug_assertions)]
        $crate::assert_ne_float!($left, $right, $error; $($arg)+);
    };
}