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}