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