1use core::{cell, f32, f64};
2#[cfg(feature = "num-complex")]
3use num_complex::Complex;
4use AbsDiffEq;
5
6pub trait RelativeEq<Rhs = Self>: AbsDiffEq<Rhs>
9where
10 Rhs: ?Sized,
11{
12 fn default_max_relative() -> Self::Epsilon;
16
17 fn relative_eq(&self, other: &Rhs, epsilon: Self::Epsilon, max_relative: Self::Epsilon)
19 -> bool;
20
21 fn relative_ne(
23 &self,
24 other: &Rhs,
25 epsilon: Self::Epsilon,
26 max_relative: Self::Epsilon,
27 ) -> bool {
28 !Self::relative_eq(self, other, epsilon, max_relative)
29 }
30}
31
32macro_rules! impl_relative_eq {
39 ($T:ident, $U:ident) => {
40 impl RelativeEq for $T {
41 #[inline]
42 fn default_max_relative() -> $T {
43 $T::EPSILON
44 }
45
46 #[inline]
47 #[allow(unused_imports)]
48 fn relative_eq(&self, other: &$T, epsilon: $T, max_relative: $T) -> bool {
49 use num_traits::float::FloatCore;
50 if self == other {
52 return true;
53 }
54
55 if $T::is_infinite(*self) || $T::is_infinite(*other) {
57 return false;
58 }
59
60 let abs_diff = $T::abs(self - other);
61
62 if abs_diff <= epsilon {
64 return true;
65 }
66
67 let abs_self = $T::abs(*self);
68 let abs_other = $T::abs(*other);
69
70 let largest = if abs_other > abs_self {
71 abs_other
72 } else {
73 abs_self
74 };
75
76 abs_diff <= largest * max_relative
78 }
79 }
80 };
81}
82
83impl_relative_eq!(f32, i32);
84impl_relative_eq!(f64, i64);
85
86impl<'a, T: RelativeEq + ?Sized> RelativeEq for &'a T {
91 #[inline]
92 fn default_max_relative() -> T::Epsilon {
93 T::default_max_relative()
94 }
95
96 #[inline]
97 fn relative_eq(&self, other: &&'a T, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool {
98 T::relative_eq(*self, *other, epsilon, max_relative)
99 }
100}
101
102impl<'a, T: RelativeEq + ?Sized> RelativeEq for &'a mut T {
103 #[inline]
104 fn default_max_relative() -> T::Epsilon {
105 T::default_max_relative()
106 }
107
108 #[inline]
109 fn relative_eq(
110 &self,
111 other: &&'a mut T,
112 epsilon: T::Epsilon,
113 max_relative: T::Epsilon,
114 ) -> bool {
115 T::relative_eq(*self, *other, epsilon, max_relative)
116 }
117}
118
119impl<T: RelativeEq + Copy> RelativeEq for cell::Cell<T> {
120 #[inline]
121 fn default_max_relative() -> T::Epsilon {
122 T::default_max_relative()
123 }
124
125 #[inline]
126 fn relative_eq(
127 &self,
128 other: &cell::Cell<T>,
129 epsilon: T::Epsilon,
130 max_relative: T::Epsilon,
131 ) -> bool {
132 T::relative_eq(&self.get(), &other.get(), epsilon, max_relative)
133 }
134}
135
136impl<T: RelativeEq + ?Sized> RelativeEq for cell::RefCell<T> {
137 #[inline]
138 fn default_max_relative() -> T::Epsilon {
139 T::default_max_relative()
140 }
141
142 #[inline]
143 fn relative_eq(
144 &self,
145 other: &cell::RefCell<T>,
146 epsilon: T::Epsilon,
147 max_relative: T::Epsilon,
148 ) -> bool {
149 T::relative_eq(&self.borrow(), &other.borrow(), epsilon, max_relative)
150 }
151}
152
153impl<A, B> RelativeEq<[B]> for [A]
154where
155 A: RelativeEq<B>,
156 A::Epsilon: Clone,
157{
158 #[inline]
159 fn default_max_relative() -> A::Epsilon {
160 A::default_max_relative()
161 }
162
163 #[inline]
164 fn relative_eq(&self, other: &[B], epsilon: A::Epsilon, max_relative: A::Epsilon) -> bool {
165 self.len() == other.len()
166 && Iterator::zip(self.iter(), other)
167 .all(|(x, y)| A::relative_eq(x, y, epsilon.clone(), max_relative.clone()))
168 }
169}
170
171#[cfg(feature = "num-complex")]
172impl<T: RelativeEq> RelativeEq for Complex<T>
173where
174 T::Epsilon: Clone,
175{
176 #[inline]
177 fn default_max_relative() -> T::Epsilon {
178 T::default_max_relative()
179 }
180
181 #[inline]
182 fn relative_eq(
183 &self,
184 other: &Complex<T>,
185 epsilon: T::Epsilon,
186 max_relative: T::Epsilon,
187 ) -> bool {
188 T::relative_eq(&self.re, &other.re, epsilon.clone(), max_relative.clone())
189 && T::relative_eq(&self.im, &other.im, epsilon, max_relative)
190 }
191}