1 #[cfg(feature = "num-complex")] 2 use num_complex::Complex; 3 #[cfg(not(feature = "std"))] 4 use num_traits::float::FloatCore; 5 use std::{cell, mem}; 6 7 use AbsDiffEq; 8 9 /// Equality comparisons between two numbers using both the absolute difference and ULPs 10 /// (Units in Last Place) based comparisons. 11 pub trait UlpsEq<Rhs = Self>: AbsDiffEq<Rhs> 12 where 13 Rhs: ?Sized, 14 { 15 /// The default ULPs to tolerate when testing values that are far-apart. 16 /// 17 /// This is used when no `max_ulps` value is supplied to the `ulps_eq` macro. default_max_ulps() -> u3218 fn default_max_ulps() -> u32; 19 20 /// A test for equality that uses units in the last place (ULP) if the values are far apart. ulps_eq(&self, other: &Rhs, epsilon: Self::Epsilon, max_ulps: u32) -> bool21 fn ulps_eq(&self, other: &Rhs, epsilon: Self::Epsilon, max_ulps: u32) -> bool; 22 23 /// The inverse of `ApproxEq::ulps_eq`. ulps_ne(&self, other: &Rhs, epsilon: Self::Epsilon, max_ulps: u32) -> bool24 fn ulps_ne(&self, other: &Rhs, epsilon: Self::Epsilon, max_ulps: u32) -> bool { 25 !Self::ulps_eq(self, other, epsilon, max_ulps) 26 } 27 } 28 29 /////////////////////////////////////////////////////////////////////////////////////////////////// 30 // Base implementations 31 /////////////////////////////////////////////////////////////////////////////////////////////////// 32 33 // Implementation based on: [Comparing Floating Point Numbers, 2012 Edition] 34 // (https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/) 35 macro_rules! impl_ulps_eq { 36 ($T:ident, $U:ident) => { 37 impl UlpsEq for $T { 38 #[inline] 39 fn default_max_ulps() -> u32 { 40 4 41 } 42 43 #[inline] 44 fn ulps_eq(&self, other: &$T, epsilon: $T, max_ulps: u32) -> bool { 45 // For when the numbers are really close together 46 if $T::abs_diff_eq(self, other, epsilon) { 47 return true; 48 } 49 50 // Trivial negative sign check 51 if self.signum() != other.signum() { 52 return false; 53 } 54 55 // ULPS difference comparison 56 let int_self: $U = unsafe { mem::transmute(*self) }; 57 let int_other: $U = unsafe { mem::transmute(*other) }; 58 59 $U::abs(int_self - int_other) <= max_ulps as $U 60 } 61 } 62 }; 63 } 64 65 impl_ulps_eq!(f32, i32); 66 impl_ulps_eq!(f64, i64); 67 68 /////////////////////////////////////////////////////////////////////////////////////////////////// 69 // Derived implementations 70 /////////////////////////////////////////////////////////////////////////////////////////////////// 71 72 impl<'a, T: UlpsEq + ?Sized> UlpsEq for &'a T { 73 #[inline] default_max_ulps() -> u3274 fn default_max_ulps() -> u32 { 75 T::default_max_ulps() 76 } 77 78 #[inline] ulps_eq(&self, other: &&'a T, epsilon: T::Epsilon, max_ulps: u32) -> bool79 fn ulps_eq(&self, other: &&'a T, epsilon: T::Epsilon, max_ulps: u32) -> bool { 80 T::ulps_eq(*self, *other, epsilon, max_ulps) 81 } 82 } 83 84 impl<'a, T: UlpsEq + ?Sized> UlpsEq for &'a mut T { 85 #[inline] default_max_ulps() -> u3286 fn default_max_ulps() -> u32 { 87 T::default_max_ulps() 88 } 89 90 #[inline] ulps_eq(&self, other: &&'a mut T, epsilon: T::Epsilon, max_ulps: u32) -> bool91 fn ulps_eq(&self, other: &&'a mut T, epsilon: T::Epsilon, max_ulps: u32) -> bool { 92 T::ulps_eq(*self, *other, epsilon, max_ulps) 93 } 94 } 95 96 impl<T: UlpsEq + Copy> UlpsEq for cell::Cell<T> { 97 #[inline] default_max_ulps() -> u3298 fn default_max_ulps() -> u32 { 99 T::default_max_ulps() 100 } 101 102 #[inline] ulps_eq(&self, other: &cell::Cell<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool103 fn ulps_eq(&self, other: &cell::Cell<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool { 104 T::ulps_eq(&self.get(), &other.get(), epsilon, max_ulps) 105 } 106 } 107 108 impl<T: UlpsEq + ?Sized> UlpsEq for cell::RefCell<T> { 109 #[inline] default_max_ulps() -> u32110 fn default_max_ulps() -> u32 { 111 T::default_max_ulps() 112 } 113 114 #[inline] ulps_eq(&self, other: &cell::RefCell<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool115 fn ulps_eq(&self, other: &cell::RefCell<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool { 116 T::ulps_eq(&self.borrow(), &other.borrow(), epsilon, max_ulps) 117 } 118 } 119 120 impl<A, B> UlpsEq<[B]> for [A] 121 where 122 A: UlpsEq<B>, 123 A::Epsilon: Clone, 124 { 125 #[inline] default_max_ulps() -> u32126 fn default_max_ulps() -> u32 { 127 A::default_max_ulps() 128 } 129 130 #[inline] ulps_eq(&self, other: &[B], epsilon: A::Epsilon, max_ulps: u32) -> bool131 fn ulps_eq(&self, other: &[B], epsilon: A::Epsilon, max_ulps: u32) -> bool { 132 self.len() == other.len() 133 && Iterator::zip(self.iter(), other) 134 .all(|(x, y)| A::ulps_eq(x, y, epsilon.clone(), max_ulps.clone())) 135 } 136 } 137 138 #[cfg(feature = "num-complex")] 139 impl<T: UlpsEq> UlpsEq for Complex<T> 140 where 141 T::Epsilon: Clone, 142 { 143 #[inline] default_max_ulps() -> u32144 fn default_max_ulps() -> u32 { 145 T::default_max_ulps() 146 } 147 148 #[inline] ulps_eq(&self, other: &Complex<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool149 fn ulps_eq(&self, other: &Complex<T>, epsilon: T::Epsilon, max_ulps: u32) -> bool { 150 T::ulps_eq(&self.re, &other.re, epsilon.clone(), max_ulps) 151 && T::ulps_eq(&self.im, &other.im, epsilon.clone(), max_ulps) 152 } 153 } 154