malachite_base/unsigned_polynomial/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/>.
8use crate::num::arithmetic::traits::{ModPowerOf2Mul, ModPowerOf2MulAssign};
9use crate::num::basic::traits::Zero;
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::unsigned_polynomial::UnsignedPolynomial;
12use crate::unsigned_polynomial::arithmetic::mod_power_of_2_add::assert_reduced;
13use alloc::vec;
14use alloc::vec::Vec;
15
16// Multiplication of polynomials whose coefficients are words reduced modulo $2^k$, for $k$ no
17// greater than the word width W. Arithmetic modulo $2^\text{W}$ is wrapping arithmetic, and $2^k$
18// divides $2^\text{W}$, so the kernels compute with wrapping arithmetic throughout and reduce each
19// coefficient of the result once, at the end.
20
21// The length of the shorter factor at which Karatsuba multiplication overtakes classical
22// multiplication. Measured on an Apple M-series machine, 2026-10, for 64-bit words: Karatsuba
23// breaks even at 32 and wins from 40.
24pub(crate) const MOD_POWER_OF_2_MUL_KARATSUBA_THRESHOLD: usize = 32;
25
26// The length at which Karatsuba squaring overtakes classical squaring, which computes only half the
27// products and so stays ahead longer. Measured as above: Karatsuba loses at 64 and wins from 80.
28pub(crate) const MOD_POWER_OF_2_SQUARE_KARATSUBA_THRESHOLD: usize = 64;
29
30// Reduces each element of `xs` modulo $2^k$, where $k$ is `pow`.
31pub(crate) fn mask_coefficients<T: PrimitiveUnsigned>(xs: &mut [T], pow: u64) {
32 if pow < T::WIDTH {
33 let mask = T::low_mask(pow);
34 for x in xs {
35 *x &= mask;
36 }
37 }
38}
39
40// Adds each element of `ys` to the element of `xs` at the same index, wrapping.
41pub(crate) fn add_wrapping_assign<T: PrimitiveUnsigned>(xs: &mut [T], ys: &[T]) {
42 for (x, &y) in xs.iter_mut().zip(ys) {
43 x.wrapping_add_assign(y);
44 }
45}
46
47// Subtracts each element of `ys` from the element of `xs` at the same index, wrapping.
48pub(crate) fn sub_wrapping_assign<T: PrimitiveUnsigned>(xs: &mut [T], ys: &[T]) {
49 for (x, &y) in xs.iter_mut().zip(ys) {
50 x.wrapping_sub_assign(y);
51 }
52}
53
54// Sets `out` to the product of the polynomials with coefficients `xs` and `ys`, modulo
55// $2^\text{W}$, by schoolbook multiplication. `out` must have length `xs.len() + ys.len() - 1`.
56pub(crate) fn mul_classical_wrapping<T: PrimitiveUnsigned>(out: &mut [T], xs: &[T], ys: &[T]) {
57 out.fill(T::ZERO);
58 for (i, &x) in xs.iter().enumerate() {
59 if x != T::ZERO {
60 for (o, &y) in out[i..].iter_mut().zip(ys) {
61 o.wrapping_add_assign(x.wrapping_mul(y));
62 }
63 }
64 }
65}
66
67// The scratch length needed by `mul_karatsuba_balanced_wrapping` for factors of length `n`: at each
68// level of the recursion, two sums and their product, each about half as long.
69pub(crate) const fn karatsuba_wrapping_scratch_len(mut n: usize) -> usize {
70 let mut len = 0;
71 while n >= MOD_POWER_OF_2_MUL_KARATSUBA_THRESHOLD {
72 let c = n - (n >> 1);
73 len += (c << 2) - 1;
74 n = c;
75 }
76 len
77}
78
79// Sets `out` to the product of the polynomials with coefficients `xs` and `ys`, which have the same
80// nonzero length $n$, modulo $2^\text{W}$, by Karatsuba multiplication, falling back to schoolbook
81// multiplication below the threshold. `out` must have length $2n - 1$, and `scratch` at least
82// `karatsuba_wrapping_scratch_len(n)`.
83fn mul_karatsuba_balanced_wrapping<T: PrimitiveUnsigned>(
84 out: &mut [T],
85 xs: &[T],
86 ys: &[T],
87 scratch: &mut [T],
88) {
89 let n = xs.len();
90 if n < MOD_POWER_OF_2_MUL_KARATSUBA_THRESHOLD {
91 mul_classical_wrapping(out, xs, ys);
92 return;
93 }
94 // Write x = x_0 + x^h x_1 and y = y_0 + x^h y_1. Then xy = x_0 y_0 + x^h ((x_0 + x_1)(y_0 +
95 // y_1) - x_0 y_0 - x_1 y_1) + x^{2h} x_1 y_1.
96 let h = n >> 1;
97 let c = n - h;
98 let two_h = h << 1;
99 let (x0, x1) = xs.split_at(h);
100 let (y0, y1) = ys.split_at(h);
101 split_into_chunks_mut!(scratch, c, [x_sum, y_sum], scratch);
102 let (middle, scratch) = scratch.split_at_mut((c << 1) - 1);
103 let (low, high) = out.split_at_mut(two_h);
104 mul_karatsuba_balanced_wrapping(&mut low[..two_h - 1], x0, y0, scratch);
105 low[two_h - 1] = T::ZERO;
106 mul_karatsuba_balanced_wrapping(high, x1, y1, scratch);
107 x_sum.copy_from_slice(x1);
108 add_wrapping_assign(x_sum, x0);
109 y_sum.copy_from_slice(y1);
110 add_wrapping_assign(y_sum, y0);
111 mul_karatsuba_balanced_wrapping(middle, x_sum, y_sum, scratch);
112 sub_wrapping_assign(middle, &out[..two_h - 1]);
113 sub_wrapping_assign(middle, &out[two_h..]);
114 add_wrapping_assign(&mut out[h..], middle);
115}
116
117// Sets `out` to the product of the polynomials with coefficients `xs` and `ys`, both nonempty,
118// modulo $2^\text{W}$, by Karatsuba multiplication, falling back to schoolbook multiplication for
119// short factors. `out` must have length `xs.len() + ys.len() - 1`. When the factors' lengths
120// differ, the longer is cut into pieces as long as the shorter, and the products of the pieces are
121// added together.
122pub(crate) fn mul_karatsuba_wrapping<T: PrimitiveUnsigned>(out: &mut [T], xs: &[T], ys: &[T]) {
123 let (xs, ys) = if xs.len() >= ys.len() {
124 (xs, ys)
125 } else {
126 (ys, xs)
127 };
128 let n = xs.len();
129 let m = ys.len();
130 if m < MOD_POWER_OF_2_MUL_KARATSUBA_THRESHOLD {
131 mul_classical_wrapping(out, xs, ys);
132 return;
133 }
134 let mut scratch = vec![T::ZERO; karatsuba_wrapping_scratch_len(m)];
135 if n == m {
136 mul_karatsuba_balanced_wrapping(out, xs, ys, &mut scratch);
137 return;
138 }
139 out.fill(T::ZERO);
140 let mut product = vec![T::ZERO; (m << 1) - 1];
141 for (k, piece) in xs.chunks(m).enumerate() {
142 let product = &mut product[..piece.len() + m - 1];
143 if piece.len() == m {
144 mul_karatsuba_balanced_wrapping(product, piece, ys, &mut scratch);
145 } else {
146 mul_karatsuba_wrapping(product, ys, piece);
147 }
148 add_wrapping_assign(&mut out[k * m..], product);
149 }
150}
151
152fn assert_lengths<T>(out: &[T], xs: &[T], ys: &[T]) {
153 assert!(!xs.is_empty());
154 assert!(!ys.is_empty());
155 assert_eq!(out.len(), xs.len() + ys.len() - 1);
156}
157
158// Sets `out` to the product of the polynomials with coefficients `xs` and `ys`, both nonempty and
159// reduced modulo $2^k$, where $k$ is `pow`, by schoolbook multiplication. `out` must have length
160// `xs.len() + ys.len() - 1`, and `pow` must be no greater than `T::WIDTH`.
161crate_test_fn! {
162#[allow(dead_code)]
163mod_power_of_2_mul_to_out_classical<T: PrimitiveUnsigned>(
164 out: &mut [T],
165 xs: &[T],
166 ys: &[T],
167 pow: u64,
168) {
169 assert_lengths(out, xs, ys);
170 assert!(pow <= T::WIDTH);
171 mul_classical_wrapping(out, xs, ys);
172 mask_coefficients(out, pow);
173}}
174
175// Sets `out` to the product of the polynomials with coefficients `xs` and `ys`, both nonempty and
176// reduced modulo $2^k$, where $k$ is `pow`, by Karatsuba multiplication. `out` must have length
177// `xs.len() + ys.len() - 1`, and `pow` must be no greater than `T::WIDTH`.
178crate_test_fn! {
179#[allow(dead_code)]
180mod_power_of_2_mul_to_out_karatsuba<T: PrimitiveUnsigned>(
181 out: &mut [T],
182 xs: &[T],
183 ys: &[T],
184 pow: u64,
185) {
186 assert_lengths(out, xs, ys);
187 assert!(pow <= T::WIDTH);
188 mul_karatsuba_wrapping(out, xs, ys);
189 mask_coefficients(out, pow);
190}}
191
192/// Sets `out` to the product of the polynomials with coefficients `xs` and `ys`, both nonempty and
193/// reduced modulo $2^k$, where $k$ is `pow`. `out` must have length `xs.len() + ys.len() - 1`, and
194/// `pow` must be no greater than `T::WIDTH`.
195///
196/// This is not part of the public API; it is public so that `malachite-nz` can multiply
197/// `NaturalPolynomial`s with word-sized coefficients modulo $2^k$.
198#[doc(hidden)]
199pub fn mod_power_of_2_mul_to_out<T: PrimitiveUnsigned>(
200 out: &mut [T],
201 xs: &[T],
202 ys: &[T],
203 pow: u64,
204) {
205 assert_lengths(out, xs, ys);
206 assert!(pow <= T::WIDTH);
207 mul_karatsuba_wrapping(out, xs, ys);
208 mask_coefficients(out, pow);
209}
210
211// The polynomial whose coefficients are `xs`, trimmed.
212pub(crate) fn from_coefficients_trimmed<T: PrimitiveUnsigned>(xs: Vec<T>) -> UnsignedPolynomial<T> {
213 let mut p = UnsignedPolynomial { coefficients: xs };
214 p.trim();
215 p
216}
217
218// The product of the polynomials with coefficients `xs` and `ys`, both reduced modulo $2^k$, where
219// $k$ is `pow`, modulo $2^k$.
220pub(crate) fn mod_power_of_2_mul_helper<T: PrimitiveUnsigned>(
221 xs: &[T],
222 ys: &[T],
223 pow: u64,
224) -> UnsignedPolynomial<T> {
225 if xs.is_empty() || ys.is_empty() {
226 return UnsignedPolynomial::ZERO;
227 }
228 let mut out = vec![T::ZERO; xs.len() + ys.len() - 1];
229 mod_power_of_2_mul_to_out(&mut out, xs, ys, pow);
230 from_coefficients_trimmed(out)
231}
232
233impl<T: PrimitiveUnsigned> ModPowerOf2Mul<Self> for UnsignedPolynomial<T> {
234 type Output = Self;
235
236 /// Multiplies two [`UnsignedPolynomial`]s modulo $2^k$, taking both by value. The coefficients
237 /// of both must already be reduced modulo $2^k$.
238 ///
239 /// $$
240 /// f(p, q, k) = pq \bmod 2^k.
241 /// $$
242 ///
243 /// The leading coefficient of the product can vanish modulo $2^k$, and then the degree of the
244 /// product is lower than the sum of the degrees.
245 ///
246 /// # Worst-case complexity
247 /// $T(n) = O(n^{\log_2 3})$
248 ///
249 /// $M(n) = O(n)$
250 ///
251 /// where $T$ is time, $M$ is additional memory, and $n$ is the length of the longer polynomial.
252 ///
253 /// # Panics
254 /// Panics if `pow` is greater than `T::WIDTH`, or if any coefficient of `self` or `other` is
255 /// greater than or equal to $2^k$.
256 ///
257 /// # Examples
258 /// ```
259 /// use core::str::FromStr;
260 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Mul;
261 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
262 ///
263 /// // The coefficients wrap around modulo 16.
264 /// assert_eq!(
265 /// UnsignedPolynomial::<u8>::from_str("x^2+3*x+2")
266 /// .unwrap()
267 /// .mod_power_of_2_mul(UnsignedPolynomial::<u8>::from_str("2*x+5").unwrap(), 4)
268 /// .to_string(),
269 /// "2*x^3+11*x^2+3*x+10"
270 /// );
271 /// // The leading coefficient vanishes modulo 16, so the degree drops.
272 /// assert_eq!(
273 /// UnsignedPolynomial::<u8>::from_str("8*x+1")
274 /// .unwrap()
275 /// .mod_power_of_2_mul(UnsignedPolynomial::<u8>::from_str("2*x+1").unwrap(), 4)
276 /// .to_string(),
277 /// "10*x+1"
278 /// );
279 /// ```
280 ///
281 /// This is equivalent to `nmod_poly_mul` from `nmod_poly/mul.c`, FLINT 3.6.0, with the modulus
282 /// $2^k$.
283 fn mod_power_of_2_mul(self, other: Self, pow: u64) -> Self {
284 assert_reduced(&self, &other, pow);
285 mod_power_of_2_mul_helper(&self.coefficients, &other.coefficients, pow)
286 }
287}
288
289impl<T: PrimitiveUnsigned> ModPowerOf2Mul<&Self> for UnsignedPolynomial<T> {
290 type Output = Self;
291
292 /// Multiplies two [`UnsignedPolynomial`]s modulo $2^k$, taking the first by value and the
293 /// second by reference. The coefficients of both must already be reduced modulo $2^k$.
294 ///
295 /// $$
296 /// f(p, q, k) = pq \bmod 2^k.
297 /// $$
298 ///
299 /// The leading coefficient of the product can vanish modulo $2^k$, and then the degree of the
300 /// product is lower than the sum of the degrees.
301 ///
302 /// # Worst-case complexity
303 /// $T(n) = O(n^{\log_2 3})$
304 ///
305 /// $M(n) = O(n)$
306 ///
307 /// where $T$ is time, $M$ is additional memory, and $n$ is the length of the longer polynomial.
308 ///
309 /// # Panics
310 /// Panics if `pow` is greater than `T::WIDTH`, or if any coefficient of `self` or `other` is
311 /// greater than or equal to $2^k$.
312 ///
313 /// # Examples
314 /// ```
315 /// use core::str::FromStr;
316 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Mul;
317 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
318 ///
319 /// // The coefficients wrap around modulo 16.
320 /// assert_eq!(
321 /// UnsignedPolynomial::<u8>::from_str("x^2+3*x+2")
322 /// .unwrap()
323 /// .mod_power_of_2_mul(&UnsignedPolynomial::<u8>::from_str("2*x+5").unwrap(), 4)
324 /// .to_string(),
325 /// "2*x^3+11*x^2+3*x+10"
326 /// );
327 /// // The leading coefficient vanishes modulo 16, so the degree drops.
328 /// assert_eq!(
329 /// UnsignedPolynomial::<u8>::from_str("8*x+1")
330 /// .unwrap()
331 /// .mod_power_of_2_mul(&UnsignedPolynomial::<u8>::from_str("2*x+1").unwrap(), 4)
332 /// .to_string(),
333 /// "10*x+1"
334 /// );
335 /// ```
336 ///
337 /// This is equivalent to `nmod_poly_mul` from `nmod_poly/mul.c`, FLINT 3.6.0, with the modulus
338 /// $2^k$.
339 fn mod_power_of_2_mul(self, other: &Self, pow: u64) -> Self {
340 assert_reduced(&self, other, pow);
341 mod_power_of_2_mul_helper(&self.coefficients, &other.coefficients, pow)
342 }
343}
344
345impl<T: PrimitiveUnsigned> ModPowerOf2Mul<UnsignedPolynomial<T>> for &UnsignedPolynomial<T> {
346 type Output = UnsignedPolynomial<T>;
347
348 /// Multiplies two [`UnsignedPolynomial`]s modulo $2^k$, taking the first by reference and the
349 /// second by value. The coefficients of both must already be reduced modulo $2^k$.
350 ///
351 /// $$
352 /// f(p, q, k) = pq \bmod 2^k.
353 /// $$
354 ///
355 /// The leading coefficient of the product can vanish modulo $2^k$, and then the degree of the
356 /// product is lower than the sum of the degrees.
357 ///
358 /// # Worst-case complexity
359 /// $T(n) = O(n^{\log_2 3})$
360 ///
361 /// $M(n) = O(n)$
362 ///
363 /// where $T$ is time, $M$ is additional memory, and $n$ is the length of the longer polynomial.
364 ///
365 /// # Panics
366 /// Panics if `pow` is greater than `T::WIDTH`, or if any coefficient of `self` or `other` is
367 /// greater than or equal to $2^k$.
368 ///
369 /// # Examples
370 /// ```
371 /// use core::str::FromStr;
372 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Mul;
373 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
374 ///
375 /// // The coefficients wrap around modulo 16.
376 /// assert_eq!(
377 /// (&UnsignedPolynomial::<u8>::from_str("x^2+3*x+2").unwrap())
378 /// .mod_power_of_2_mul(UnsignedPolynomial::<u8>::from_str("2*x+5").unwrap(), 4)
379 /// .to_string(),
380 /// "2*x^3+11*x^2+3*x+10"
381 /// );
382 /// // The leading coefficient vanishes modulo 16, so the degree drops.
383 /// assert_eq!(
384 /// (&UnsignedPolynomial::<u8>::from_str("8*x+1").unwrap())
385 /// .mod_power_of_2_mul(UnsignedPolynomial::<u8>::from_str("2*x+1").unwrap(), 4)
386 /// .to_string(),
387 /// "10*x+1"
388 /// );
389 /// ```
390 ///
391 /// This is equivalent to `nmod_poly_mul` from `nmod_poly/mul.c`, FLINT 3.6.0, with the modulus
392 /// $2^k$.
393 fn mod_power_of_2_mul(self, other: UnsignedPolynomial<T>, pow: u64) -> UnsignedPolynomial<T> {
394 assert_reduced(self, &other, pow);
395 mod_power_of_2_mul_helper(&self.coefficients, &other.coefficients, pow)
396 }
397}
398
399impl<T: PrimitiveUnsigned> ModPowerOf2Mul<&UnsignedPolynomial<T>> for &UnsignedPolynomial<T> {
400 type Output = UnsignedPolynomial<T>;
401
402 /// Multiplies two [`UnsignedPolynomial`]s modulo $2^k$, taking both by reference. The
403 /// coefficients of both must already be reduced modulo $2^k$.
404 ///
405 /// $$
406 /// f(p, q, k) = pq \bmod 2^k.
407 /// $$
408 ///
409 /// The leading coefficient of the product can vanish modulo $2^k$, and then the degree of the
410 /// product is lower than the sum of the degrees.
411 ///
412 /// # Worst-case complexity
413 /// $T(n) = O(n^{\log_2 3})$
414 ///
415 /// $M(n) = O(n)$
416 ///
417 /// where $T$ is time, $M$ is additional memory, and $n$ is the length of the longer polynomial.
418 ///
419 /// # Panics
420 /// Panics if `pow` is greater than `T::WIDTH`, or if any coefficient of `self` or `other` is
421 /// greater than or equal to $2^k$.
422 ///
423 /// # Examples
424 /// ```
425 /// use core::str::FromStr;
426 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Mul;
427 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
428 ///
429 /// // The coefficients wrap around modulo 16.
430 /// assert_eq!(
431 /// (&UnsignedPolynomial::<u8>::from_str("x^2+3*x+2").unwrap())
432 /// .mod_power_of_2_mul(&UnsignedPolynomial::<u8>::from_str("2*x+5").unwrap(), 4)
433 /// .to_string(),
434 /// "2*x^3+11*x^2+3*x+10"
435 /// );
436 /// // The leading coefficient vanishes modulo 16, so the degree drops.
437 /// assert_eq!(
438 /// (&UnsignedPolynomial::<u8>::from_str("8*x+1").unwrap())
439 /// .mod_power_of_2_mul(&UnsignedPolynomial::<u8>::from_str("2*x+1").unwrap(), 4)
440 /// .to_string(),
441 /// "10*x+1"
442 /// );
443 /// ```
444 ///
445 /// This is equivalent to `nmod_poly_mul` from `nmod_poly/mul.c`, FLINT 3.6.0, with the modulus
446 /// $2^k$.
447 fn mod_power_of_2_mul(self, other: &UnsignedPolynomial<T>, pow: u64) -> UnsignedPolynomial<T> {
448 assert_reduced(self, other, pow);
449 mod_power_of_2_mul_helper(&self.coefficients, &other.coefficients, pow)
450 }
451}
452
453impl<T: PrimitiveUnsigned> ModPowerOf2MulAssign<Self> for UnsignedPolynomial<T> {
454 /// Multiplies an [`UnsignedPolynomial`] by another [`UnsignedPolynomial`] modulo $2^k$ in
455 /// place, taking the right-hand side by value. The coefficients of both must already be reduced
456 /// modulo $2^k$.
457 ///
458 /// $$
459 /// p \gets pq \bmod 2^k.
460 /// $$
461 ///
462 /// # Worst-case complexity
463 /// $T(n) = O(n^{\log_2 3})$
464 ///
465 /// $M(n) = O(n)$
466 ///
467 /// where $T$ is time, $M$ is additional memory, and $n$ is the length of the longer polynomial.
468 ///
469 /// # Panics
470 /// Panics if `pow` is greater than `T::WIDTH`, or if any coefficient of `self` or `other` is
471 /// greater than or equal to $2^k$.
472 ///
473 /// # Examples
474 /// ```
475 /// use core::str::FromStr;
476 /// use malachite_base::num::arithmetic::traits::ModPowerOf2MulAssign;
477 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
478 ///
479 /// let mut p = UnsignedPolynomial::<u8>::from_str("x^2+3*x+2").unwrap();
480 /// p.mod_power_of_2_mul_assign(UnsignedPolynomial::<u8>::from_str("2*x+5").unwrap(), 4);
481 /// assert_eq!(p.to_string(), "2*x^3+11*x^2+3*x+10");
482 /// ```
483 ///
484 /// This is equivalent to `nmod_poly_mul` from `nmod_poly/mul.c`, FLINT 3.6.0, with the modulus
485 /// $2^k$.
486 fn mod_power_of_2_mul_assign(&mut self, other: Self, pow: u64) {
487 assert_reduced(self, &other, pow);
488 *self = mod_power_of_2_mul_helper(&self.coefficients, &other.coefficients, pow);
489 }
490}
491
492impl<T: PrimitiveUnsigned> ModPowerOf2MulAssign<&Self> for UnsignedPolynomial<T> {
493 /// Multiplies an [`UnsignedPolynomial`] by another [`UnsignedPolynomial`] modulo $2^k$ in
494 /// place, taking the right-hand side by reference. The coefficients of both must already be
495 /// reduced modulo $2^k$.
496 ///
497 /// $$
498 /// p \gets pq \bmod 2^k.
499 /// $$
500 ///
501 /// # Worst-case complexity
502 /// $T(n) = O(n^{\log_2 3})$
503 ///
504 /// $M(n) = O(n)$
505 ///
506 /// where $T$ is time, $M$ is additional memory, and $n$ is the length of the longer polynomial.
507 ///
508 /// # Panics
509 /// Panics if `pow` is greater than `T::WIDTH`, or if any coefficient of `self` or `other` is
510 /// greater than or equal to $2^k$.
511 ///
512 /// # Examples
513 /// ```
514 /// use core::str::FromStr;
515 /// use malachite_base::num::arithmetic::traits::ModPowerOf2MulAssign;
516 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
517 ///
518 /// let mut p = UnsignedPolynomial::<u8>::from_str("x^2+3*x+2").unwrap();
519 /// p.mod_power_of_2_mul_assign(&UnsignedPolynomial::<u8>::from_str("2*x+5").unwrap(), 4);
520 /// assert_eq!(p.to_string(), "2*x^3+11*x^2+3*x+10");
521 /// ```
522 ///
523 /// This is equivalent to `nmod_poly_mul` from `nmod_poly/mul.c`, FLINT 3.6.0, with the modulus
524 /// $2^k$.
525 fn mod_power_of_2_mul_assign(&mut self, other: &Self, pow: u64) {
526 assert_reduced(self, other, pow);
527 *self = mod_power_of_2_mul_helper(&self.coefficients, &other.coefficients, pow);
528 }
529}