1 use core::ops::{Div, Rem}; 2 3 pub trait Euclid: Sized + Div<Self, Output = Self> + Rem<Self, Output = Self> { 4 /// Calculates Euclidean division, the matching method for `rem_euclid`. 5 /// 6 /// This computes the integer `n` such that 7 /// `self = n * v + self.rem_euclid(v)`. 8 /// In other words, the result is `self / v` rounded to the integer `n` 9 /// such that `self >= n * v`. 10 /// 11 /// # Examples 12 /// 13 /// ``` 14 /// use num_traits::Euclid; 15 /// 16 /// let a: i32 = 7; 17 /// let b: i32 = 4; 18 /// assert_eq!(Euclid::div_euclid(&a, &b), 1); // 7 > 4 * 1 19 /// assert_eq!(Euclid::div_euclid(&-a, &b), -2); // -7 >= 4 * -2 20 /// assert_eq!(Euclid::div_euclid(&a, &-b), -1); // 7 >= -4 * -1 21 /// assert_eq!(Euclid::div_euclid(&-a, &-b), 2); // -7 >= -4 * 2 22 /// ``` div_euclid(&self, v: &Self) -> Self23 fn div_euclid(&self, v: &Self) -> Self; 24 25 /// Calculates the least nonnegative remainder of `self (mod v)`. 26 /// 27 /// In particular, the return value `r` satisfies `0.0 <= r < v.abs()` in 28 /// most cases. However, due to a floating point round-off error it can 29 /// result in `r == v.abs()`, violating the mathematical definition, if 30 /// `self` is much smaller than `v.abs()` in magnitude and `self < 0.0`. 31 /// This result is not an element of the function's codomain, but it is the 32 /// closest floating point number in the real numbers and thus fulfills the 33 /// property `self == self.div_euclid(v) * v + self.rem_euclid(v)` 34 /// approximatively. 35 /// 36 /// # Examples 37 /// 38 /// ``` 39 /// use num_traits::Euclid; 40 /// 41 /// let a: i32 = 7; 42 /// let b: i32 = 4; 43 /// assert_eq!(Euclid::rem_euclid(&a, &b), 3); 44 /// assert_eq!(Euclid::rem_euclid(&-a, &b), 1); 45 /// assert_eq!(Euclid::rem_euclid(&a, &-b), 3); 46 /// assert_eq!(Euclid::rem_euclid(&-a, &-b), 1); 47 /// ``` rem_euclid(&self, v: &Self) -> Self48 fn rem_euclid(&self, v: &Self) -> Self; 49 } 50 51 macro_rules! euclid_forward_impl { 52 ($($t:ty)*) => {$( 53 #[cfg(has_div_euclid)] 54 impl Euclid for $t { 55 #[inline] 56 fn div_euclid(&self, v: &$t) -> Self { 57 <$t>::div_euclid(*self, *v) 58 } 59 60 #[inline] 61 fn rem_euclid(&self, v: &$t) -> Self { 62 <$t>::rem_euclid(*self, *v) 63 } 64 } 65 )*} 66 } 67 68 macro_rules! euclid_int_impl { 69 ($($t:ty)*) => {$( 70 euclid_forward_impl!($t); 71 72 #[cfg(not(has_div_euclid))] 73 impl Euclid for $t { 74 #[inline] 75 fn div_euclid(&self, v: &$t) -> Self { 76 let q = self / v; 77 if self % v < 0 { 78 return if *v > 0 { q - 1 } else { q + 1 } 79 } 80 q 81 } 82 83 #[inline] 84 fn rem_euclid(&self, v: &$t) -> Self { 85 let r = self % v; 86 if r < 0 { 87 if *v < 0 { 88 r - v 89 } else { 90 r + v 91 } 92 } else { 93 r 94 } 95 } 96 } 97 )*} 98 } 99 100 macro_rules! euclid_uint_impl { 101 ($($t:ty)*) => {$( 102 euclid_forward_impl!($t); 103 104 #[cfg(not(has_div_euclid))] 105 impl Euclid for $t { 106 #[inline] 107 fn div_euclid(&self, v: &$t) -> Self { 108 self / v 109 } 110 111 #[inline] 112 fn rem_euclid(&self, v: &$t) -> Self { 113 self % v 114 } 115 } 116 )*} 117 } 118 119 euclid_int_impl!(isize i8 i16 i32 i64 i128); 120 euclid_uint_impl!(usize u8 u16 u32 u64 u128); 121 122 #[cfg(all(has_div_euclid, feature = "std"))] 123 euclid_forward_impl!(f32 f64); 124 125 #[cfg(not(all(has_div_euclid, feature = "std")))] 126 impl Euclid for f32 { 127 #[inline] div_euclid(&self, v: &f32) -> f32128 fn div_euclid(&self, v: &f32) -> f32 { 129 let q = <f32 as crate::float::FloatCore>::trunc(self / v); 130 if self % v < 0.0 { 131 return if *v > 0.0 { q - 1.0 } else { q + 1.0 }; 132 } 133 q 134 } 135 136 #[inline] rem_euclid(&self, v: &f32) -> f32137 fn rem_euclid(&self, v: &f32) -> f32 { 138 let r = self % v; 139 if r < 0.0 { 140 r + <f32 as crate::float::FloatCore>::abs(*v) 141 } else { 142 r 143 } 144 } 145 } 146 147 #[cfg(not(all(has_div_euclid, feature = "std")))] 148 impl Euclid for f64 { 149 #[inline] div_euclid(&self, v: &f64) -> f64150 fn div_euclid(&self, v: &f64) -> f64 { 151 let q = <f64 as crate::float::FloatCore>::trunc(self / v); 152 if self % v < 0.0 { 153 return if *v > 0.0 { q - 1.0 } else { q + 1.0 }; 154 } 155 q 156 } 157 158 #[inline] rem_euclid(&self, v: &f64) -> f64159 fn rem_euclid(&self, v: &f64) -> f64 { 160 let r = self % v; 161 if r < 0.0 { 162 r + <f64 as crate::float::FloatCore>::abs(*v) 163 } else { 164 r 165 } 166 } 167 } 168 169 pub trait CheckedEuclid: Euclid { 170 /// Performs euclid division that returns `None` instead of panicking on division by zero 171 /// and instead of wrapping around on underflow and overflow. checked_div_euclid(&self, v: &Self) -> Option<Self>172 fn checked_div_euclid(&self, v: &Self) -> Option<Self>; 173 174 /// Finds the euclid remainder of dividing two numbers, checking for underflow, overflow and 175 /// division by zero. If any of that happens, `None` is returned. checked_rem_euclid(&self, v: &Self) -> Option<Self>176 fn checked_rem_euclid(&self, v: &Self) -> Option<Self>; 177 } 178 179 macro_rules! checked_euclid_forward_impl { 180 ($($t:ty)*) => {$( 181 #[cfg(has_div_euclid)] 182 impl CheckedEuclid for $t { 183 #[inline] 184 fn checked_div_euclid(&self, v: &$t) -> Option<Self> { 185 <$t>::checked_div_euclid(*self, *v) 186 } 187 188 #[inline] 189 fn checked_rem_euclid(&self, v: &$t) -> Option<Self> { 190 <$t>::checked_rem_euclid(*self, *v) 191 } 192 } 193 )*} 194 } 195 196 macro_rules! checked_euclid_int_impl { 197 ($($t:ty)*) => {$( 198 checked_euclid_forward_impl!($t); 199 200 #[cfg(not(has_div_euclid))] 201 impl CheckedEuclid for $t { 202 #[inline] 203 fn checked_div_euclid(&self, v: &$t) -> Option<$t> { 204 if *v == 0 || (*self == Self::min_value() && *v == -1) { 205 None 206 } else { 207 Some(Euclid::div_euclid(self, v)) 208 } 209 } 210 211 #[inline] 212 fn checked_rem_euclid(&self, v: &$t) -> Option<$t> { 213 if *v == 0 || (*self == Self::min_value() && *v == -1) { 214 None 215 } else { 216 Some(Euclid::rem_euclid(self, v)) 217 } 218 } 219 } 220 )*} 221 } 222 223 macro_rules! checked_euclid_uint_impl { 224 ($($t:ty)*) => {$( 225 checked_euclid_forward_impl!($t); 226 227 #[cfg(not(has_div_euclid))] 228 impl CheckedEuclid for $t { 229 #[inline] 230 fn checked_div_euclid(&self, v: &$t) -> Option<$t> { 231 if *v == 0 { 232 None 233 } else { 234 Some(Euclid::div_euclid(self, v)) 235 } 236 } 237 238 #[inline] 239 fn checked_rem_euclid(&self, v: &$t) -> Option<$t> { 240 if *v == 0 { 241 None 242 } else { 243 Some(Euclid::rem_euclid(self, v)) 244 } 245 } 246 } 247 )*} 248 } 249 250 checked_euclid_int_impl!(isize i8 i16 i32 i64 i128); 251 checked_euclid_uint_impl!(usize u8 u16 u32 u64 u128); 252 253 #[cfg(test)] 254 mod tests { 255 use super::*; 256 257 #[test] euclid_unsigned()258 fn euclid_unsigned() { 259 macro_rules! test_euclid { 260 ($($t:ident)+) => { 261 $( 262 { 263 let x: $t = 10; 264 let y: $t = 3; 265 assert_eq!(Euclid::div_euclid(&x, &y), 3); 266 assert_eq!(Euclid::rem_euclid(&x, &y), 1); 267 } 268 )+ 269 }; 270 } 271 272 test_euclid!(usize u8 u16 u32 u64); 273 } 274 275 #[test] euclid_signed()276 fn euclid_signed() { 277 macro_rules! test_euclid { 278 ($($t:ident)+) => { 279 $( 280 { 281 let x: $t = 10; 282 let y: $t = -3; 283 assert_eq!(Euclid::div_euclid(&x, &y), -3); 284 assert_eq!(Euclid::div_euclid(&-x, &y), 4); 285 assert_eq!(Euclid::rem_euclid(&x, &y), 1); 286 assert_eq!(Euclid::rem_euclid(&-x, &y), 2); 287 let x: $t = $t::min_value() + 1; 288 let y: $t = -1; 289 assert_eq!(Euclid::div_euclid(&x, &y), $t::max_value()); 290 } 291 )+ 292 }; 293 } 294 295 test_euclid!(isize i8 i16 i32 i64 i128); 296 } 297 298 #[test] euclid_float()299 fn euclid_float() { 300 macro_rules! test_euclid { 301 ($($t:ident)+) => { 302 $( 303 { 304 let x: $t = 12.1; 305 let y: $t = 3.2; 306 assert!(Euclid::div_euclid(&x, &y) * y + Euclid::rem_euclid(&x, &y) - x 307 <= 46.4 * <$t as crate::float::FloatCore>::epsilon()); 308 assert!(Euclid::div_euclid(&x, &-y) * -y + Euclid::rem_euclid(&x, &-y) - x 309 <= 46.4 * <$t as crate::float::FloatCore>::epsilon()); 310 assert!(Euclid::div_euclid(&-x, &y) * y + Euclid::rem_euclid(&-x, &y) + x 311 <= 46.4 * <$t as crate::float::FloatCore>::epsilon()); 312 assert!(Euclid::div_euclid(&-x, &-y) * -y + Euclid::rem_euclid(&-x, &-y) + x 313 <= 46.4 * <$t as crate::float::FloatCore>::epsilon()); 314 } 315 )+ 316 }; 317 } 318 319 test_euclid!(f32 f64); 320 } 321 322 #[test] euclid_checked()323 fn euclid_checked() { 324 macro_rules! test_euclid_checked { 325 ($($t:ident)+) => { 326 $( 327 { 328 assert_eq!(CheckedEuclid::checked_div_euclid(&$t::min_value(), &-1), None); 329 assert_eq!(CheckedEuclid::checked_rem_euclid(&$t::min_value(), &-1), None); 330 assert_eq!(CheckedEuclid::checked_div_euclid(&1, &0), None); 331 assert_eq!(CheckedEuclid::checked_rem_euclid(&1, &0), None); 332 } 333 )+ 334 }; 335 } 336 337 test_euclid_checked!(isize i8 i16 i32 i64 i128); 338 } 339 } 340