Skip to main content

malachite_nz/natural/arithmetic/
mod_power_of_2_mul.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::InnerNatural::{Large, Small};
10use crate::natural::arithmetic::mod_power_of_2::limbs_vec_mod_power_of_2_in_place;
11use crate::natural::arithmetic::mod_power_of_2_square::{
12    limbs_mod_power_of_2_square, limbs_mod_power_of_2_square_ref,
13};
14use crate::natural::arithmetic::mul::limbs_mul;
15use crate::natural::arithmetic::mul::mul_low::limbs_mul_low_same_length;
16use crate::natural::{Natural, bit_to_limb_count_ceiling};
17use crate::platform::{DoubleLimb, Limb};
18use alloc::vec::Vec;
19use malachite_base::num::arithmetic::traits::{
20    ModPowerOf2, ModPowerOf2Assign, ModPowerOf2Mul, ModPowerOf2MulAssign,
21};
22use malachite_base::num::basic::integers::PrimitiveInt;
23use malachite_base::num::basic::traits::{One, Zero};
24use malachite_base::num::logic::traits::SignificantBits;
25
26// Interpreting two `Vec<Limb>`s as the limbs (in ascending order) of two `Natural`s, returns a
27// `Vec` of the limbs of the product of the `Natural`s mod `2 ^ pow`. Assumes the inputs are already
28// reduced mod `2 ^ pow`. The input `Vec`s may be mutated. Neither input may be empty or have
29// trailing zeros.
30//
31// # Worst-case complexity
32// $T(n) = O(n \log n \log\log n)$
33//
34// $M(n) = O(n \log n)$
35//
36// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
37//
38// # Panics
39// Panics if either input is empty. May panic if either input has trailing zeros.
40pub_test! {limbs_mod_power_of_2_mul(xs: &mut Vec<Limb>, ys: &mut Vec<Limb>, pow: u64) -> Vec<Limb> {
41    if core::ptr::eq(xs.as_slice(), ys.as_slice()) {
42        return limbs_mod_power_of_2_square(xs, pow);
43    }
44    let xs_len = xs.len();
45    assert_ne!(xs_len, 0);
46    let ys_len = ys.len();
47    assert_ne!(ys_len, 0);
48    let max_len = bit_to_limb_count_ceiling(pow);
49    if max_len > xs_len + ys_len + 1 {
50        return limbs_mul(xs, ys);
51    }
52    // Should really be max_len / sqrt(2); 0.75 * max_len is close enough
53    let limit = max_len.checked_mul(3).unwrap() >> 2;
54    let mut product = if xs_len >= limit && ys_len >= limit {
55        if xs_len != max_len {
56            xs.resize(max_len, 0);
57        }
58        if ys_len != max_len {
59            ys.resize(max_len, 0);
60        }
61        let mut product_limbs = vec![0; max_len];
62        limbs_mul_low_same_length(&mut product_limbs, xs, ys);
63        product_limbs
64    } else {
65        limbs_mul(xs, ys)
66    };
67    limbs_vec_mod_power_of_2_in_place(&mut product, pow);
68    product
69}}
70
71// Interpreting a slice of `Limb` and a `Vec<Limb>` as the limbs (in ascending order) of two
72// `Natural`s, returns a `Vec` of the limbs of the product of the `Natural`s mod `2 ^ pow`. Assumes
73// the inputs are already reduced mod `2 ^ pow`. The input `Vec` may be mutated. Neither input may
74// be empty or have trailing zeros.
75//
76// # Worst-case complexity
77// $T(n) = O(n \log n \log\log n)$
78//
79// $M(n) = O(n \log n)$
80//
81// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
82//
83// # Panics
84// Panics if either input is empty. May panic if either input has trailing zeros.
85pub_test! {limbs_mod_power_of_2_mul_val_ref(
86    xs: &mut Vec<Limb>,
87    ys: &[Limb],
88    pow: u64
89) -> Vec<Limb> {
90    if core::ptr::eq(xs.as_slice(), ys) {
91        return limbs_mod_power_of_2_square(xs, pow);
92    }
93    let xs_len = xs.len();
94    assert_ne!(xs_len, 0);
95    let ys_len = ys.len();
96    assert_ne!(ys_len, 0);
97    let max_len = bit_to_limb_count_ceiling(pow);
98    if max_len > xs_len + ys_len + 1 {
99        return limbs_mul(xs, ys);
100    }
101    // Should really be max_len / sqrt(2); 0.75 * max_len is close enough
102    let limit = max_len.checked_mul(3).unwrap() >> 2;
103    let mut product = if xs_len >= limit && ys_len >= limit {
104        if xs_len != max_len {
105            xs.resize(max_len, 0);
106        }
107        let mut ys_adjusted_vec;
108        let ys_adjusted = if ys_len == max_len {
109            ys
110        } else {
111            ys_adjusted_vec = vec![0; max_len];
112            ys_adjusted_vec[..ys_len].copy_from_slice(ys);
113            &ys_adjusted_vec
114        };
115        let mut product = vec![0; max_len];
116        limbs_mul_low_same_length(&mut product, xs, ys_adjusted);
117        product
118    } else {
119        limbs_mul(xs, ys)
120    };
121    limbs_vec_mod_power_of_2_in_place(&mut product, pow);
122    product
123}}
124
125// Interpreting two slices of `Limb` as the limbs (in ascending order) of two `Natural`s, returns a
126// `Vec` of the limbs of the product of the `Natural`s mod `2 ^ pow`. Assumes the inputs are already
127// reduced mod `2 ^ pow`. Neither input may be empty or have trailing zeros.
128//
129// # Worst-case complexity
130// $T(n) = O(n \log n \log\log n)$
131//
132// $M(n) = O(n \log n)$
133//
134// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
135//
136// # Panics
137// Panics if either input is empty. May panic if either input has trailing zeros.
138pub_test! {limbs_mod_power_of_2_mul_ref_ref(xs: &[Limb], ys: &[Limb], pow: u64) -> Vec<Limb> {
139    if core::ptr::eq(xs, ys) {
140        return limbs_mod_power_of_2_square_ref(xs, pow);
141    }
142    let xs_len = xs.len();
143    assert_ne!(xs_len, 0);
144    let ys_len = ys.len();
145    assert_ne!(ys_len, 0);
146    let max_len = bit_to_limb_count_ceiling(pow);
147    if max_len > xs_len + ys_len + 1 {
148        return limbs_mul(xs, ys);
149    }
150    // Should really be max_len / sqrt(2); 0.75 * max_len is close enough
151    let limit = max_len.checked_mul(3).unwrap() >> 2;
152    let mut product = if xs_len >= limit && ys_len >= limit {
153        let mut xs_adjusted_vec;
154        let mut ys_adjusted_vec;
155        let xs_adjusted = if xs_len == max_len {
156            xs
157        } else {
158            xs_adjusted_vec = vec![0; max_len];
159            xs_adjusted_vec[..xs_len].copy_from_slice(xs);
160            &xs_adjusted_vec
161        };
162        let ys_adjusted = if ys_len == max_len {
163            ys
164        } else {
165            ys_adjusted_vec = vec![0; max_len];
166            ys_adjusted_vec[..ys_len].copy_from_slice(ys);
167            &ys_adjusted_vec
168        };
169        let mut product = vec![0; max_len];
170        limbs_mul_low_same_length(&mut product, xs_adjusted, ys_adjusted);
171        product
172    } else {
173        limbs_mul(xs, ys)
174    };
175    limbs_vec_mod_power_of_2_in_place(&mut product, pow);
176    product
177}}
178
179impl Natural {
180    fn mod_power_of_2_mul_limb_ref(&self, y: Limb, pow: u64) -> Self {
181        match (self, y, pow) {
182            (_, 0, _) | (&Self::ZERO, _, _) => Self::ZERO,
183            (_, 1, _) => self.clone(),
184            (&Self::ONE, _, _) => Self(Small(y)),
185            (&Self(Small(small)), other, pow) if pow <= Limb::WIDTH => {
186                Self(Small(small.mod_power_of_2_mul(other, pow)))
187            }
188            (&Self(Small(small)), other, pow) => {
189                Self::from((DoubleLimb::from(small) * DoubleLimb::from(other)).mod_power_of_2(pow))
190            }
191            (x, other, pow) => (x * Self::from(other)).mod_power_of_2(pow),
192        }
193    }
194
195    fn mod_power_of_2_mul_limb_assign(&mut self, y: Limb, pow: u64) {
196        match (&mut *self, y, pow) {
197            (_, 1, _) | (&mut Self::ZERO, _, _) => {}
198            (_, 0, _) => *self = Self::ZERO,
199            (&mut Self::ONE, _, _) => *self = Self(Small(y)),
200            (&mut Self(Small(ref mut small)), other, pow) if pow <= Limb::WIDTH => {
201                small.mod_power_of_2_mul_assign(other, pow);
202            }
203            (&mut Self(Small(small)), other, pow) => {
204                *self = Self::from(
205                    (DoubleLimb::from(small) * DoubleLimb::from(other)).mod_power_of_2(pow),
206                );
207            }
208            (x, other, pow) => {
209                *x *= Self::from(other);
210                x.mod_power_of_2_assign(pow);
211            }
212        }
213    }
214}
215
216impl ModPowerOf2Mul<Self> for Natural {
217    type Output = Self;
218
219    /// Multiplies two [`Natural`]s modulo $2^k$. The inputs must be already reduced modulo $2^k$.
220    /// Both [`Natural`]s are taken by value.
221    ///
222    /// $f(x, y, k) = z$, where $x, y, z < 2^k$ and $xy \equiv z \mod 2^k$.
223    ///
224    /// # Worst-case complexity
225    /// $T(n) = O(n \log n \log\log n)$
226    ///
227    /// $M(n) = O(n \log n)$
228    ///
229    /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
230    ///
231    /// # Panics
232    /// Panics if `self` or `other` are greater than or equal to $2^k$.
233    ///
234    /// # Examples
235    /// ```
236    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Mul;
237    /// use malachite_nz::natural::Natural;
238    ///
239    /// assert_eq!(
240    ///     Natural::from(3u32).mod_power_of_2_mul(Natural::from(2u32), 5),
241    ///     6
242    /// );
243    /// assert_eq!(
244    ///     Natural::from(10u32).mod_power_of_2_mul(Natural::from(14u32), 4),
245    ///     12
246    /// );
247    /// ```
248    #[inline]
249    fn mod_power_of_2_mul(mut self, other: Self, pow: u64) -> Self {
250        self.mod_power_of_2_mul_assign(other, pow);
251        self
252    }
253}
254
255impl<'a> ModPowerOf2Mul<&'a Self> for Natural {
256    type Output = Self;
257
258    /// Multiplies two [`Natural`]s modulo $2^k$. The inputs must be already reduced modulo $2^k$.
259    /// The first [`Natural`] is taken by value and the second by reference.
260    ///
261    /// $f(x, y, k) = z$, where $x, y, z < 2^k$ and $xy \equiv z \mod 2^k$.
262    ///
263    /// # Worst-case complexity
264    /// $T(n) = O(n \log n \log\log n)$
265    ///
266    /// $M(n) = O(n \log n)$
267    ///
268    /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
269    ///
270    /// # Panics
271    /// Panics if `self` or `other` are greater than or equal to $2^k$.
272    ///
273    /// # Examples
274    /// ```
275    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Mul;
276    /// use malachite_nz::natural::Natural;
277    ///
278    /// assert_eq!(
279    ///     Natural::from(3u32).mod_power_of_2_mul(&Natural::from(2u32), 5),
280    ///     6
281    /// );
282    /// assert_eq!(
283    ///     Natural::from(10u32).mod_power_of_2_mul(&Natural::from(14u32), 4),
284    ///     12
285    /// );
286    /// ```
287    #[inline]
288    fn mod_power_of_2_mul(mut self, other: &'a Self, pow: u64) -> Self {
289        self.mod_power_of_2_mul_assign(other, pow);
290        self
291    }
292}
293
294impl ModPowerOf2Mul<Natural> for &Natural {
295    type Output = Natural;
296
297    /// Multiplies two [`Natural`]s modulo $2^k$. The inputs must be already reduced modulo $2^k$.
298    /// The first [`Natural`] is taken by reference and the second by value.
299    ///
300    /// $f(x, y, k) = z$, where $x, y, z < 2^k$ and $xy \equiv z \mod 2^k$.
301    ///
302    /// # Worst-case complexity
303    /// $T(n) = O(n \log n \log\log n)$
304    ///
305    /// $M(n) = O(n \log n)$
306    ///
307    /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
308    ///
309    /// # Panics
310    /// Panics if `self` or `other` are greater than or equal to $2^k$.
311    ///
312    /// # Examples
313    /// ```
314    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Mul;
315    /// use malachite_nz::natural::Natural;
316    ///
317    /// assert_eq!(
318    ///     (&Natural::from(3u32)).mod_power_of_2_mul(Natural::from(2u32), 5),
319    ///     6
320    /// );
321    /// assert_eq!(
322    ///     (&Natural::from(10u32)).mod_power_of_2_mul(Natural::from(14u32), 4),
323    ///     12
324    /// );
325    /// ```
326    #[inline]
327    fn mod_power_of_2_mul(self, mut other: Natural, pow: u64) -> Natural {
328        other.mod_power_of_2_mul_assign(self, pow);
329        other
330    }
331}
332
333impl ModPowerOf2Mul<&Natural> for &Natural {
334    type Output = Natural;
335
336    /// Multiplies two [`Natural`]s modulo $2^k$. The inputs must be already reduced modulo $2^k$.
337    /// Both [`Natural`]s are taken by reference.
338    ///
339    /// $f(x, y, k) = z$, where $x, y, z < 2^k$ and $xy \equiv z \mod 2^k$.
340    ///
341    /// # Worst-case complexity
342    /// $T(n) = O(n \log n \log\log n)$
343    ///
344    /// $M(n) = O(n \log n)$
345    ///
346    /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
347    ///
348    /// # Panics
349    /// Panics if `self` or `other` are greater than or equal to $2^k$.
350    ///
351    /// # Examples
352    /// ```
353    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Mul;
354    /// use malachite_nz::natural::Natural;
355    ///
356    /// assert_eq!(
357    ///     (&Natural::from(3u32)).mod_power_of_2_mul(&Natural::from(2u32), 5),
358    ///     6
359    /// );
360    /// assert_eq!(
361    ///     (&Natural::from(10u32)).mod_power_of_2_mul(&Natural::from(14u32), 4),
362    ///     12
363    /// );
364    /// ```
365    fn mod_power_of_2_mul(self, other: &Natural, pow: u64) -> Natural {
366        assert!(
367            self.significant_bits() <= pow,
368            "self must be reduced mod 2^pow, but {self} >= 2^{pow}"
369        );
370        assert!(
371            other.significant_bits() <= pow,
372            "other must be reduced mod 2^pow, but {other} >= 2^{pow}"
373        );
374        match (self, other) {
375            (x, &Natural(Small(y))) => x.mod_power_of_2_mul_limb_ref(y, pow),
376            (&Natural(Small(x)), y) => y.mod_power_of_2_mul_limb_ref(x, pow),
377            (&Natural(Large(ref xs)), &Natural(Large(ref ys))) => {
378                Natural::from_owned_limbs_asc(limbs_mod_power_of_2_mul_ref_ref(xs, ys, pow))
379            }
380        }
381    }
382}
383
384impl ModPowerOf2MulAssign<Self> for Natural {
385    /// Multiplies two [`Natural`]s modulo $2^k$, in place. The inputs must be already reduced
386    /// modulo $2^k$. The [`Natural`] on the right-hand side is taken by value.
387    ///
388    /// $x \gets z$, where $x, y, z < 2^k$ and $x + y \equiv z \mod 2^k$.
389    ///
390    /// # Worst-case complexity
391    /// $T(n) = O(n \log n \log\log n)$
392    ///
393    /// $M(n) = O(n \log n)$
394    ///
395    /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
396    ///
397    /// # Panics
398    /// Panics if `self` or `other` are greater than or equal to $2^k$.
399    ///
400    /// # Examples
401    /// ```
402    /// use malachite_base::num::arithmetic::traits::ModPowerOf2MulAssign;
403    /// use malachite_nz::natural::Natural;
404    ///
405    /// let mut x = Natural::from(3u32);
406    /// x.mod_power_of_2_mul_assign(Natural::from(2u32), 5);
407    /// assert_eq!(x, 6);
408    ///
409    /// let mut x = Natural::from(10u32);
410    /// x.mod_power_of_2_mul_assign(Natural::from(14u32), 4);
411    /// assert_eq!(x, 12);
412    /// ```
413    fn mod_power_of_2_mul_assign(&mut self, mut other: Self, pow: u64) {
414        assert!(
415            self.significant_bits() <= pow,
416            "self must be reduced mod 2^pow, but {self} >= 2^{pow}"
417        );
418        assert!(
419            other.significant_bits() <= pow,
420            "other must be reduced mod 2^pow, but {other} >= 2^{pow}"
421        );
422        match (&mut *self, &mut other) {
423            (x, &mut Self(Small(y))) => x.mod_power_of_2_mul_limb_assign(y, pow),
424            (&mut Self(Small(x)), y) => {
425                y.mod_power_of_2_mul_limb_assign(x, pow);
426                *self = other;
427            }
428            (&mut Self(Large(ref mut xs)), &mut Self(Large(ref mut ys))) => {
429                *xs = limbs_mod_power_of_2_mul(xs, ys, pow);
430                self.trim();
431            }
432        }
433    }
434}
435
436impl<'a> ModPowerOf2MulAssign<&'a Self> for Natural {
437    /// Multiplies two [`Natural`]s modulo $2^k$, in place. The inputs must be already reduced
438    /// modulo $2^k$. The [`Natural`] on the right-hand side is taken by reference.
439    ///
440    /// $x \gets z$, where $x, y, z < 2^k$ and $x + y \equiv z \mod 2^k$.
441    ///
442    /// # Worst-case complexity
443    /// $T(n) = O(n \log n \log\log n)$
444    ///
445    /// $M(n) = O(n \log n)$
446    ///
447    /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
448    ///
449    /// # Panics
450    /// Panics if `self` or `other` are greater than or equal to $2^k$.
451    ///
452    /// # Examples
453    /// ```
454    /// use malachite_base::num::arithmetic::traits::ModPowerOf2MulAssign;
455    /// use malachite_nz::natural::Natural;
456    ///
457    /// let mut x = Natural::from(3u32);
458    /// x.mod_power_of_2_mul_assign(&Natural::from(2u32), 5);
459    /// assert_eq!(x, 6);
460    ///
461    /// let mut x = Natural::from(10u32);
462    /// x.mod_power_of_2_mul_assign(&Natural::from(14u32), 4);
463    /// assert_eq!(x, 12);
464    /// ```
465    fn mod_power_of_2_mul_assign(&mut self, other: &'a Self, pow: u64) {
466        assert!(
467            self.significant_bits() <= pow,
468            "self must be reduced mod 2^pow, but {self} >= 2^{pow}"
469        );
470        assert!(
471            other.significant_bits() <= pow,
472            "other must be reduced mod 2^pow, but {other} >= 2^{pow}"
473        );
474        match (&mut *self, other) {
475            (x, &Self(Small(y))) => x.mod_power_of_2_mul_limb_assign(y, pow),
476            (&mut Self(Small(x)), y) => {
477                *self = y.mod_power_of_2_mul_limb_ref(x, pow);
478            }
479            (&mut Self(Large(ref mut xs)), &Self(Large(ref ys))) => {
480                *xs = limbs_mod_power_of_2_mul_val_ref(xs, ys, pow);
481                self.trim();
482            }
483        }
484    }
485}