malachite_nz/natural/arithmetic/round_to_multiple.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::natural::Natural;
10use core::cmp::Ordering::{self, *};
11use malachite_base::num::arithmetic::traits::{RoundToMultiple, RoundToMultipleAssign};
12use malachite_base::num::basic::traits::Zero;
13use malachite_base::rounding_modes::RoundingMode::{self, *};
14
15impl RoundToMultiple<Self> for Natural {
16 type Output = Self;
17
18 /// Rounds a [`Natural`] to a multiple of another [`Natural`], according to a specified rounding
19 /// mode. Both [`Natural`]s are taken by value. An [`Ordering`] is also returned, indicating
20 /// whether the returned value is less than, equal to, or greater than the original value.
21 ///
22 /// Let $q = \frac{x}{y}$:
23 ///
24 /// $f(x, y, \mathrm{Down}) = f(x, y, \mathrm{Floor}) = y \lfloor q \rfloor.$
25 ///
26 /// $f(x, y, \mathrm{Up}) = f(x, y, \mathrm{Ceiling}) = y \lceil q \rceil.$
27 ///
28 /// $$
29 /// f(x, y, \mathrm{Nearest}) = \begin{cases}
30 /// y \lfloor q \rfloor & \text{if} \\quad
31 /// q - \lfloor q \rfloor < \frac{1}{2} \\\\
32 /// y \lceil q \rceil & \text{if} \\quad q - \lfloor q \rfloor > \frac{1}{2} \\\\
33 /// y \lfloor q \rfloor &
34 /// \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2} \\ \text{and} \\ \lfloor q \rfloor
35 /// \\ \text{is even} \\\\
36 /// y \lceil q \rceil & \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2}
37 /// \\ \text{and} \\ \lfloor q \rfloor \\ \text{is odd.}
38 /// \end{cases}
39 /// $$
40 ///
41 /// $f(x, y, \mathrm{Exact}) = x$, but panics if $q \notin \N$.
42 ///
43 /// The following two expressions are equivalent:
44 /// - `x.round_to_multiple(other, Exact)`
45 /// - `{ assert!(x.divisible_by(other)); x }`
46 ///
47 /// but the latter should be used as it is clearer and more efficient.
48 ///
49 /// # Worst-case complexity
50 /// $T(n) = O(n \log n \log\log n)$
51 ///
52 /// $M(n) = O(n \log n)$
53 ///
54 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
55 ///
56 /// # Panics
57 /// - If `rm` is `Exact`, but `self` is not a multiple of `other`.
58 /// - If `self` is nonzero, `other` is zero, and `rm` is trying to round away from zero.
59 ///
60 /// # Examples
61 /// ```
62 /// use malachite_base::num::arithmetic::traits::RoundToMultiple;
63 /// use malachite_base::num::basic::traits::Zero;
64 /// use malachite_base::rounding_modes::RoundingMode::*;
65 /// use malachite_base::strings::ToDebugString;
66 /// use malachite_nz::natural::Natural;
67 ///
68 /// assert_eq!(
69 /// Natural::from(5u32)
70 /// .round_to_multiple(Natural::ZERO, Down)
71 /// .to_debug_string(),
72 /// "(0, Less)"
73 /// );
74 ///
75 /// assert_eq!(
76 /// Natural::from(10u32)
77 /// .round_to_multiple(Natural::from(4u32), Down)
78 /// .to_debug_string(),
79 /// "(8, Less)"
80 /// );
81 /// assert_eq!(
82 /// Natural::from(10u32)
83 /// .round_to_multiple(Natural::from(4u32), Up)
84 /// .to_debug_string(),
85 /// "(12, Greater)"
86 /// );
87 /// assert_eq!(
88 /// Natural::from(10u32)
89 /// .round_to_multiple(Natural::from(5u32), Exact)
90 /// .to_debug_string(),
91 /// "(10, Equal)"
92 /// );
93 /// assert_eq!(
94 /// Natural::from(10u32)
95 /// .round_to_multiple(Natural::from(3u32), Nearest)
96 /// .to_debug_string(),
97 /// "(9, Less)"
98 /// );
99 /// assert_eq!(
100 /// Natural::from(20u32)
101 /// .round_to_multiple(Natural::from(3u32), Nearest)
102 /// .to_debug_string(),
103 /// "(21, Greater)"
104 /// );
105 /// assert_eq!(
106 /// Natural::from(10u32)
107 /// .round_to_multiple(Natural::from(4u32), Nearest)
108 /// .to_debug_string(),
109 /// "(8, Less)"
110 /// );
111 /// assert_eq!(
112 /// Natural::from(14u32)
113 /// .round_to_multiple(Natural::from(4u32), Nearest)
114 /// .to_debug_string(),
115 /// "(16, Greater)"
116 /// );
117 /// ```
118 #[inline]
119 fn round_to_multiple(mut self, other: Self, rm: RoundingMode) -> (Self, Ordering) {
120 let o = self.round_to_multiple_assign(other, rm);
121 (self, o)
122 }
123}
124
125impl RoundToMultiple<&Self> for Natural {
126 type Output = Self;
127
128 /// Rounds a [`Natural`] to a multiple of another [`Natural`], according to a specified rounding
129 /// mode. The first [`Natural`] is taken by value and the second by reference. An [`Ordering`]
130 /// is also returned, indicating whether the returned value is less than, equal to, or greater
131 /// than the original value.
132 ///
133 /// Let $q = \frac{x}{y}$:
134 ///
135 /// $f(x, y, \mathrm{Down}) = f(x, y, \mathrm{Floor}) = y \lfloor q \rfloor.$
136 ///
137 /// $f(x, y, \mathrm{Up}) = f(x, y, \mathrm{Ceiling}) = y \lceil q \rceil.$
138 ///
139 /// $$
140 /// f(x, y, \mathrm{Nearest}) = \begin{cases}
141 /// y \lfloor q \rfloor & \text{if} \\quad
142 /// q - \lfloor q \rfloor < \frac{1}{2} \\\\
143 /// y \lceil q \rceil & \text{if} \\quad q - \lfloor q \rfloor > \frac{1}{2} \\\\
144 /// y \lfloor q \rfloor &
145 /// \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2} \\ \text{and} \\ \lfloor q \rfloor
146 /// \\ \text{is even} \\\\
147 /// y \lceil q \rceil & \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2}
148 /// \\ \text{and} \\ \lfloor q \rfloor \\ \text{is odd.}
149 /// \end{cases}
150 /// $$
151 ///
152 /// $f(x, y, \mathrm{Exact}) = x$, but panics if $q \notin \N$.
153 ///
154 /// The following two expressions are equivalent:
155 /// - `x.round_to_multiple(other, Exact)`
156 /// - `{ assert!(x.divisible_by(other)); x }`
157 ///
158 /// but the latter should be used as it is clearer and more efficient.
159 ///
160 /// # Worst-case complexity
161 /// $T(n) = O(n \log n \log\log n)$
162 ///
163 /// $M(n) = O(n \log n)$
164 ///
165 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
166 ///
167 /// # Panics
168 /// - If `rm` is `Exact`, but `self` is not a multiple of `other`.
169 /// - If `self` is nonzero, `other` is zero, and `rm` is trying to round away from zero.
170 ///
171 /// # Examples
172 /// ```
173 /// use malachite_base::num::arithmetic::traits::RoundToMultiple;
174 /// use malachite_base::num::basic::traits::Zero;
175 /// use malachite_base::rounding_modes::RoundingMode::*;
176 /// use malachite_base::strings::ToDebugString;
177 /// use malachite_nz::natural::Natural;
178 ///
179 /// assert_eq!(
180 /// Natural::from(5u32)
181 /// .round_to_multiple(&Natural::ZERO, Down)
182 /// .to_debug_string(),
183 /// "(0, Less)"
184 /// );
185 ///
186 /// assert_eq!(
187 /// Natural::from(10u32)
188 /// .round_to_multiple(&Natural::from(4u32), Down)
189 /// .to_debug_string(),
190 /// "(8, Less)"
191 /// );
192 /// assert_eq!(
193 /// Natural::from(10u32)
194 /// .round_to_multiple(&Natural::from(4u32), Up)
195 /// .to_debug_string(),
196 /// "(12, Greater)"
197 /// );
198 /// assert_eq!(
199 /// Natural::from(10u32)
200 /// .round_to_multiple(&Natural::from(5u32), Exact)
201 /// .to_debug_string(),
202 /// "(10, Equal)"
203 /// );
204 /// assert_eq!(
205 /// Natural::from(10u32)
206 /// .round_to_multiple(&Natural::from(3u32), Nearest)
207 /// .to_debug_string(),
208 /// "(9, Less)"
209 /// );
210 /// assert_eq!(
211 /// Natural::from(20u32)
212 /// .round_to_multiple(&Natural::from(3u32), Nearest)
213 /// .to_debug_string(),
214 /// "(21, Greater)"
215 /// );
216 /// assert_eq!(
217 /// Natural::from(10u32)
218 /// .round_to_multiple(&Natural::from(4u32), Nearest)
219 /// .to_debug_string(),
220 /// "(8, Less)"
221 /// );
222 /// assert_eq!(
223 /// Natural::from(14u32)
224 /// .round_to_multiple(&Natural::from(4u32), Nearest)
225 /// .to_debug_string(),
226 /// "(16, Greater)"
227 /// );
228 /// ```
229 #[inline]
230 fn round_to_multiple(mut self, other: &Self, rm: RoundingMode) -> (Self, Ordering) {
231 let o = self.round_to_multiple_assign(other, rm);
232 (self, o)
233 }
234}
235
236impl RoundToMultiple<Natural> for &Natural {
237 type Output = Natural;
238
239 /// Rounds a [`Natural`] to a multiple of another [`Natural`], according to a specified rounding
240 /// mode. The first [`Natural`] is taken by reference and the second by value. An [`Ordering`]
241 /// is also returned, indicating whether the returned value is less than, equal to, or greater
242 /// than the original value.
243 ///
244 /// Let $q = \frac{x}{y}$:
245 ///
246 /// $f(x, y, \mathrm{Down}) = f(x, y, \mathrm{Floor}) = y \lfloor q \rfloor.$
247 ///
248 /// $f(x, y, \mathrm{Up}) = f(x, y, \mathrm{Ceiling}) = y \lceil q \rceil.$
249 ///
250 /// $$
251 /// f(x, y, \mathrm{Nearest}) = \begin{cases}
252 /// y \lfloor q \rfloor & \text{if} \\quad
253 /// q - \lfloor q \rfloor < \frac{1}{2} \\\\
254 /// y \lceil q \rceil & \text{if} \\quad q - \lfloor q \rfloor > \frac{1}{2} \\\\
255 /// y \lfloor q \rfloor &
256 /// \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2} \\ \text{and} \\ \lfloor q \rfloor
257 /// \\ \text{is even} \\\\
258 /// y \lceil q \rceil & \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2}
259 /// \\ \text{and} \\ \lfloor q \rfloor \\ \text{is odd.}
260 /// \end{cases}
261 /// $$
262 ///
263 /// $f(x, y, \mathrm{Exact}) = x$, but panics if $q \notin \N$.
264 ///
265 /// The following two expressions are equivalent:
266 /// - `x.round_to_multiple(other, Exact)`
267 /// - `{ assert!(x.divisible_by(other)); x }`
268 ///
269 /// but the latter should be used as it is clearer and more efficient.
270 ///
271 /// # Worst-case complexity
272 /// $T(n) = O(n \log n \log\log n)$
273 ///
274 /// $M(n) = O(n \log n)$
275 ///
276 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
277 ///
278 /// # Panics
279 /// - If `rm` is `Exact`, but `self` is not a multiple of `other`.
280 /// - If `self` is nonzero, `other` is zero, and `rm` is trying to round away from zero.
281 ///
282 /// # Examples
283 /// ```
284 /// use malachite_base::num::arithmetic::traits::RoundToMultiple;
285 /// use malachite_base::num::basic::traits::Zero;
286 /// use malachite_base::rounding_modes::RoundingMode::*;
287 /// use malachite_base::strings::ToDebugString;
288 /// use malachite_nz::natural::Natural;
289 ///
290 /// assert_eq!(
291 /// (&Natural::from(5u32))
292 /// .round_to_multiple(Natural::ZERO, Down)
293 /// .to_debug_string(),
294 /// "(0, Less)"
295 /// );
296 ///
297 /// assert_eq!(
298 /// (&Natural::from(10u32))
299 /// .round_to_multiple(Natural::from(4u32), Down)
300 /// .to_debug_string(),
301 /// "(8, Less)"
302 /// );
303 /// assert_eq!(
304 /// (&Natural::from(10u32))
305 /// .round_to_multiple(Natural::from(4u32), Up)
306 /// .to_debug_string(),
307 /// "(12, Greater)"
308 /// );
309 /// assert_eq!(
310 /// (&Natural::from(10u32))
311 /// .round_to_multiple(Natural::from(5u32), Exact)
312 /// .to_debug_string(),
313 /// "(10, Equal)"
314 /// );
315 /// assert_eq!(
316 /// (&Natural::from(10u32))
317 /// .round_to_multiple(Natural::from(3u32), Nearest)
318 /// .to_debug_string(),
319 /// "(9, Less)"
320 /// );
321 /// assert_eq!(
322 /// (&Natural::from(20u32))
323 /// .round_to_multiple(Natural::from(3u32), Nearest)
324 /// .to_debug_string(),
325 /// "(21, Greater)"
326 /// );
327 /// assert_eq!(
328 /// (&Natural::from(10u32))
329 /// .round_to_multiple(Natural::from(4u32), Nearest)
330 /// .to_debug_string(),
331 /// "(8, Less)"
332 /// );
333 /// assert_eq!(
334 /// (&Natural::from(14u32))
335 /// .round_to_multiple(Natural::from(4u32), Nearest)
336 /// .to_debug_string(),
337 /// "(16, Greater)"
338 /// );
339 /// ```
340 fn round_to_multiple(self, other: Natural, rm: RoundingMode) -> (Natural, Ordering) {
341 match (self, other) {
342 (x, y) if *x == y => (y, Equal),
343 (x, Natural::ZERO) => match rm {
344 Down | Floor | Nearest => (Natural::ZERO, Less),
345 _ => panic!("Cannot round {x} to zero using RoundingMode {rm}"),
346 },
347 (x, y) => {
348 let r = x % &y;
349 if r == 0 {
350 (x.clone(), Equal)
351 } else {
352 let floor = x - &r;
353 match rm {
354 Down | Floor => (floor, Less),
355 Up | Ceiling => (floor + y, Greater),
356 Nearest => {
357 match (r << 1u64).cmp(&y) {
358 Less => (floor, Less),
359 Greater => (floor + y, Greater),
360 Equal => {
361 // The even multiple of y will have more trailing zeros.
362 if floor == 0 {
363 (floor, Less)
364 } else {
365 let ceiling = &floor + y;
366 if floor.trailing_zeros() > ceiling.trailing_zeros() {
367 (floor, Less)
368 } else {
369 (ceiling, Greater)
370 }
371 }
372 }
373 }
374 }
375 Exact => {
376 panic!("Cannot round {x} to {y} using RoundingMode {rm}")
377 }
378 }
379 }
380 }
381 }
382 }
383}
384
385impl RoundToMultiple<&Natural> for &Natural {
386 type Output = Natural;
387
388 /// Rounds a [`Natural`] to a multiple of another [`Natural`], according to a specified rounding
389 /// mode. Both [`Natural`]s are taken by reference. An [`Ordering`] is also returned, indicating
390 /// whether the returned value is less than, equal to, or greater than the original value.
391 ///
392 /// Let $q = \frac{x}{y}$:
393 ///
394 /// $f(x, y, \mathrm{Down}) = f(x, y, \mathrm{Floor}) = y \lfloor q \rfloor.$
395 ///
396 /// $f(x, y, \mathrm{Up}) = f(x, y, \mathrm{Ceiling}) = y \lceil q \rceil.$
397 ///
398 /// $$
399 /// f(x, y, \mathrm{Nearest}) = \begin{cases}
400 /// y \lfloor q \rfloor & \text{if} \\quad
401 /// q - \lfloor q \rfloor < \frac{1}{2} \\\\
402 /// y \lceil q \rceil & \text{if} \\quad q - \lfloor q \rfloor > \frac{1}{2} \\\\
403 /// y \lfloor q \rfloor &
404 /// \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2} \\ \text{and} \\ \lfloor q \rfloor
405 /// \\ \text{is even} \\\\
406 /// y \lceil q \rceil & \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2}
407 /// \\ \text{and} \\ \lfloor q \rfloor \\ \text{is odd.}
408 /// \end{cases}
409 /// $$
410 ///
411 /// $f(x, y, \mathrm{Exact}) = x$, but panics if $q \notin \N$.
412 ///
413 /// The following two expressions are equivalent:
414 /// - `x.round_to_multiple(other, Exact)`
415 /// - `{ assert!(x.divisible_by(other)); x }`
416 ///
417 /// but the latter should be used as it is clearer and more efficient.
418 ///
419 /// # Worst-case complexity
420 /// $T(n) = O(n \log n \log\log n)$
421 ///
422 /// $M(n) = O(n \log n)$
423 ///
424 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
425 ///
426 /// # Panics
427 /// - If `rm` is `Exact`, but `self` is not a multiple of `other`.
428 /// - If `self` is nonzero, `other` is zero, and `rm` is trying to round away from zero.
429 ///
430 /// # Examples
431 /// ```
432 /// use malachite_base::num::arithmetic::traits::RoundToMultiple;
433 /// use malachite_base::num::basic::traits::Zero;
434 /// use malachite_base::rounding_modes::RoundingMode::*;
435 /// use malachite_base::strings::ToDebugString;
436 /// use malachite_nz::natural::Natural;
437 ///
438 /// assert_eq!(
439 /// (&Natural::from(5u32))
440 /// .round_to_multiple(&Natural::ZERO, Down)
441 /// .to_debug_string(),
442 /// "(0, Less)"
443 /// );
444 ///
445 /// assert_eq!(
446 /// (&Natural::from(10u32))
447 /// .round_to_multiple(&Natural::from(4u32), Down)
448 /// .to_debug_string(),
449 /// "(8, Less)"
450 /// );
451 /// assert_eq!(
452 /// (&Natural::from(10u32))
453 /// .round_to_multiple(&Natural::from(4u32), Up)
454 /// .to_debug_string(),
455 /// "(12, Greater)"
456 /// );
457 /// assert_eq!(
458 /// (&Natural::from(10u32))
459 /// .round_to_multiple(&Natural::from(5u32), Exact)
460 /// .to_debug_string(),
461 /// "(10, Equal)"
462 /// );
463 /// assert_eq!(
464 /// (&Natural::from(10u32))
465 /// .round_to_multiple(&Natural::from(3u32), Nearest)
466 /// .to_debug_string(),
467 /// "(9, Less)"
468 /// );
469 /// assert_eq!(
470 /// (&Natural::from(20u32))
471 /// .round_to_multiple(&Natural::from(3u32), Nearest)
472 /// .to_debug_string(),
473 /// "(21, Greater)"
474 /// );
475 /// assert_eq!(
476 /// (&Natural::from(10u32))
477 /// .round_to_multiple(&Natural::from(4u32), Nearest)
478 /// .to_debug_string(),
479 /// "(8, Less)"
480 /// );
481 /// assert_eq!(
482 /// (&Natural::from(14u32))
483 /// .round_to_multiple(&Natural::from(4u32), Nearest)
484 /// .to_debug_string(),
485 /// "(16, Greater)"
486 /// );
487 /// ```
488 fn round_to_multiple(self, other: &Natural, rm: RoundingMode) -> (Natural, Ordering) {
489 match (self, other) {
490 (x, y) if x == y => (x.clone(), Equal),
491 (x, &Natural::ZERO) => match rm {
492 Down | Floor | Nearest => (Natural::ZERO, Less),
493 _ => panic!("Cannot round {x} to zero using RoundingMode {rm}"),
494 },
495 (x, y) => {
496 let r = x % y;
497 if r == 0 {
498 (x.clone(), Equal)
499 } else {
500 let floor = x - &r;
501 match rm {
502 Down | Floor => (floor, Less),
503 Up | Ceiling => (floor + y, Greater),
504 Nearest => {
505 match (r << 1u64).cmp(y) {
506 Less => (floor, Less),
507 Greater => (floor + y, Greater),
508 Equal => {
509 // The even multiple of y will have more trailing zeros.
510 if floor == 0 {
511 (floor, Less)
512 } else {
513 let ceiling = &floor + y;
514 if floor.trailing_zeros() > ceiling.trailing_zeros() {
515 (floor, Less)
516 } else {
517 (ceiling, Greater)
518 }
519 }
520 }
521 }
522 }
523 Exact => {
524 panic!("Cannot round {x} to {y} using RoundingMode {rm}")
525 }
526 }
527 }
528 }
529 }
530 }
531}
532
533impl RoundToMultipleAssign<Self> for Natural {
534 /// Rounds a [`Natural`] to a multiple of another [`Natural`] in place, according to a specified
535 /// rounding mode. The [`Natural`] on the right-hand side is taken by value. An [`Ordering`] is
536 /// returned, indicating whether the returned value is less than, equal to, or greater than the
537 /// original value.
538 ///
539 /// See the [`RoundToMultiple`] documentation for details.
540 ///
541 /// The following two expressions are equivalent:
542 /// - `x.round_to_multiple_assign(other, Exact);`
543 /// - `assert!(x.divisible_by(other));`
544 ///
545 /// but the latter should be used as it is clearer and more efficient.
546 ///
547 /// # Worst-case complexity
548 /// $T(n) = O(n \log n \log\log n)$
549 ///
550 /// $M(n) = O(n \log n)$
551 ///
552 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
553 ///
554 /// # Panics
555 /// - If `rm` is `Exact`, but `self` is not a multiple of `other`.
556 /// - If `self` is nonzero, `other` is zero, and `rm` is trying to round away from zero.
557 ///
558 /// # Examples
559 /// ```
560 /// use core::cmp::Ordering::*;
561 /// use malachite_base::num::arithmetic::traits::RoundToMultipleAssign;
562 /// use malachite_base::num::basic::traits::Zero;
563 /// use malachite_base::rounding_modes::RoundingMode::*;
564 /// use malachite_nz::natural::Natural;
565 ///
566 /// let mut x = Natural::from(5u32);
567 /// assert_eq!(x.round_to_multiple_assign(Natural::ZERO, Down), Less);
568 /// assert_eq!(x, 0);
569 ///
570 /// let mut x = Natural::from(10u32);
571 /// assert_eq!(x.round_to_multiple_assign(Natural::from(4u32), Down), Less);
572 /// assert_eq!(x, 8);
573 ///
574 /// let mut x = Natural::from(10u32);
575 /// assert_eq!(x.round_to_multiple_assign(Natural::from(4u32), Up), Greater);
576 /// assert_eq!(x, 12);
577 ///
578 /// let mut x = Natural::from(10u32);
579 /// assert_eq!(
580 /// x.round_to_multiple_assign(Natural::from(5u32), Exact),
581 /// Equal
582 /// );
583 /// assert_eq!(x, 10);
584 ///
585 /// let mut x = Natural::from(10u32);
586 /// assert_eq!(
587 /// x.round_to_multiple_assign(Natural::from(3u32), Nearest),
588 /// Less
589 /// );
590 /// assert_eq!(x, 9);
591 ///
592 /// let mut x = Natural::from(20u32);
593 /// assert_eq!(
594 /// x.round_to_multiple_assign(Natural::from(3u32), Nearest),
595 /// Greater
596 /// );
597 /// assert_eq!(x, 21);
598 ///
599 /// let mut x = Natural::from(10u32);
600 /// assert_eq!(
601 /// x.round_to_multiple_assign(Natural::from(4u32), Nearest),
602 /// Less
603 /// );
604 /// assert_eq!(x, 8);
605 ///
606 /// let mut x = Natural::from(14u32);
607 /// assert_eq!(
608 /// x.round_to_multiple_assign(Natural::from(4u32), Nearest),
609 /// Greater
610 /// );
611 /// assert_eq!(x, 16);
612 /// ```
613 fn round_to_multiple_assign(&mut self, other: Self, rm: RoundingMode) -> Ordering {
614 match (&mut *self, other) {
615 (x, y) if *x == y => Equal,
616 (x, Self::ZERO) => match rm {
617 Down | Floor | Nearest => {
618 *self = Self::ZERO;
619 Less
620 }
621 _ => panic!("Cannot round {x} to zero using RoundingMode {rm}"),
622 },
623 (x, y) => {
624 let r = &*x % &y;
625 if r == 0 {
626 Equal
627 } else {
628 *x -= &r;
629 match rm {
630 Down | Floor => Less,
631 Up | Ceiling => {
632 *x += y;
633 Greater
634 }
635 Nearest => {
636 match (r << 1u64).cmp(&y) {
637 Less => Less,
638 Greater => {
639 *x += y;
640 Greater
641 }
642 Equal => {
643 // The even multiple of y will have more trailing zeros.
644 if *x == 0 {
645 Less
646 } else {
647 let ceiling = &*x + y;
648 if x.trailing_zeros() < ceiling.trailing_zeros() {
649 *x = ceiling;
650 Greater
651 } else {
652 Less
653 }
654 }
655 }
656 }
657 }
658 Exact => {
659 panic!("Cannot round {x} to {y} using RoundingMode {rm}")
660 }
661 }
662 }
663 }
664 }
665 }
666}
667
668impl RoundToMultipleAssign<&Self> for Natural {
669 /// Rounds a [`Natural`] to a multiple of another [`Natural`] in place, according to a specified
670 /// rounding mode. The [`Natural`] on the right-hand side is taken by reference. An [`Ordering`]
671 /// is also returned, indicating whether the returned value is less than, equal to, or greater
672 /// than the original value.
673 ///
674 /// See the [`RoundToMultiple`] documentation for details.
675 ///
676 /// The following two expressions are equivalent:
677 /// - `x.round_to_multiple_assign(other, Exact);`
678 /// - `assert!(x.divisible_by(other));`
679 ///
680 /// but the latter should be used as it is clearer and more efficient.
681 ///
682 /// # Worst-case complexity
683 /// $T(n) = O(n \log n \log\log n)$
684 ///
685 /// $M(n) = O(n \log n)$
686 ///
687 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
688 ///
689 /// # Panics
690 /// - If `rm` is `Exact`, but `self` is not a multiple of `other`.
691 /// - If `self` is nonzero, `other` is zero, and `rm` is trying to round away from zero.
692 ///
693 /// # Examples
694 /// ```
695 /// use core::cmp::Ordering::*;
696 /// use malachite_base::num::arithmetic::traits::RoundToMultipleAssign;
697 /// use malachite_base::num::basic::traits::Zero;
698 /// use malachite_base::rounding_modes::RoundingMode::*;
699 /// use malachite_nz::natural::Natural;
700 ///
701 /// let mut x = Natural::from(5u32);
702 /// assert_eq!(x.round_to_multiple_assign(&Natural::ZERO, Down), Less);
703 /// assert_eq!(x, 0);
704 ///
705 /// let mut x = Natural::from(10u32);
706 /// assert_eq!(x.round_to_multiple_assign(&Natural::from(4u32), Down), Less);
707 /// assert_eq!(x, 8);
708 ///
709 /// let mut x = Natural::from(10u32);
710 /// assert_eq!(
711 /// x.round_to_multiple_assign(&Natural::from(4u32), Up),
712 /// Greater
713 /// );
714 /// assert_eq!(x, 12);
715 ///
716 /// let mut x = Natural::from(10u32);
717 /// assert_eq!(
718 /// x.round_to_multiple_assign(&Natural::from(5u32), Exact),
719 /// Equal
720 /// );
721 /// assert_eq!(x, 10);
722 ///
723 /// let mut x = Natural::from(10u32);
724 /// assert_eq!(
725 /// x.round_to_multiple_assign(&Natural::from(3u32), Nearest),
726 /// Less
727 /// );
728 /// assert_eq!(x, 9);
729 ///
730 /// let mut x = Natural::from(20u32);
731 /// assert_eq!(
732 /// x.round_to_multiple_assign(&Natural::from(3u32), Nearest),
733 /// Greater
734 /// );
735 /// assert_eq!(x, 21);
736 ///
737 /// let mut x = Natural::from(10u32);
738 /// assert_eq!(
739 /// x.round_to_multiple_assign(&Natural::from(4u32), Nearest),
740 /// Less
741 /// );
742 /// assert_eq!(x, 8);
743 ///
744 /// let mut x = Natural::from(14u32);
745 /// assert_eq!(
746 /// x.round_to_multiple_assign(&Natural::from(4u32), Nearest),
747 /// Greater
748 /// );
749 /// assert_eq!(x, 16);
750 /// ```
751 fn round_to_multiple_assign(&mut self, other: &Self, rm: RoundingMode) -> Ordering {
752 match (&mut *self, other) {
753 (x, y) if *x == *y => Equal,
754 (x, &Self::ZERO) => match rm {
755 Down | Floor | Nearest => {
756 *self = Self::ZERO;
757 Less
758 }
759 _ => panic!("Cannot round {x} to zero using RoundingMode {rm}"),
760 },
761 (x, y) => {
762 let r = &*x % y;
763 if r == 0 {
764 Equal
765 } else {
766 *x -= &r;
767 match rm {
768 Down | Floor => Less,
769 Up | Ceiling => {
770 *x += y;
771 Greater
772 }
773 Nearest => {
774 match (r << 1u64).cmp(y) {
775 Less => Less,
776 Greater => {
777 *x += y;
778 Greater
779 }
780 Equal => {
781 // The even multiple of y will have more trailing zeros.
782 if *x == 0 {
783 Less
784 } else {
785 let ceiling = &*x + y;
786 if x.trailing_zeros() < ceiling.trailing_zeros() {
787 *x = ceiling;
788 Greater
789 } else {
790 Less
791 }
792 }
793 }
794 }
795 }
796 Exact => {
797 panic!("Cannot round {x} to {y} using RoundingMode {rm}")
798 }
799 }
800 }
801 }
802 }
803 }
804}