malachite_nz/natural/arithmetic/mod_shl.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, ModShl, ModShlAssign, UnsignedAbs,
14};
15use malachite_base::num::basic::signeds::PrimitiveSigned;
16use malachite_base::num::basic::traits::{One, Two, Zero};
17use malachite_base::num::basic::unsigneds::PrimitiveUnsigned;
18
19fn mod_shl_ref_val_unsigned<T: PrimitiveUnsigned>(x: &Natural, bits: T, m: Natural) -> Natural
20where
21 Natural: From<T>,
22{
23 assert!(*x < m, "x must be reduced mod m, but {x} >= {m}");
24 if bits == T::ZERO {
25 x.clone()
26 } else {
27 match m {
28 Natural::ONE | Natural::TWO => Natural::ZERO,
29 _ => x.mod_mul(Natural::TWO.mod_pow(Natural::from(bits), &m), m),
30 }
31 }
32}
33
34fn mod_shl_ref_ref_unsigned<T: PrimitiveUnsigned>(x: &Natural, bits: T, m: &Natural) -> Natural
35where
36 Natural: From<T>,
37{
38 assert!(x < m, "x must be reduced mod m, but {x} >= {m}");
39 if bits == T::ZERO {
40 x.clone()
41 } else {
42 match m {
43 &Natural::ONE | &Natural::TWO => Natural::ZERO,
44 _ => x.mod_mul(Natural::TWO.mod_pow(Natural::from(bits), m), m),
45 }
46 }
47}
48
49fn mod_shl_assign_unsigned_nz<T: PrimitiveUnsigned>(x: &mut Natural, bits: T, m: Natural)
50where
51 Natural: From<T>,
52{
53 assert!(*x < m, "x must be reduced mod m, but {x} >= {m}");
54 if bits != T::ZERO {
55 match m {
56 Natural::ONE | Natural::TWO => *x = Natural::ZERO,
57 _ => x.mod_mul_assign(Natural::TWO.mod_pow(Natural::from(bits), &m), m),
58 }
59 }
60}
61
62fn mod_shl_assign_ref_unsigned<T: PrimitiveUnsigned>(x: &mut Natural, bits: T, m: &Natural)
63where
64 Natural: From<T>,
65{
66 assert!(*x < *m, "x must be reduced mod m, but {x} >= {m}");
67 if bits != T::ZERO {
68 match m {
69 &Natural::ONE | &Natural::TWO => *x = Natural::ZERO,
70 _ => x.mod_mul_assign(Natural::TWO.mod_pow(Natural::from(bits), m), m),
71 }
72 }
73}
74
75macro_rules! impl_mod_shl_unsigned {
76 ($t:ident) => {
77 impl ModShl<$t, Natural> for Natural {
78 type Output = Natural;
79
80 /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo another [`Natural`]
81 /// $m$. The first [`Natural`] must be already reduced modulo $m$. Both [`Natural`]s are
82 /// taken by value.
83 ///
84 /// $f(x, n, m) = y$, where $x, y < m$ and $2^nx \equiv y \mod m$.
85 ///
86 /// # Worst-case complexity
87 /// $T(n, m) = O(mn \log n \log\log n)$
88 ///
89 /// $M(n) = O(n \log n)$
90 ///
91 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
92 /// is `bits`.
93 ///
94 /// # Panics
95 /// Panics if `self` is greater than or equal to `m`.
96 ///
97 /// # Examples
98 /// See [here](super::mod_shl#mod_shl).
99 #[inline]
100 fn mod_shl(mut self, bits: $t, m: Natural) -> Natural {
101 self.mod_shl_assign(bits, m);
102 self
103 }
104 }
105
106 impl<'a> ModShl<$t, &'a Natural> for Natural {
107 type Output = Natural;
108
109 /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo another [`Natural`]
110 /// $m$. The first [`Natural`] must be already reduced modulo $m$. The first [`Natural`]
111 /// is taken by value and the second by reference.
112 ///
113 /// $f(x, n, m) = y$, where $x, y < m$ and $2^nx \equiv y \mod m$.
114 ///
115 /// # Worst-case complexity
116 /// $T(n, m) = O(mn \log n \log\log n)$
117 ///
118 /// $M(n) = O(n \log n)$
119 ///
120 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
121 /// is `bits`.
122 ///
123 /// # Panics
124 /// Panics if `self` is greater than or equal to `m`.
125 ///
126 /// # Examples
127 /// See [here](super::mod_shl#mod_shl).
128 #[inline]
129 fn mod_shl(mut self, bits: $t, m: &'a Natural) -> Natural {
130 self.mod_shl_assign(bits, m);
131 self
132 }
133 }
134
135 impl ModShl<$t, Natural> for &Natural {
136 type Output = Natural;
137
138 /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo another [`Natural`]
139 /// $m$. The first [`Natural`] must be already reduced modulo $m$. The first [`Natural`]
140 /// is taken by reference and the second by value.
141 ///
142 /// $f(x, n, m) = y$, where $x, y < m$ and $2^nx \equiv y \mod m$.
143 ///
144 /// # Worst-case complexity
145 /// $T(n, m) = O(mn \log n \log\log n)$
146 ///
147 /// $M(n) = O(n \log n)$
148 ///
149 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
150 /// is `bits`.
151 ///
152 /// # Panics
153 /// Panics if `self` is greater than or equal to `m`.
154 ///
155 /// # Examples
156 /// See [here](super::mod_shl#mod_shl).
157 #[inline]
158 fn mod_shl(self, bits: $t, m: Natural) -> Natural {
159 mod_shl_ref_val_unsigned(self, bits, m)
160 }
161 }
162
163 impl ModShl<$t, &Natural> for &Natural {
164 type Output = Natural;
165
166 /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo another [`Natural`]
167 /// $m$. The first [`Natural`] must be already reduced modulo $m$. Both [`Natural`]s are
168 /// taken by reference.
169 ///
170 /// $f(x, n, m) = y$, where $x, y < m$ and $2^nx \equiv y \mod m$.
171 ///
172 /// # Worst-case complexity
173 /// $T(n, m) = O(mn \log n \log\log n)$
174 ///
175 /// $M(n) = O(n \log n)$
176 ///
177 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
178 /// is `bits`.
179 ///
180 /// # Panics
181 /// Panics if `self` is greater than or equal to `m`.
182 ///
183 /// # Examples
184 /// See [here](super::mod_shl#mod_shl).
185 #[inline]
186 fn mod_shl(self, bits: $t, m: &Natural) -> Natural {
187 mod_shl_ref_ref_unsigned(self, bits, m)
188 }
189 }
190
191 impl ModShlAssign<$t, Natural> for Natural {
192 /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo another [`Natural`]
193 /// $m$, in place. The first [`Natural`] must be already reduced modulo $m$. The
194 /// [`Natural`] on the right-hand side is taken by value.
195 ///
196 /// $x \gets y$, where $x, y < m$ and $2^nx \equiv y \mod m$.
197 ///
198 /// # Worst-case complexity
199 /// $T(n, m) = O(mn \log n \log\log n)$
200 ///
201 /// $M(n) = O(n \log n)$
202 ///
203 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
204 /// is `bits`.
205 ///
206 /// # Panics
207 /// Panics if `self` is greater than or equal to `m`.
208 ///
209 /// # Examples
210 /// See [here](super::mod_shl#mod_shl_assign).
211 #[inline]
212 fn mod_shl_assign(&mut self, bits: $t, m: Natural) {
213 mod_shl_assign_unsigned_nz(self, bits, m);
214 }
215 }
216
217 impl ModShlAssign<$t, &Natural> for Natural {
218 /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo another [`Natural`]
219 /// $m$, in place. The first [`Natural`] must be already reduced modulo $m$. The
220 /// [`Natural`] on the right-hand side is taken by reference.
221 ///
222 /// $x \gets y$, where $x, y < m$ and $2^nx \equiv y \mod m$.
223 ///
224 /// # Worst-case complexity
225 /// $T(n, m) = O(mn \log n \log\log n)$
226 ///
227 /// $M(n) = O(n \log n)$
228 ///
229 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
230 /// is `bits`.
231 ///
232 /// # Panics
233 /// Panics if `self` is greater than or equal to `m`.
234 ///
235 /// # Examples
236 /// See [here](super::mod_shl#mod_shl_assign).
237 #[inline]
238 fn mod_shl_assign(&mut self, bits: $t, m: &Natural) {
239 mod_shl_assign_ref_unsigned(self, bits, m);
240 }
241 }
242 };
243}
244apply_to_unsigneds!(impl_mod_shl_unsigned);
245
246fn mod_shl_ref_val_signed<'a, U, S: PrimitiveSigned + UnsignedAbs<Output = U>>(
247 x: &'a Natural,
248 bits: S,
249 m: Natural,
250) -> Natural
251where
252 Natural: From<U>,
253 &'a Natural: Shr<U, Output = Natural>,
254{
255 assert!(*x < m, "x must be reduced mod m, but {x} >= {m}");
256 let bits_abs = bits.unsigned_abs();
257 match bits.cmp(&S::ZERO) {
258 Equal => x.clone(),
259 Less => x >> bits_abs,
260 Greater => match m {
261 Natural::ONE | Natural::TWO => Natural::ZERO,
262 _ => x.mod_mul(Natural::TWO.mod_pow(Natural::from(bits_abs), &m), m),
263 },
264 }
265}
266
267fn mod_shl_ref_ref_signed<'a, U, S: PrimitiveSigned + UnsignedAbs<Output = U>>(
268 x: &'a Natural,
269 bits: S,
270 m: &Natural,
271) -> Natural
272where
273 Natural: From<U>,
274 &'a Natural: Shr<U, Output = Natural>,
275{
276 assert!(x < m, "x must be reduced mod m, but {x} >= {m}");
277 let bits_abs = bits.unsigned_abs();
278 match bits.cmp(&S::ZERO) {
279 Equal => x.clone(),
280 Less => x >> bits_abs,
281 Greater => match m {
282 &Natural::ONE | &Natural::TWO => Natural::ZERO,
283 _ => x.mod_mul(Natural::TWO.mod_pow(Natural::from(bits_abs), m), m),
284 },
285 }
286}
287
288fn mod_shl_assign_signed_nz<U, S: PrimitiveSigned + UnsignedAbs<Output = U>>(
289 x: &mut Natural,
290 bits: S,
291 m: Natural,
292) where
293 Natural: From<U> + ShrAssign<U>,
294{
295 assert!(*x < m, "x must be reduced mod m, but {x} >= {m}");
296 let bits_abs = bits.unsigned_abs();
297 match bits.cmp(&S::ZERO) {
298 Equal => {}
299 Less => *x >>= bits_abs,
300 Greater => match m {
301 Natural::ONE | Natural::TWO => *x = Natural::ZERO,
302 _ => x.mod_mul_assign(Natural::TWO.mod_pow(Natural::from(bits_abs), &m), m),
303 },
304 }
305}
306
307fn mod_shl_assign_ref_signed<U, S: PrimitiveSigned + UnsignedAbs<Output = U>>(
308 x: &mut Natural,
309 bits: S,
310 m: &Natural,
311) where
312 Natural: From<U> + ShrAssign<U>,
313{
314 assert!(*x < *m, "x must be reduced mod m, but {x} >= {m}");
315 let bits_abs = bits.unsigned_abs();
316 match bits.cmp(&S::ZERO) {
317 Equal => {}
318 Less => *x >>= bits_abs,
319 Greater => match m {
320 &Natural::ONE | &Natural::TWO => *x = Natural::ZERO,
321 _ => x.mod_mul_assign(Natural::TWO.mod_pow(Natural::from(bits_abs), m), m),
322 },
323 }
324}
325
326macro_rules! impl_mod_shl_signed {
327 ($t:ident) => {
328 impl ModShl<$t, Natural> for Natural {
329 type Output = Natural;
330
331 /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo another [`Natural`]
332 /// $m$. The first [`Natural`] must be already reduced modulo $m$. Both [`Natural`]s are
333 /// taken by value.
334 ///
335 /// $f(x, n, m) = y$, where $x, y < m$ and $\lfloor 2^nx \rfloor \equiv y \mod m$.
336 ///
337 /// # Worst-case complexity
338 /// $T(n, m) = O(mn \log n \log\log n)$
339 ///
340 /// $M(n) = O(n \log n)$
341 ///
342 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
343 /// is `bits`.
344 ///
345 /// # Panics
346 /// Panics if `self` is greater than or equal to `m`.
347 ///
348 /// # Examples
349 /// See [here](super::mod_shl#mod_shl).
350 #[inline]
351 fn mod_shl(mut self, bits: $t, m: Natural) -> Natural {
352 self.mod_shl_assign(bits, m);
353 self
354 }
355 }
356
357 impl ModShl<$t, &Natural> for Natural {
358 type Output = Natural;
359
360 /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo another [`Natural`]
361 /// $m$. The first [`Natural`] must be already reduced modulo $m$. The first [`Natural`]
362 /// is taken by value and the second by reference.
363 ///
364 /// $f(x, n, m) = y$, where $x, y < m$ and $\lfloor 2^nx \rfloor \equiv y \mod m$.
365 ///
366 /// # Worst-case complexity
367 /// $T(n, m) = O(mn \log n \log\log n)$
368 ///
369 /// $M(n) = O(n \log n)$
370 ///
371 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
372 /// is `bits`.
373 ///
374 /// # Panics
375 /// Panics if `self` is greater than or equal to `m`.
376 ///
377 /// # Examples
378 /// See [here](super::mod_shl#mod_shl).
379 #[inline]
380 fn mod_shl(mut self, bits: $t, m: &Natural) -> Natural {
381 self.mod_shl_assign(bits, m);
382 self
383 }
384 }
385
386 impl ModShl<$t, Natural> for &Natural {
387 type Output = Natural;
388
389 /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo another [`Natural`]
390 /// $m$. The first [`Natural`] must be already reduced modulo $m$. The first [`Natural`]
391 /// is taken by reference and the second by value.
392 ///
393 /// $f(x, n, m) = y$, where $x, y < m$ and $\lfloor 2^nx \rfloor \equiv y \mod m$.
394 ///
395 /// # Worst-case complexity
396 /// $T(n, m) = O(mn \log n \log\log n)$
397 ///
398 /// $M(n) = O(n \log n)$
399 ///
400 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
401 /// is `bits`.
402 ///
403 /// # Panics
404 /// Panics if `self` is greater than or equal to `m`.
405 ///
406 /// # Examples
407 /// See [here](super::mod_shl#mod_shl).
408 #[inline]
409 fn mod_shl(self, bits: $t, m: Natural) -> Natural {
410 mod_shl_ref_val_signed(self, bits, m)
411 }
412 }
413
414 impl ModShl<$t, &Natural> for &Natural {
415 type Output = Natural;
416
417 /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo another [`Natural`]
418 /// $m$. The first [`Natural`] must be already reduced modulo $m$. Both [`Natural`]s are
419 /// taken by reference.
420 ///
421 /// $f(x, n, m) = y$, where $x, y < m$ and $\lfloor 2^nx \rfloor \equiv y \mod m$.
422 ///
423 /// # Worst-case complexity
424 /// $T(n, m) = O(mn \log n \log\log n)$
425 ///
426 /// $M(n) = O(n \log n)$
427 ///
428 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
429 /// is `bits`.
430 ///
431 /// # Panics
432 /// Panics if `self` is greater than or equal to `m`.
433 ///
434 /// # Examples
435 /// See [here](super::mod_shl#mod_shl).
436 #[inline]
437 fn mod_shl(self, bits: $t, m: &Natural) -> Natural {
438 mod_shl_ref_ref_signed(self, bits, m)
439 }
440 }
441
442 impl ModShlAssign<$t, Natural> for Natural {
443 /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo another [`Natural`]
444 /// $m$, in place. The first [`Natural`] must be already reduced modulo $m$. The
445 /// [`Natural`] on the right-hand side is taken by value.
446 ///
447 /// $x \gets y$, where $x, y < m$ and $\lfloor 2^nx \rfloor \equiv y \mod m$.
448 ///
449 /// # Worst-case complexity
450 /// $T(n, m) = O(mn \log n \log\log n)$
451 ///
452 /// $M(n) = O(n \log n)$
453 ///
454 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
455 /// is `bits`.
456 ///
457 /// # Panics
458 /// Panics if `self` is greater than or equal to `m`.
459 ///
460 /// # Examples
461 /// See [here](super::mod_shl#mod_shl_assign).
462 #[inline]
463 fn mod_shl_assign(&mut self, bits: $t, m: Natural) {
464 mod_shl_assign_signed_nz(self, bits, m);
465 }
466 }
467
468 impl ModShlAssign<$t, &Natural> for Natural {
469 /// Left-shifts a [`Natural`] (multiplies it by a power of 2) modulo another [`Natural`]
470 /// $m$, in place. The first [`Natural`] must be already reduced modulo $m$. The
471 /// [`Natural`] on the right-hand side is taken by reference.
472 ///
473 /// $x \gets y$, where $x, y < m$ and $\lfloor 2^nx \rfloor \equiv y \mod m$.
474 ///
475 /// # Worst-case complexity
476 /// $T(n, m) = O(mn \log n \log\log n)$
477 ///
478 /// $M(n) = O(n \log n)$
479 ///
480 /// where $T$ is time, $M$ is additional memory, $n$ is `m.significant_bits()`, and $m$
481 /// is `bits`.
482 ///
483 /// # Panics
484 /// Panics if `self` is greater than or equal to `m`.
485 ///
486 /// # Examples
487 /// See [here](super::mod_shl#mod_shl_assign).
488 #[inline]
489 fn mod_shl_assign(&mut self, bits: $t, m: &Natural) {
490 mod_shl_assign_ref_signed(self, bits, m);
491 }
492 }
493 };
494}
495apply_to_signeds!(impl_mod_shl_signed);