euclid.rs 8.6 KB

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