nam_num_traits/ops/euclid.rs
1pub trait Euclid: Sized {
2 /// Calculates Euclidean division, the matching method for `rem_euclid`.
3 ///
4 /// This computes the integer `n` such that
5 /// `self = n * v + self.rem_euclid(v)`.
6 /// In other words, the result is `self / v` rounded to the integer `n`
7 /// such that `self >= n * v`.
8 ///
9 /// # Examples
10 ///
11 /// ```
12 /// use num_traits::Euclid;
13 ///
14 /// let a: i32 = 7;
15 /// let b: i32 = 4;
16 /// assert_eq!(Euclid::div_euclid(&a, &b), 1); // 7 > 4 * 1
17 /// assert_eq!(Euclid::div_euclid(&-a, &b), -2); // -7 >= 4 * -2
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 /// ```
21 fn div_euclid(&self, v: &Self) -> Self;
22
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 /// Returns both the quotient and remainder from Euclidean division.
49 ///
50 /// By default, it internally calls both `Euclid::div_euclid` and `Euclid::rem_euclid`,
51 /// but it can be overridden in order to implement some optimization.
52 ///
53 /// # Examples
54 ///
55 /// ```
56 /// # use num_traits::Euclid;
57 /// let x = 5u8;
58 /// let y = 3u8;
59 ///
60 /// let div = Euclid::div_euclid(&x, &y);
61 /// let rem = Euclid::rem_euclid(&x, &y);
62 ///
63 /// assert_eq!((div, rem), Euclid::div_rem_euclid(&x, &y));
64 /// ```
65 fn div_rem_euclid(&self, v: &Self) -> (Self, Self) {
66 (self.div_euclid(v), self.rem_euclid(v))
67 }
68}
69
70macro_rules! euclid_forward_impl {
71 ($($t:ty)*) => {$(
72 impl Euclid for $t {
73 #[inline]
74 fn div_euclid(&self, v: &$t) -> Self {
75 <$t>::div_euclid(*self, *v)
76 }
77
78 #[inline]
79 fn rem_euclid(&self, v: &$t) -> Self {
80 <$t>::rem_euclid(*self, *v)
81 }
82 }
83 )*}
84}
85
86euclid_forward_impl!(isize i8 i16 i32 i64 i128);
87euclid_forward_impl!(usize u8 u16 u32 u64 u128);
88
89#[cfg(feature = "std")]
90euclid_forward_impl!(f32 f64);
91
92#[cfg(not(feature = "std"))]
93impl Euclid for f32 {
94 #[inline]
95 fn div_euclid(&self, v: &f32) -> f32 {
96 let q = <f32 as crate::float::FloatCore>::trunc(self / v);
97 if self % v < 0.0 {
98 return if *v > 0.0 { q - 1.0 } else { q + 1.0 };
99 }
100 q
101 }
102
103 #[inline]
104 fn rem_euclid(&self, v: &f32) -> f32 {
105 let r = self % v;
106 if r < 0.0 {
107 r + <f32 as crate::float::FloatCore>::abs(*v)
108 } else {
109 r
110 }
111 }
112}
113
114#[cfg(not(feature = "std"))]
115impl Euclid for f64 {
116 #[inline]
117 fn div_euclid(&self, v: &f64) -> f64 {
118 let q = <f64 as crate::float::FloatCore>::trunc(self / v);
119 if self % v < 0.0 {
120 return if *v > 0.0 { q - 1.0 } else { q + 1.0 };
121 }
122 q
123 }
124
125 #[inline]
126 fn rem_euclid(&self, v: &f64) -> f64 {
127 let r = self % v;
128 if r < 0.0 {
129 r + <f64 as crate::float::FloatCore>::abs(*v)
130 } else {
131 r
132 }
133 }
134}
135
136pub trait CheckedEuclid: Euclid {
137 /// Performs euclid division, returning `None` on division by zero or if
138 /// overflow occurred.
139 fn checked_div_euclid(&self, v: &Self) -> Option<Self>;
140
141 /// Finds the euclid remainder of dividing two numbers, returning `None` on
142 /// division by zero or if overflow occurred.
143 fn checked_rem_euclid(&self, v: &Self) -> Option<Self>;
144
145 /// Returns both the quotient and remainder from checked Euclidean division,
146 /// returning `None` on division by zero or if overflow occurred.
147 ///
148 /// By default, it internally calls both `CheckedEuclid::checked_div_euclid` and `CheckedEuclid::checked_rem_euclid`,
149 /// but it can be overridden in order to implement some optimization.
150 /// # Examples
151 ///
152 /// ```
153 /// # use num_traits::CheckedEuclid;
154 /// let x = 5u8;
155 /// let y = 3u8;
156 ///
157 /// let div = CheckedEuclid::checked_div_euclid(&x, &y);
158 /// let rem = CheckedEuclid::checked_rem_euclid(&x, &y);
159 ///
160 /// assert_eq!(Some((div.unwrap(), rem.unwrap())), CheckedEuclid::checked_div_rem_euclid(&x, &y));
161 /// ```
162 fn checked_div_rem_euclid(&self, v: &Self) -> Option<(Self, Self)> {
163 Some((self.checked_div_euclid(v)?, self.checked_rem_euclid(v)?))
164 }
165}
166
167macro_rules! checked_euclid_forward_impl {
168 ($($t:ty)*) => {$(
169 impl CheckedEuclid for $t {
170 #[inline]
171 fn checked_div_euclid(&self, v: &$t) -> Option<Self> {
172 <$t>::checked_div_euclid(*self, *v)
173 }
174
175 #[inline]
176 fn checked_rem_euclid(&self, v: &$t) -> Option<Self> {
177 <$t>::checked_rem_euclid(*self, *v)
178 }
179 }
180 )*}
181}
182
183checked_euclid_forward_impl!(isize i8 i16 i32 i64 i128);
184checked_euclid_forward_impl!(usize u8 u16 u32 u64 u128);
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn euclid_unsigned() {
192 macro_rules! test_euclid {
193 ($($t:ident)+) => {
194 $(
195 {
196 let x: $t = 10;
197 let y: $t = 3;
198 let div = Euclid::div_euclid(&x, &y);
199 let rem = Euclid::rem_euclid(&x, &y);
200 assert_eq!(div, 3);
201 assert_eq!(rem, 1);
202 assert_eq!((div, rem), Euclid::div_rem_euclid(&x, &y));
203 }
204 )+
205 };
206 }
207
208 test_euclid!(usize u8 u16 u32 u64);
209 }
210
211 #[test]
212 fn euclid_signed() {
213 macro_rules! test_euclid {
214 ($($t:ident)+) => {
215 $(
216 {
217 let x: $t = 10;
218 let y: $t = -3;
219 assert_eq!(Euclid::div_euclid(&x, &y), -3);
220 assert_eq!(Euclid::div_euclid(&-x, &y), 4);
221 assert_eq!(Euclid::rem_euclid(&x, &y), 1);
222 assert_eq!(Euclid::rem_euclid(&-x, &y), 2);
223 assert_eq!((Euclid::div_euclid(&x, &y), Euclid::rem_euclid(&x, &y)), Euclid::div_rem_euclid(&x, &y));
224 let x: $t = $t::min_value() + 1;
225 let y: $t = -1;
226 assert_eq!(Euclid::div_euclid(&x, &y), $t::max_value());
227 }
228 )+
229 };
230 }
231
232 test_euclid!(isize i8 i16 i32 i64 i128);
233 }
234
235 #[test]
236 fn euclid_float() {
237 macro_rules! test_euclid {
238 ($($t:ident)+) => {
239 $(
240 {
241 let x: $t = 12.1;
242 let y: $t = 3.2;
243 assert!(Euclid::div_euclid(&x, &y) * y + Euclid::rem_euclid(&x, &y) - x
244 <= 46.4 * <$t as crate::float::FloatCore>::epsilon());
245 assert!(Euclid::div_euclid(&x, &-y) * -y + Euclid::rem_euclid(&x, &-y) - x
246 <= 46.4 * <$t as crate::float::FloatCore>::epsilon());
247 assert!(Euclid::div_euclid(&-x, &y) * y + Euclid::rem_euclid(&-x, &y) + x
248 <= 46.4 * <$t as crate::float::FloatCore>::epsilon());
249 assert!(Euclid::div_euclid(&-x, &-y) * -y + Euclid::rem_euclid(&-x, &-y) + x
250 <= 46.4 * <$t as crate::float::FloatCore>::epsilon());
251 assert_eq!((Euclid::div_euclid(&x, &y), Euclid::rem_euclid(&x, &y)), Euclid::div_rem_euclid(&x, &y));
252 }
253 )+
254 };
255 }
256
257 test_euclid!(f32 f64);
258 }
259
260 #[test]
261 fn euclid_checked() {
262 macro_rules! test_euclid_checked {
263 ($($t:ident)+) => {
264 $(
265 {
266 assert_eq!(CheckedEuclid::checked_div_euclid(&$t::min_value(), &-1), None);
267 assert_eq!(CheckedEuclid::checked_rem_euclid(&$t::min_value(), &-1), None);
268 assert_eq!(CheckedEuclid::checked_div_euclid(&1, &0), None);
269 assert_eq!(CheckedEuclid::checked_rem_euclid(&1, &0), None);
270 }
271 )+
272 };
273 }
274
275 test_euclid_checked!(isize i8 i16 i32 i64 i128);
276 }
277}