1#![doc = include_str!("../README.md")]
2#![no_std]
3
4mod sealed {
8 pub trait Sealed {}
9
10 impl Sealed for f32 {}
11 impl Sealed for f64 {}
12}
13
14pub trait ApproxEq: sealed::Sealed {
16 fn approx_eq(self, other: Self) -> bool;
17}
18
19impl ApproxEq for f32 {
20 fn approx_eq(self, other: Self) -> bool {
21 let diff = (self - other).abs();
22 let a = self.abs();
23 let b = other.abs();
24 let largest = f32::max(a, b);
25 diff <= largest * f32::EPSILON
26 }
27}
28
29impl ApproxEq for f64 {
30 fn approx_eq(self, other: Self) -> bool {
31 let diff = (self - other).abs();
32 let a = self.abs();
33 let b = other.abs();
34 let largest = f64::max(a, b);
35 diff <= largest * f64::EPSILON
36 }
37}
38
39#[macro_export]
40macro_rules! assert_approx_eq {
41 ($a:expr, $b:expr$(,)?) => {{
42 let a = $a;
43 let b = $b;
44 assert!(
45 $crate::ApproxEq::approx_eq(a, b),
46 "assertion `{a}.approx_eq({b})` failed"
47 )
48 }};
49}
50
51#[macro_export]
52macro_rules! assert_approx_eq_slice {
53 ($a:expr, $b:expr$(,)?) => {{
54 let a = $a;
55 let b = $b;
56
57 let a: &[_] = ::core::convert::AsRef::as_ref(&a);
58 let b: &[_] = ::core::convert::AsRef::as_ref(&b);
59
60 assert_eq!(
61 a.len(),
62 b.len(),
63 "assertion `{a:?}.len() == {b:?}.len()` failed"
64 );
65
66 for (&a, &b) in a.iter().zip(b) {
67 $crate::assert_approx_eq!(a, b);
68 }
69 }};
70}