1use core::cell;
2#[cfg(feature = "num-complex")]
3use num_complex::Complex;
4use num_traits::Signed;
5
6use AbsDiffEq;
7
8pub trait UlpsEq<Rhs = Self>: AbsDiffEq<Rhs>
11where
12 Rhs: ?Sized,
13{
14 fn default_max_ulps() -> u32;
18
19 fn ulps_eq(&self, other: &Rhs, epsilon: Self::Epsilon, max_ulps: u32) -> bool;
21
22 fn ulps_ne(&self, other: &Rhs, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
24 !Self::ulps_eq(self, other, epsilon, max_ulps)
25 }
26}
27
28macro_rules! impl_ulps_eq {
35 ($T:ident, $U:ident) => {
36 impl UlpsEq for $T {
37 #[inline]
38 fn default_max_ulps() -> u32 {
39 4
40 }
41
42 #[inline]
43 fn ulps_eq(&self, other: &$T, epsilon: $T, max_ulps: u32) -> bool {
44 if $T::abs_diff_eq(self, other, epsilon) {
46 return true;
47 }
48
49 if self.signum() != other.signum() {
51 return false;
52 }
53
54 let int_self: $U = self.to_bits();
56 let int_other: $U = other.to_bits();
57
58 if int_self <= int_other {
61 int_other - int_self <= max_ulps as $U
62 } else {
63 int_self - int_other <= max_ulps as $U
64 }
65 }
66 }
67 };
68}
69
70impl_ulps_eq!(f32, u32);
71impl_ulps_eq!(f64, u64);
72
73impl<'a, T: UlpsEq + ?Sized> UlpsEq for &'a T {
78 #[inline]
79 fn default_max_ulps() -> u32 {
80 T::default_max_ulps()
81 }
82
83 #[inline]
84 fn ulps_eq(&self, other: &&'a T, epsilon: T::Epsilon, max_ulps: u32) -> bool {
85 T::ulps_eq(*self, *other, epsilon, max_ulps)
86 }
87}
88
89impl<'a, T: UlpsEq + ?Sized> UlpsEq for &'a mut T {
90 #[inline]
91 fn default_max_ulps() -> u32 {
92 T::default_max_ulps()
93 }
94
95 #[inline]
96 fn ulps_eq(&self, other: &&'a mut T, epsilon: T::Epsilon, max_ulps: u32) -> bool {
97 T::ulps_eq(*self, *other, epsilon, max_ulps)
98 }
99}
100
101impl<T: UlpsEq + Copy> UlpsEq for cell::Cell<T> {
102 #[inline]
103 fn default_max_ulps() -> u32 {
104 T::default_max_ulps()
105 }
106
107 #[inline]
108 fn ulps_eq(&self, other: &cell::Cell<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool {
109 T::ulps_eq(&self.get(), &other.get(), epsilon, max_ulps)
110 }
111}
112
113impl<T: UlpsEq + ?Sized> UlpsEq for cell::RefCell<T> {
114 #[inline]
115 fn default_max_ulps() -> u32 {
116 T::default_max_ulps()
117 }
118
119 #[inline]
120 fn ulps_eq(&self, other: &cell::RefCell<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool {
121 T::ulps_eq(&self.borrow(), &other.borrow(), epsilon, max_ulps)
122 }
123}
124
125impl<A, B> UlpsEq<[B]> for [A]
126where
127 A: UlpsEq<B>,
128 A::Epsilon: Clone,
129{
130 #[inline]
131 fn default_max_ulps() -> u32 {
132 A::default_max_ulps()
133 }
134
135 #[inline]
136 fn ulps_eq(&self, other: &[B], epsilon: A::Epsilon, max_ulps: u32) -> bool {
137 self.len() == other.len()
138 && Iterator::zip(self.iter(), other)
139 .all(|(x, y)| A::ulps_eq(x, y, epsilon.clone(), max_ulps))
140 }
141}
142
143#[cfg(feature = "num-complex")]
144impl<T: UlpsEq> UlpsEq for Complex<T>
145where
146 T::Epsilon: Clone,
147{
148 #[inline]
149 fn default_max_ulps() -> u32 {
150 T::default_max_ulps()
151 }
152
153 #[inline]
154 fn ulps_eq(&self, other: &Complex<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool {
155 T::ulps_eq(&self.re, &other.re, epsilon.clone(), max_ulps)
156 && T::ulps_eq(&self.im, &other.im, epsilon, max_ulps)
157 }
158}