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
use std::fmt::{Debug, Display};

use num::Float;

/// Asserts that two decimals are equal with the specified precision.
/// On panic, the function will print the value of the decimal with their debug representations.
/// 2つの小数が指定した精度で等しいことを保証する。
/// パニックになると、この関数は小数の値をデバッグ表現とともに出力する。
///
/// # Panics
///
/// Panic if the value is not equivalent to the specified precision.
/// 値が指定した精度で等価でなければパニックする。
///
/// # Examples
///
/// ```should_panic
/// use assert_be_close::assert_be_close;
///
/// assert_be_close(1.0, 1.0001, 3);
/// assert_be_close(1.0, 1.0001, 4); // panic
/// ```
pub fn assert_be_close<T: Float + Display>(left: T, right: T, precision: i32) {
    let expected_diff = T::from(10.0).unwrap().powi(-precision) / T::from(2.0).unwrap();
    let received_diff = (left - right).abs();

    if received_diff >= expected_diff {
        panic!("assertion 'left ≈ right` failed\n left: {}\nright: {}\nreceived_diff: {}\nexpected_diff: {}", left, right, received_diff, expected_diff);
    }
}

/// Asserts that two decimals aren't equal with the specified precision.
/// On panic, the function will print the value of the decimal with their debug representations.
/// 2つの小数が指定した精度で等しくないことを保証する。
/// パニックになると、この関数は小数の値をデバッグ表現とともに出力する。
///
/// # Panics
///
/// Panic if the value is equivalent to the specified precision.
/// 値が指定した精度で等価であるとパニックする。
///
/// # Examples
///
/// ```should_panic
/// use assert_be_close::assert_not_close;
///
/// assert_not_close(1.0, 1.0001, 4);
/// assert_not_close(1.0, 1.0001, 3); // panic
/// ```
pub fn assert_not_close<T: Float + Display>(left: T, right: T, precision: i32) {
    let expected_diff = T::from(10.0).unwrap().powi(-precision) / T::from(2.0).unwrap();
    let received_diff = (left - right).abs();

    if received_diff <= expected_diff {
        panic!("assertion 'left != right` failed\n left: {}\nright: {}\nreceived_diff: {}\nexpected_diff: {}", left, right, received_diff, expected_diff);
    }
}


#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn assert_be_close_works() {
        assert_be_close(1.0, 1.0001, 3);
    }

    #[test]
    fn assert_not_close_works() {
        assert_not_close(1.0, 1.0001, 4);
    }
}