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); 120 euclid_uint_impl!(usize u8 u16 u32 u64); 121 #[cfg(has_i128)] 122 euclid_int_impl!(i128); 123 #[cfg(has_i128)] 124 euclid_uint_impl!(u128); 125 126 #[cfg(all(has_div_euclid, feature = "std"))] 127 euclid_forward_impl!(f32 f64); 128 129 #[cfg(not(all(has_div_euclid, feature = "std")))] 130 impl Euclid for f32 { 131 #[inline] div_euclid(&self, v: &f32) -> f32132 fn div_euclid(&self, v: &f32) -> f32 { 133 let q = <f32 as ::float::FloatCore>::trunc(self / v); 134 if self % v < 0.0 { 135 return if *v > 0.0 { q - 1.0 } else { q + 1.0 }; 136 } 137 q 138 } 139 140 #[inline] rem_euclid(&self, v: &f32) -> f32141 fn rem_euclid(&self, v: &f32) -> f32 { 142 let r = self % v; 143 if r < 0.0 { 144 r + <f32 as ::float::FloatCore>::abs(*v) 145 } else { 146 r 147 } 148 } 149 } 150 151 #[cfg(not(all(has_div_euclid, feature = "std")))] 152 impl Euclid for f64 { 153 #[inline] div_euclid(&self, v: &f64) -> f64154 fn div_euclid(&self, v: &f64) -> f64 { 155 let q = <f64 as ::float::FloatCore>::trunc(self / v); 156 if self % v < 0.0 { 157 return if *v > 0.0 { q - 1.0 } else { q + 1.0 }; 158 } 159 q 160 } 161 162 #[inline] rem_euclid(&self, v: &f64) -> f64163 fn rem_euclid(&self, v: &f64) -> f64 { 164 let r = self % v; 165 if r < 0.0 { 166 r + <f64 as ::float::FloatCore>::abs(*v) 167 } else { 168 r 169 } 170 } 171 } 172 173 pub trait CheckedEuclid: Euclid { 174 /// Performs euclid division that returns `None` instead of panicking on division by zero 175 /// and instead of wrapping around on underflow and overflow. checked_div_euclid(&self, v: &Self) -> Option<Self>176 fn checked_div_euclid(&self, v: &Self) -> Option<Self>; 177 178 /// Finds the euclid remainder of dividing two numbers, checking for underflow, overflow and 179 /// division by zero. If any of that happens, `None` is returned. checked_rem_euclid(&self, v: &Self) -> Option<Self>180 fn checked_rem_euclid(&self, v: &Self) -> Option<Self>; 181 } 182 183 macro_rules! checked_euclid_forward_impl { 184 ($($t:ty)*) => {$( 185 #[cfg(has_div_euclid)] 186 impl CheckedEuclid for $t { 187 #[inline] 188 fn checked_div_euclid(&self, v: &$t) -> Option<Self> { 189 <$t>::checked_div_euclid(*self, *v) 190 } 191 192 #[inline] 193 fn checked_rem_euclid(&self, v: &$t) -> Option<Self> { 194 <$t>::checked_rem_euclid(*self, *v) 195 } 196 } 197 )*} 198 } 199 200 macro_rules! checked_euclid_int_impl { 201 ($($t:ty)*) => {$( 202 checked_euclid_forward_impl!($t); 203 204 #[cfg(not(has_div_euclid))] 205 impl CheckedEuclid for $t { 206 #[inline] 207 fn checked_div_euclid(&self, v: &$t) -> Option<$t> { 208 if *v == 0 || (*self == Self::min_value() && *v == -1) { 209 None 210 } else { 211 Some(Euclid::div_euclid(self, v)) 212 } 213 } 214 215 #[inline] 216 fn checked_rem_euclid(&self, v: &$t) -> Option<$t> { 217 if *v == 0 || (*self == Self::min_value() && *v == -1) { 218 None 219 } else { 220 Some(Euclid::rem_euclid(self, v)) 221 } 222 } 223 } 224 )*} 225 } 226 227 macro_rules! checked_euclid_uint_impl { 228 ($($t:ty)*) => {$( 229 checked_euclid_forward_impl!($t); 230 231 #[cfg(not(has_div_euclid))] 232 impl CheckedEuclid for $t { 233 #[inline] 234 fn checked_div_euclid(&self, v: &$t) -> Option<$t> { 235 if *v == 0 { 236 None 237 } else { 238 Some(Euclid::div_euclid(self, v)) 239 } 240 } 241 242 #[inline] 243 fn checked_rem_euclid(&self, v: &$t) -> Option<$t> { 244 if *v == 0 { 245 None 246 } else { 247 Some(Euclid::rem_euclid(self, v)) 248 } 249 } 250 } 251 )*} 252 } 253 254 checked_euclid_int_impl!(isize i8 i16 i32 i64); 255 checked_euclid_uint_impl!(usize u8 u16 u32 u64); 256 #[cfg(has_i128)] 257 checked_euclid_int_impl!(i128); 258 #[cfg(has_i128)] 259 checked_euclid_uint_impl!(u128); 260 261 #[cfg(test)] 262 mod tests { 263 use super::*; 264 265 #[test] euclid_unsigned()266 fn euclid_unsigned() { 267 macro_rules! test_euclid { 268 ($($t:ident)+) => { 269 $( 270 { 271 let x: $t = 10; 272 let y: $t = 3; 273 assert_eq!(Euclid::div_euclid(&x, &y), 3); 274 assert_eq!(Euclid::rem_euclid(&x, &y), 1); 275 } 276 )+ 277 }; 278 } 279 280 test_euclid!(usize u8 u16 u32 u64); 281 } 282 283 #[test] euclid_signed()284 fn euclid_signed() { 285 macro_rules! test_euclid { 286 ($($t:ident)+) => { 287 $( 288 { 289 let x: $t = 10; 290 let y: $t = -3; 291 assert_eq!(Euclid::div_euclid(&x, &y), -3); 292 assert_eq!(Euclid::div_euclid(&-x, &y), 4); 293 assert_eq!(Euclid::rem_euclid(&x, &y), 1); 294 assert_eq!(Euclid::rem_euclid(&-x, &y), 2); 295 let x: $t = $t::min_value() + 1; 296 let y: $t = -1; 297 assert_eq!(Euclid::div_euclid(&x, &y), $t::max_value()); 298 } 299 )+ 300 }; 301 } 302 303 test_euclid!(isize i8 i16 i32 i64); 304 } 305 306 #[test] euclid_float()307 fn euclid_float() { 308 macro_rules! test_euclid { 309 ($($t:ident)+) => { 310 $( 311 { 312 let x: $t = 12.1; 313 let y: $t = 3.2; 314 assert!(Euclid::div_euclid(&x, &y) * y + Euclid::rem_euclid(&x, &y) - x 315 <= 46.4 * <$t as ::float::FloatCore>::epsilon()); 316 assert!(Euclid::div_euclid(&x, &-y) * -y + Euclid::rem_euclid(&x, &-y) - x 317 <= 46.4 * <$t as ::float::FloatCore>::epsilon()); 318 assert!(Euclid::div_euclid(&-x, &y) * y + Euclid::rem_euclid(&-x, &y) + x 319 <= 46.4 * <$t as ::float::FloatCore>::epsilon()); 320 assert!(Euclid::div_euclid(&-x, &-y) * -y + Euclid::rem_euclid(&-x, &-y) + x 321 <= 46.4 * <$t as ::float::FloatCore>::epsilon()); 322 } 323 )+ 324 }; 325 } 326 327 test_euclid!(f32 f64); 328 } 329 330 #[test] euclid_checked()331 fn euclid_checked() { 332 macro_rules! test_euclid_checked { 333 ($($t:ident)+) => { 334 $( 335 { 336 assert_eq!(CheckedEuclid::checked_div_euclid(&$t::min_value(), &-1), None); 337 assert_eq!(CheckedEuclid::checked_rem_euclid(&$t::min_value(), &-1), None); 338 assert_eq!(CheckedEuclid::checked_div_euclid(&1, &0), None); 339 assert_eq!(CheckedEuclid::checked_rem_euclid(&1, &0), None); 340 } 341 )+ 342 }; 343 } 344 345 test_euclid_checked!(isize i8 i16 i32 i64); 346 } 347 } 348