1 #[cfg(feature = "num-complex")]
2 use num_complex::Complex;
3 #[cfg(not(feature = "std"))]
4 use num_traits::float::FloatCore;
5 use std::{cell, mem};
6 
7 use AbsDiffEq;
8 
9 /// Equality comparisons between two numbers using both the absolute difference and ULPs
10 /// (Units in Last Place) based comparisons.
11 pub trait UlpsEq<Rhs = Self>: AbsDiffEq<Rhs>
12 where
13     Rhs: ?Sized,
14 {
15     /// The default ULPs to tolerate when testing values that are far-apart.
16     ///
17     /// This is used when no `max_ulps` value is supplied to the `ulps_eq` macro.
default_max_ulps() -> u3218     fn default_max_ulps() -> u32;
19 
20     /// A test for equality that uses units in the last place (ULP) if the values are far apart.
ulps_eq(&self, other: &Rhs, epsilon: Self::Epsilon, max_ulps: u32) -> bool21     fn ulps_eq(&self, other: &Rhs, epsilon: Self::Epsilon, max_ulps: u32) -> bool;
22 
23     /// The inverse of `ApproxEq::ulps_eq`.
ulps_ne(&self, other: &Rhs, epsilon: Self::Epsilon, max_ulps: u32) -> bool24     fn ulps_ne(&self, other: &Rhs, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
25         !Self::ulps_eq(self, other, epsilon, max_ulps)
26     }
27 }
28 
29 ///////////////////////////////////////////////////////////////////////////////////////////////////
30 // Base implementations
31 ///////////////////////////////////////////////////////////////////////////////////////////////////
32 
33 // Implementation based on: [Comparing Floating Point Numbers, 2012 Edition]
34 // (https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/)
35 macro_rules! impl_ulps_eq {
36     ($T:ident, $U:ident) => {
37         impl UlpsEq for $T {
38             #[inline]
39             fn default_max_ulps() -> u32 {
40                 4
41             }
42 
43             #[inline]
44             fn ulps_eq(&self, other: &$T, epsilon: $T, max_ulps: u32) -> bool {
45                 // For when the numbers are really close together
46                 if $T::abs_diff_eq(self, other, epsilon) {
47                     return true;
48                 }
49 
50                 // Trivial negative sign check
51                 if self.signum() != other.signum() {
52                     return false;
53                 }
54 
55                 // ULPS difference comparison
56                 let int_self: $U = unsafe { mem::transmute(*self) };
57                 let int_other: $U = unsafe { mem::transmute(*other) };
58 
59                 $U::abs(int_self - int_other) <= max_ulps as $U
60             }
61         }
62     };
63 }
64 
65 impl_ulps_eq!(f32, i32);
66 impl_ulps_eq!(f64, i64);
67 
68 ///////////////////////////////////////////////////////////////////////////////////////////////////
69 // Derived implementations
70 ///////////////////////////////////////////////////////////////////////////////////////////////////
71 
72 impl<'a, T: UlpsEq + ?Sized> UlpsEq for &'a T {
73     #[inline]
default_max_ulps() -> u3274     fn default_max_ulps() -> u32 {
75         T::default_max_ulps()
76     }
77 
78     #[inline]
ulps_eq(&self, other: &&'a T, epsilon: T::Epsilon, max_ulps: u32) -> bool79     fn ulps_eq(&self, other: &&'a T, epsilon: T::Epsilon, max_ulps: u32) -> bool {
80         T::ulps_eq(*self, *other, epsilon, max_ulps)
81     }
82 }
83 
84 impl<'a, T: UlpsEq + ?Sized> UlpsEq for &'a mut T {
85     #[inline]
default_max_ulps() -> u3286     fn default_max_ulps() -> u32 {
87         T::default_max_ulps()
88     }
89 
90     #[inline]
ulps_eq(&self, other: &&'a mut T, epsilon: T::Epsilon, max_ulps: u32) -> bool91     fn ulps_eq(&self, other: &&'a mut T, epsilon: T::Epsilon, max_ulps: u32) -> bool {
92         T::ulps_eq(*self, *other, epsilon, max_ulps)
93     }
94 }
95 
96 impl<T: UlpsEq + Copy> UlpsEq for cell::Cell<T> {
97     #[inline]
default_max_ulps() -> u3298     fn default_max_ulps() -> u32 {
99         T::default_max_ulps()
100     }
101 
102     #[inline]
ulps_eq(&self, other: &cell::Cell<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool103     fn ulps_eq(&self, other: &cell::Cell<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool {
104         T::ulps_eq(&self.get(), &other.get(), epsilon, max_ulps)
105     }
106 }
107 
108 impl<T: UlpsEq + ?Sized> UlpsEq for cell::RefCell<T> {
109     #[inline]
default_max_ulps() -> u32110     fn default_max_ulps() -> u32 {
111         T::default_max_ulps()
112     }
113 
114     #[inline]
ulps_eq(&self, other: &cell::RefCell<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool115     fn ulps_eq(&self, other: &cell::RefCell<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool {
116         T::ulps_eq(&self.borrow(), &other.borrow(), epsilon, max_ulps)
117     }
118 }
119 
120 impl<A, B> UlpsEq<[B]> for [A]
121 where
122     A: UlpsEq<B>,
123     A::Epsilon: Clone,
124 {
125     #[inline]
default_max_ulps() -> u32126     fn default_max_ulps() -> u32 {
127         A::default_max_ulps()
128     }
129 
130     #[inline]
ulps_eq(&self, other: &[B], epsilon: A::Epsilon, max_ulps: u32) -> bool131     fn ulps_eq(&self, other: &[B], epsilon: A::Epsilon, max_ulps: u32) -> bool {
132         self.len() == other.len()
133             && Iterator::zip(self.iter(), other)
134                 .all(|(x, y)| A::ulps_eq(x, y, epsilon.clone(), max_ulps.clone()))
135     }
136 }
137 
138 #[cfg(feature = "num-complex")]
139 impl<T: UlpsEq> UlpsEq for Complex<T>
140 where
141     T::Epsilon: Clone,
142 {
143     #[inline]
default_max_ulps() -> u32144     fn default_max_ulps() -> u32 {
145         T::default_max_ulps()
146     }
147 
148     #[inline]
ulps_eq(&self, other: &Complex<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool149     fn ulps_eq(&self, other: &Complex<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool {
150         T::ulps_eq(&self.re, &other.re, epsilon.clone(), max_ulps)
151             && T::ulps_eq(&self.im, &other.im, epsilon.clone(), max_ulps)
152     }
153 }
154