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);