1
2macro_rules! impl_equals {
5 ($fp:ident, $bits:ident, $SIGNIFICAND_SIZE:expr) => {
6 const SIGNIFICAND_SIZE: $bits = $SIGNIFICAND_SIZE;
7 const EXPONENT_SIZE: $bits = (core::mem::size_of::<$fp>() as $bits) * 8 - SIGNIFICAND_SIZE - 1;
8 const EXPONENT_MASK: $bits = ((1 << EXPONENT_SIZE) - 1) << SIGNIFICAND_SIZE;
9 const EXPONENT_BIAS: $bits = (1 << (EXPONENT_SIZE - 1)) - 1;
10
11 const SIGN_BIT: $bits = 1 << (core::mem::size_of::<$fp>() as $bits * 8 - 1);
12
13 #[inline]
15 pub(crate) fn abs(f: $fp) -> $fp {
16 $fp::from_bits(f.to_bits() & !SIGN_BIT)
17 }
18
19 #[inline]
20 pub(crate) fn eq_with_tol_impl(lhs: $fp, rhs: $fp, tol: $fp) -> bool {
21 let left_mag = abs(lhs);
22 let right_mag = abs(rhs);
23 if !((left_mag < core::$fp::INFINITY) & (right_mag < core::$fp::INFINITY)) {
24 handle_not_finite(lhs, rhs, tol)
25 } else {
26 let scale = if left_mag > right_mag {
27 left_mag
28 } else {
29 right_mag
30 };
31 let scale = if scale > core::$fp::MIN_POSITIVE {
34 scale
35 } else {
36 core::$fp::MIN_POSITIVE
37 };
38 let abs_tol = tol * scale;
39 abs(lhs - rhs) < abs_tol
40 }
41 }
42
43 #[cold]
44 #[inline(never)]
45 fn handle_not_finite(lhs: $fp, rhs: $fp, tol: $fp) -> bool {
46 if lhs.is_nan() || rhs.is_nan() {
47 false
48 } else if lhs.is_infinite() && rhs.is_infinite() {
49 lhs == rhs
50 } else {
51 let (lhs, rhs) = if lhs.is_infinite() { (lhs, rhs) } else { (rhs, lhs) };
57 debug_assert!(rhs.is_finite() && lhs.is_infinite(), "logic bug {} {} {:x} {:x}", lhs, rhs, lhs.to_bits(), rhs.to_bits());
58 let rbits = rhs.to_bits();
59 if (rbits & EXPONENT_MASK) == 0 {
60 return false;
63 }
64 let max_float_binade_bits = core::$fp::MAX.to_bits() & EXPONENT_MASK;
66 let new_lhs = $fp::from_bits(max_float_binade_bits | (lhs.to_bits() & SIGN_BIT));
68
69 let rhs_rescale = $fp::from_bits((EXPONENT_BIAS - 1) << SIGNIFICAND_SIZE);
70 let new_rhs = rhs * rhs_rescale;
71
72 eq_with_tol_impl(new_lhs, new_rhs, tol)
73 }
74 }
75
76 };
77}
78
79pub(crate) mod f32 {
80 impl_equals!(f32, u32, 23);
81}
82
83
84pub(crate) mod f64 {
85 impl_equals!(f64, u64, 52);
86}