1 // Copyright 2015 Brendan Zabarauskas
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! A crate that provides facilities for testing the approximate equality of floating-point
16 //! based types, using either relative difference, or units in the last place (ULPs)
17 //! comparisons.
18 //!
19 //! You can also use the `*_{eq, ne}!` and `assert_*_{eq, ne}!` macros to test for equality using a
20 //! more positional style:
21 //!
22 //! ```rust
23 //! #[macro_use]
24 //! extern crate approx;
25 //!
26 //! use std::f64;
27 //!
28 //! # fn main() {
29 //! abs_diff_eq!(1.0, 1.0);
30 //! abs_diff_eq!(1.0, 1.0, epsilon = f64::EPSILON);
31 //!
32 //! relative_eq!(1.0, 1.0);
33 //! relative_eq!(1.0, 1.0, epsilon = f64::EPSILON);
34 //! relative_eq!(1.0, 1.0, max_relative = 1.0);
35 //! relative_eq!(1.0, 1.0, epsilon = f64::EPSILON, max_relative = 1.0);
36 //! relative_eq!(1.0, 1.0, max_relative = 1.0, epsilon = f64::EPSILON);
37 //!
38 //! ulps_eq!(1.0, 1.0);
39 //! ulps_eq!(1.0, 1.0, epsilon = f64::EPSILON);
40 //! ulps_eq!(1.0, 1.0, max_ulps = 4);
41 //! ulps_eq!(1.0, 1.0, epsilon = f64::EPSILON, max_ulps = 4);
42 //! ulps_eq!(1.0, 1.0, max_ulps = 4, epsilon = f64::EPSILON);
43 //! # }
44 //! ```
45 //!
46 //! # Implementing approximate equality for custom types
47 //!
48 //! The `*Eq` traits allow approximate equalities to be implemented on types, based on the
49 //! fundamental floating point implementations.
50 //!
51 //! For example, we might want to be able to do approximate assertions on a complex number type:
52 //!
53 //! ```rust
54 //! #[macro_use]
55 //! extern crate approx;
56 //! # use approx::{AbsDiffEq, RelativeEq, UlpsEq};
57 //!
58 //! #[derive(Debug, PartialEq)]
59 //! struct Complex<T> {
60 //!     x: T,
61 //!     i: T,
62 //! }
63 //! # impl<T: AbsDiffEq> AbsDiffEq for Complex<T> where T::Epsilon: Copy {
64 //! #     type Epsilon = T::Epsilon;
65 //! #     fn default_epsilon() -> T::Epsilon { T::default_epsilon() }
66 //! #     fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
67 //! #         T::abs_diff_eq(&self.x, &other.x, epsilon) &&
68 //! #         T::abs_diff_eq(&self.i, &other.i, epsilon)
69 //! #     }
70 //! # }
71 //! # impl<T: RelativeEq> RelativeEq for Complex<T> where T::Epsilon: Copy {
72 //! #     fn default_max_relative() -> T::Epsilon { T::default_max_relative() }
73 //! #     fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon)
74 //! #                   -> bool {
75 //! #         T::relative_eq(&self.x, &other.x, epsilon, max_relative) &&
76 //! #         T::relative_eq(&self.i, &other.i, epsilon, max_relative)
77 //! #     }
78 //! # }
79 //! # impl<T: UlpsEq> UlpsEq for Complex<T> where T::Epsilon: Copy {
80 //! #     fn default_max_ulps() -> u32 { T::default_max_ulps() }
81 //! #     fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool {
82 //! #         T::ulps_eq(&self.x, &other.x, epsilon, max_ulps) &&
83 //! #         T::ulps_eq(&self.i, &other.i, epsilon, max_ulps)
84 //! #     }
85 //! # }
86 //!
87 //! # fn main() {
88 //! let x = Complex { x: 1.2, i: 2.3 };
89 //!
90 //! assert_relative_eq!(x, x);
91 //! assert_ulps_eq!(x, x, max_ulps = 4);
92 //! # }
93 //! ```
94 //!
95 //! To do this we can implement [`AbsDiffEq`], [`RelativeEq`] and [`UlpsEq`] generically in terms
96 //! of a type parameter that also implements `AbsDiffEq`, `RelativeEq` and `UlpsEq` respectively.
97 //! This means that we can make comparisons for either `Complex<f32>` or `Complex<f64>`:
98 //!
99 //! ```rust
100 //! # use approx::{AbsDiffEq, RelativeEq, UlpsEq};
101 //! # #[derive(Debug, PartialEq)]
102 //! # struct Complex<T> { x: T, i: T, }
103 //! #
104 //! impl<T: AbsDiffEq> AbsDiffEq for Complex<T> where
105 //!     T::Epsilon: Copy,
106 //! {
107 //!     type Epsilon = T::Epsilon;
108 //!
109 //!     fn default_epsilon() -> T::Epsilon {
110 //!         T::default_epsilon()
111 //!     }
112 //!
113 //!     fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
114 //!         T::abs_diff_eq(&self.x, &other.x, epsilon) &&
115 //!         T::abs_diff_eq(&self.i, &other.i, epsilon)
116 //!     }
117 //! }
118 //!
119 //! impl<T: RelativeEq> RelativeEq for Complex<T> where
120 //!     T::Epsilon: Copy,
121 //! {
122 //!     fn default_max_relative() -> T::Epsilon {
123 //!         T::default_max_relative()
124 //!     }
125 //!
126 //!     fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool {
127 //!         T::relative_eq(&self.x, &other.x, epsilon, max_relative) &&
128 //!         T::relative_eq(&self.i, &other.i, epsilon, max_relative)
129 //!     }
130 //! }
131 //!
132 //! impl<T: UlpsEq> UlpsEq for Complex<T> where
133 //!     T::Epsilon: Copy,
134 //! {
135 //!     fn default_max_ulps() -> u32 {
136 //!         T::default_max_ulps()
137 //!     }
138 //!
139 //!     fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool {
140 //!         T::ulps_eq(&self.x, &other.x, epsilon, max_ulps) &&
141 //!         T::ulps_eq(&self.i, &other.i, epsilon, max_ulps)
142 //!     }
143 //! }
144 //! ```
145 //!
146 //! # References
147 //!
148 //! Floating point is hard! Thanks goes to these links for helping to make things a _little_
149 //! easier to understand:
150 //!
151 //! - [Comparing Floating Point Numbers, 2012 Edition](
152 //!   https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/)
153 //! - [The Floating Point Guide - Comparison](http://floating-point-gui.de/errors/comparison/)
154 //! - [What Every Computer Scientist Should Know About Floating-Point Arithmetic](
155 //!   https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)
156 
157 #![no_std]
158 #![allow(clippy::transmute_float_to_int)]
159 
160 #[cfg(feature = "num-complex")]
161 extern crate num_complex;
162 extern crate num_traits;
163 
164 mod abs_diff_eq;
165 mod relative_eq;
166 mod ulps_eq;
167 
168 mod macros;
169 
170 pub use abs_diff_eq::AbsDiffEq;
171 pub use relative_eq::RelativeEq;
172 pub use ulps_eq::UlpsEq;
173 
174 /// The requisite parameters for testing for approximate equality using a
175 /// absolute difference based comparison.
176 ///
177 /// This is not normally used directly, rather via the
178 /// `assert_abs_diff_{eq|ne}!` and `abs_diff_{eq|ne}!` macros.
179 ///
180 /// # Example
181 ///
182 /// ```rust
183 /// use std::f64;
184 /// use approx::AbsDiff;
185 ///
186 /// AbsDiff::default().eq(&1.0, &1.0);
187 /// AbsDiff::default().epsilon(f64::EPSILON).eq(&1.0, &1.0);
188 /// ```
189 pub struct AbsDiff<A, B = A>
190 where
191     A: AbsDiffEq<B> + ?Sized,
192     B: ?Sized,
193 {
194     /// The tolerance to use when testing values that are close together.
195     pub epsilon: A::Epsilon,
196 }
197 
198 impl<A, B> Default for AbsDiff<A, B>
199 where
200     A: AbsDiffEq<B> + ?Sized,
201     B: ?Sized,
202 {
203     #[inline]
default() -> AbsDiff<A, B>204     fn default() -> AbsDiff<A, B> {
205         AbsDiff {
206             epsilon: A::default_epsilon(),
207         }
208     }
209 }
210 
211 impl<A, B> AbsDiff<A, B>
212 where
213     A: AbsDiffEq<B> + ?Sized,
214     B: ?Sized,
215 {
216     /// Replace the epsilon value with the one specified.
217     #[inline]
epsilon(self, epsilon: A::Epsilon) -> AbsDiff<A, B>218     pub fn epsilon(self, epsilon: A::Epsilon) -> AbsDiff<A, B> {
219         AbsDiff { epsilon }
220     }
221 
222     /// Peform the equality comparison
223     #[inline]
224     #[must_use]
eq(self, lhs: &A, rhs: &B) -> bool225     pub fn eq(self, lhs: &A, rhs: &B) -> bool {
226         A::abs_diff_eq(lhs, rhs, self.epsilon)
227     }
228 
229     /// Peform the inequality comparison
230     #[inline]
231     #[must_use]
ne(self, lhs: &A, rhs: &B) -> bool232     pub fn ne(self, lhs: &A, rhs: &B) -> bool {
233         A::abs_diff_ne(lhs, rhs, self.epsilon)
234     }
235 }
236 
237 /// The requisite parameters for testing for approximate equality using a
238 /// relative based comparison.
239 ///
240 /// This is not normally used directly, rather via the
241 /// `assert_relative_{eq|ne}!` and `relative_{eq|ne}!` macros.
242 ///
243 /// # Example
244 ///
245 /// ```rust
246 /// use std::f64;
247 /// use approx::Relative;
248 ///
249 /// Relative::default().eq(&1.0, &1.0);
250 /// Relative::default().epsilon(f64::EPSILON).eq(&1.0, &1.0);
251 /// Relative::default().max_relative(1.0).eq(&1.0, &1.0);
252 /// Relative::default().epsilon(f64::EPSILON).max_relative(1.0).eq(&1.0, &1.0);
253 /// Relative::default().max_relative(1.0).epsilon(f64::EPSILON).eq(&1.0, &1.0);
254 /// ```
255 pub struct Relative<A, B = A>
256 where
257     A: RelativeEq<B> + ?Sized,
258     B: ?Sized,
259 {
260     /// The tolerance to use when testing values that are close together.
261     pub epsilon: A::Epsilon,
262     /// The relative tolerance for testing values that are far-apart.
263     pub max_relative: A::Epsilon,
264 }
265 
266 impl<A, B> Default for Relative<A, B>
267 where
268     A: RelativeEq<B> + ?Sized,
269     B: ?Sized,
270 {
271     #[inline]
default() -> Relative<A, B>272     fn default() -> Relative<A, B> {
273         Relative {
274             epsilon: A::default_epsilon(),
275             max_relative: A::default_max_relative(),
276         }
277     }
278 }
279 
280 impl<A, B> Relative<A, B>
281 where
282     A: RelativeEq<B> + ?Sized,
283     B: ?Sized,
284 {
285     /// Replace the epsilon value with the one specified.
286     #[inline]
epsilon(self, epsilon: A::Epsilon) -> Relative<A, B>287     pub fn epsilon(self, epsilon: A::Epsilon) -> Relative<A, B> {
288         Relative { epsilon, ..self }
289     }
290 
291     /// Replace the maximum relative value with the one specified.
292     #[inline]
max_relative(self, max_relative: A::Epsilon) -> Relative<A, B>293     pub fn max_relative(self, max_relative: A::Epsilon) -> Relative<A, B> {
294         Relative {
295             max_relative,
296             ..self
297         }
298     }
299 
300     /// Peform the equality comparison
301     #[inline]
302     #[must_use]
eq(self, lhs: &A, rhs: &B) -> bool303     pub fn eq(self, lhs: &A, rhs: &B) -> bool {
304         A::relative_eq(lhs, rhs, self.epsilon, self.max_relative)
305     }
306 
307     /// Peform the inequality comparison
308     #[inline]
309     #[must_use]
ne(self, lhs: &A, rhs: &B) -> bool310     pub fn ne(self, lhs: &A, rhs: &B) -> bool {
311         A::relative_ne(lhs, rhs, self.epsilon, self.max_relative)
312     }
313 }
314 
315 /// The requisite parameters for testing for approximate equality using an ULPs
316 /// based comparison.
317 ///
318 /// This is not normally used directly, rather via the `assert_ulps_{eq|ne}!`
319 /// and `ulps_{eq|ne}!` macros.
320 ///
321 /// # Example
322 ///
323 /// ```rust
324 /// use std::f64;
325 /// use approx::Ulps;
326 ///
327 /// Ulps::default().eq(&1.0, &1.0);
328 /// Ulps::default().epsilon(f64::EPSILON).eq(&1.0, &1.0);
329 /// Ulps::default().max_ulps(4).eq(&1.0, &1.0);
330 /// Ulps::default().epsilon(f64::EPSILON).max_ulps(4).eq(&1.0, &1.0);
331 /// Ulps::default().max_ulps(4).epsilon(f64::EPSILON).eq(&1.0, &1.0);
332 /// ```
333 pub struct Ulps<A, B = A>
334 where
335     A: UlpsEq<B> + ?Sized,
336     B: ?Sized,
337 {
338     /// The tolerance to use when testing values that are close together.
339     pub epsilon: A::Epsilon,
340     /// The ULPs to tolerate when testing values that are far-apart.
341     pub max_ulps: u32,
342 }
343 
344 impl<A, B> Default for Ulps<A, B>
345 where
346     A: UlpsEq<B> + ?Sized,
347     B: ?Sized,
348 {
349     #[inline]
default() -> Ulps<A, B>350     fn default() -> Ulps<A, B> {
351         Ulps {
352             epsilon: A::default_epsilon(),
353             max_ulps: A::default_max_ulps(),
354         }
355     }
356 }
357 
358 impl<A, B> Ulps<A, B>
359 where
360     A: UlpsEq<B> + ?Sized,
361     B: ?Sized,
362 {
363     /// Replace the epsilon value with the one specified.
364     #[inline]
epsilon(self, epsilon: A::Epsilon) -> Ulps<A, B>365     pub fn epsilon(self, epsilon: A::Epsilon) -> Ulps<A, B> {
366         Ulps { epsilon, ..self }
367     }
368 
369     /// Replace the max ulps value with the one specified.
370     #[inline]
max_ulps(self, max_ulps: u32) -> Ulps<A, B>371     pub fn max_ulps(self, max_ulps: u32) -> Ulps<A, B> {
372         Ulps { max_ulps, ..self }
373     }
374 
375     /// Peform the equality comparison
376     #[inline]
377     #[must_use]
eq(self, lhs: &A, rhs: &B) -> bool378     pub fn eq(self, lhs: &A, rhs: &B) -> bool {
379         A::ulps_eq(lhs, rhs, self.epsilon, self.max_ulps)
380     }
381 
382     /// Peform the inequality comparison
383     #[inline]
384     #[must_use]
ne(self, lhs: &A, rhs: &B) -> bool385     pub fn ne(self, lhs: &A, rhs: &B) -> bool {
386         A::ulps_ne(lhs, rhs, self.epsilon, self.max_ulps)
387     }
388 }
389