approx/
lib.rs

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")]
161extern crate num_complex;
162extern crate num_traits;
163
164mod abs_diff_eq;
165mod relative_eq;
166mod ulps_eq;
167
168mod macros;
169
170pub use abs_diff_eq::AbsDiffEq;
171pub use relative_eq::RelativeEq;
172pub 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/// ```
189pub struct AbsDiff<A, B = A>
190where
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
198impl<A, B> Default for AbsDiff<A, B>
199where
200    A: AbsDiffEq<B> + ?Sized,
201    B: ?Sized,
202{
203    #[inline]
204    fn default() -> AbsDiff<A, B> {
205        AbsDiff {
206            epsilon: A::default_epsilon(),
207        }
208    }
209}
210
211impl<A, B> AbsDiff<A, B>
212where
213    A: AbsDiffEq<B> + ?Sized,
214    B: ?Sized,
215{
216    /// Replace the epsilon value with the one specified.
217    #[inline]
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]
225    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]
232    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/// ```
255pub struct Relative<A, B = A>
256where
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
266impl<A, B> Default for Relative<A, B>
267where
268    A: RelativeEq<B> + ?Sized,
269    B: ?Sized,
270{
271    #[inline]
272    fn default() -> Relative<A, B> {
273        Relative {
274            epsilon: A::default_epsilon(),
275            max_relative: A::default_max_relative(),
276        }
277    }
278}
279
280impl<A, B> Relative<A, B>
281where
282    A: RelativeEq<B> + ?Sized,
283    B: ?Sized,
284{
285    /// Replace the epsilon value with the one specified.
286    #[inline]
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]
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]
303    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]
310    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/// ```
333pub struct Ulps<A, B = A>
334where
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
344impl<A, B> Default for Ulps<A, B>
345where
346    A: UlpsEq<B> + ?Sized,
347    B: ?Sized,
348{
349    #[inline]
350    fn default() -> Ulps<A, B> {
351        Ulps {
352            epsilon: A::default_epsilon(),
353            max_ulps: A::default_max_ulps(),
354        }
355    }
356}
357
358impl<A, B> Ulps<A, B>
359where
360    A: UlpsEq<B> + ?Sized,
361    B: ?Sized,
362{
363    /// Replace the epsilon value with the one specified.
364    #[inline]
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]
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]
378    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]
385    pub fn ne(self, lhs: &A, rhs: &B) -> bool {
386        A::ulps_ne(lhs, rhs, self.epsilon, self.max_ulps)
387    }
388}