Skip to main content

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