Skip to main content

malachite_nz/natural/arithmetic/
mod_shr.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::*;
11use core::ops::{Shr, ShrAssign};
12use malachite_base::num::arithmetic::traits::{
13    ModMul, ModMulAssign, ModPow, ModShr, ModShrAssign, UnsignedAbs,
14};
15use malachite_base::num::basic::signeds::PrimitiveSigned;
16use malachite_base::num::basic::traits::{One, Two, Zero};
17
18fn mod_shr_ref_val<'a, U, S: PrimitiveSigned + UnsignedAbs<Output = U>>(
19    x: &'a Natural,
20    bits: S,
21    m: Natural,
22) -> Natural
23where
24    Natural: From<U>,
25    &'a Natural: Shr<U, Output = Natural>,
26{
27    assert!(*x < m, "x must be reduced mod m, but {x} >= {m}");
28    let bits_abs = bits.unsigned_abs();
29    match bits.cmp(&S::ZERO) {
30        Equal => x.clone(),
31        Greater => x >> bits_abs,
32        Less => match m {
33            Natural::ONE | Natural::TWO => Natural::ZERO,
34            _ => x.mod_mul(Natural::TWO.mod_pow(Natural::from(bits_abs), &m), m),
35        },
36    }
37}
38
39fn mod_shr_ref_ref<'a, U, S: PrimitiveSigned + UnsignedAbs<Output = U>>(
40    x: &'a Natural,
41    bits: S,
42    m: &Natural,
43) -> Natural
44where
45    Natural: From<U>,
46    &'a Natural: Shr<U, Output = Natural>,
47{
48    assert!(x < m, "x must be reduced mod m, but {x} >= {m}");
49    let bits_abs = bits.unsigned_abs();
50    match bits.cmp(&S::ZERO) {
51        Equal => x.clone(),
52        Greater => x >> bits_abs,
53        Less => match m {
54            &Natural::ONE | &Natural::TWO => Natural::ZERO,
55            _ => x.mod_mul(Natural::TWO.mod_pow(Natural::from(bits_abs), m), m),
56        },
57    }
58}
59
60fn mod_shr_assign<U, S: PrimitiveSigned + UnsignedAbs<Output = U>>(
61    x: &mut Natural,
62    bits: S,
63    m: Natural,
64) where
65    Natural: From<U> + ShrAssign<U>,
66{
67    assert!(*x < m, "x must be reduced mod m, but {x} >= {m}");
68    let bits_abs = bits.unsigned_abs();
69    match bits.cmp(&S::ZERO) {
70        Equal => {}
71        Greater => *x >>= bits_abs,
72        Less => match m {
73            Natural::ONE | Natural::TWO => *x = Natural::ZERO,
74            _ => x.mod_mul_assign(Natural::TWO.mod_pow(Natural::from(bits_abs), &m), m),
75        },
76    }
77}
78
79fn mod_shr_assign_ref<U, S: PrimitiveSigned + UnsignedAbs<Output = U>>(
80    x: &mut Natural,
81    bits: S,
82    m: &Natural,
83) where
84    Natural: From<U> + ShrAssign<U>,
85{
86    assert!(*x < *m, "x must be reduced mod m, but {x} >= {m}");
87    let bits_abs = bits.unsigned_abs();
88    match bits.cmp(&S::ZERO) {
89        Equal => {}
90        Greater => *x >>= bits_abs,
91        Less => match m {
92            &Natural::ONE | &Natural::TWO => *x = Natural::ZERO,
93            _ => x.mod_mul_assign(Natural::TWO.mod_pow(Natural::from(bits_abs), m), m),
94        },
95    }
96}
97
98macro_rules! impl_mod_shr {
99    ($t:ident) => {
100        impl ModShr<$t, Natural> for Natural {
101            type Output = Natural;
102
103            /// Right-shifts a [`Natural`] (divides it by a power of 2) modulo another [`Natural`]
104            /// $m$. The first [`Natural`] must be already reduced modulo $m$. Both [`Natural`]s are
105            /// taken by value.
106            ///
107            /// $f(x, n, m) = y$, where $x, y < m$ and $\lfloor 2^{-n}x \rfloor \equiv y \mod m$.
108            ///
109            /// # Worst-case complexity
110            /// $T(n, m) = O(mn \log n \log\log n)$
111            ///
112            /// $M(n) = O(n \log n)$
113            ///
114            /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
115            /// is `bits`.
116            ///
117            /// # Panics
118            /// Panics if `self` is greater than or equal to `m`.
119            ///
120            /// # Examples
121            /// See [here](super::mod_shr#mod_shr).
122            #[inline]
123            fn mod_shr(mut self, bits: $t, m: Natural) -> Natural {
124                self.mod_shr_assign(bits, m);
125                self
126            }
127        }
128
129        impl<'a> ModShr<$t, &'a Natural> for Natural {
130            type Output = Natural;
131
132            /// Right-shifts a [`Natural`] (divides it by a power of 2) modulo another [`Natural`]
133            /// $m$. The first [`Natural`] must be already reduced modulo $m$. The first [`Natural`]
134            /// is taken by value and the second by reference.
135            ///
136            /// $f(x, n, m) = y$, where $x, y < m$ and $\lfloor 2^{-n}x \rfloor \equiv y \mod m$.
137            ///
138            /// # Worst-case complexity
139            /// $T(n, m) = O(mn \log n \log\log n)$
140            ///
141            /// $M(n) = O(n \log n)$
142            ///
143            /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
144            /// is `bits`.
145            ///
146            /// # Panics
147            /// Panics if `self` is greater than or equal to `m`.
148            ///
149            /// # Examples
150            /// See [here](super::mod_shr#mod_shr).
151            #[inline]
152            fn mod_shr(mut self, bits: $t, m: &'a Natural) -> Natural {
153                self.mod_shr_assign(bits, m);
154                self
155            }
156        }
157
158        impl ModShr<$t, Natural> for &Natural {
159            type Output = Natural;
160
161            /// Right-shifts a [`Natural`] (divides it by a power of 2) modulo another [`Natural`]
162            /// $m$. The first [`Natural`] must be already reduced modulo $m$. The first [`Natural`]
163            /// is taken by reference and the second by value.
164            ///
165            /// $f(x, n, m) = y$, where $x, y < m$ and $\lfloor 2^{-n}x \rfloor \equiv y \mod m$.
166            ///
167            /// # Worst-case complexity
168            /// $T(n, m) = O(mn \log n \log\log n)$
169            ///
170            /// $M(n) = O(n \log n)$
171            ///
172            /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
173            /// is `bits`.
174            ///
175            /// # Panics
176            /// Panics if `self` is greater than or equal to `m`.
177            ///
178            /// # Examples
179            /// See [here](super::mod_shr#mod_shr).
180            #[inline]
181            fn mod_shr(self, bits: $t, m: Natural) -> Natural {
182                mod_shr_ref_val(self, bits, m)
183            }
184        }
185
186        impl ModShr<$t, &Natural> for &Natural {
187            type Output = Natural;
188
189            /// Right-shifts a [`Natural`] (divides it by a power of 2) modulo another [`Natural`]
190            /// $m$. The first [`Natural`] must be already reduced modulo $m$. Both [`Natural`]s are
191            /// taken by reference.
192            ///
193            /// $f(x, n, m) = y$, where $x, y < m$ and $\lfloor 2^{-n}x \rfloor \equiv y \mod m$.
194            ///
195            /// # Worst-case complexity
196            /// $T(n, m) = O(mn \log n \log\log n)$
197            ///
198            /// $M(n) = O(n \log n)$
199            ///
200            /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
201            /// is `bits`.
202            ///
203            /// # Panics
204            /// Panics if `self` is greater than or equal to `m`.
205            ///
206            /// # Examples
207            /// See [here](super::mod_shr#mod_shr).
208            #[inline]
209            fn mod_shr(self, bits: $t, m: &Natural) -> Natural {
210                mod_shr_ref_ref(self, bits, m)
211            }
212        }
213
214        impl ModShrAssign<$t, Natural> for Natural {
215            /// Right-shifts a [`Natural`] (divides it by a power of 2) modulo another [`Natural`]
216            /// $m$, in place. The first [`Natural`] must be already reduced modulo $m$. The
217            /// [`Natural`] on the right-hand side is taken by value.
218            ///
219            /// $x \gets y$, where $x, y < m$ and $\lfloor 2^{-n}x \rfloor \equiv y \mod m$.
220            ///
221            /// # Worst-case complexity
222            /// $T(n, m) = O(mn \log n \log\log n)$
223            ///
224            /// $M(n) = O(n \log n)$
225            ///
226            /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
227            /// is `bits`.
228            ///
229            /// # Panics
230            /// Panics if `self` is greater than or equal to `m`.
231            ///
232            /// # Examples
233            /// See [here](super::mod_shr#mod_shr_assign).
234            #[inline]
235            fn mod_shr_assign(&mut self, bits: $t, m: Natural) {
236                mod_shr_assign(self, bits, m);
237            }
238        }
239
240        impl<'a> ModShrAssign<$t, &'a Natural> for Natural {
241            /// Right-shifts a [`Natural`] (divides it by a power of 2) modulo another [`Natural`]
242            /// $m$, in place. The first [`Natural`] must be already reduced modulo $m$. The
243            /// [`Natural`] on the right-hand side is taken by reference.
244            ///
245            /// $x \gets y$, where $x, y < m$ and $\lfloor 2^{-n}x \rfloor \equiv y \mod m$.
246            ///
247            /// # Worst-case complexity
248            /// $T(n, m) = O(mn \log n \log\log n)$
249            ///
250            /// $M(n) = O(n \log n)$
251            ///
252            /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
253            /// is `bits`.
254            ///
255            /// # Panics
256            /// Panics if `self` is greater than or equal to `m`.
257            ///
258            /// # Examples
259            /// See [here](super::mod_shr#mod_shr_assign).
260            #[inline]
261            fn mod_shr_assign(&mut self, bits: $t, m: &'a Natural) {
262                mod_shr_assign_ref(self, bits, m);
263            }
264        }
265    };
266}
267apply_to_signeds!(impl_mod_shr);