Skip to main content

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}