malachite_nz/natural/arithmetic/mul/mod.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// Some optimizations contributed by florian1345.
4//
5// Uses code adopted from the GNU MP Library.
6//
7// `mpn_mul` and `TOOM44_OK` contributed to the GNU project by Torbjörn Granlund.
8//
9// Copyright © 1991—1994, 1996, 1996-2003, 2005-2007, 2008, 2009, 2010, 2012, 2014, 2019
10// Free Software Foundation, Inc.
11//
12// This file is part of Malachite.
13//
14// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
15// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
16// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
17
18use crate::natural::InnerNatural::{Large, Small};
19use crate::natural::Natural;
20use crate::natural::arithmetic::add::limbs_slice_add_greater_in_place_left;
21use crate::natural::arithmetic::add_mul::{
22 limbs_slice_add_mul_limb_same_length_in_place_left,
23 limbs_slice_add_mul_two_limbs_matching_length_in_place_left,
24};
25use crate::natural::arithmetic::mul::fft::mpn_mul_default_mpn_ctx;
26use crate::natural::arithmetic::mul::limb::limbs_mul_limb_to_out;
27use crate::natural::arithmetic::mul::toom::MUL_TOOM33_THRESHOLD_LIMIT;
28use crate::natural::arithmetic::mul::toom::{
29 limbs_mul_greater_to_out_toom_6h, limbs_mul_greater_to_out_toom_6h_scratch_len,
30 limbs_mul_greater_to_out_toom_8h, limbs_mul_greater_to_out_toom_8h_scratch_len,
31 limbs_mul_greater_to_out_toom_22, limbs_mul_greater_to_out_toom_22_scratch_len,
32 limbs_mul_greater_to_out_toom_32, limbs_mul_greater_to_out_toom_32_scratch_len,
33 limbs_mul_greater_to_out_toom_33, limbs_mul_greater_to_out_toom_33_scratch_len,
34 limbs_mul_greater_to_out_toom_42, limbs_mul_greater_to_out_toom_42_scratch_len,
35 limbs_mul_greater_to_out_toom_43, limbs_mul_greater_to_out_toom_43_scratch_len,
36 limbs_mul_greater_to_out_toom_44, limbs_mul_greater_to_out_toom_44_scratch_len,
37 limbs_mul_greater_to_out_toom_53, limbs_mul_greater_to_out_toom_53_scratch_len,
38 limbs_mul_greater_to_out_toom_63, limbs_mul_greater_to_out_toom_63_scratch_len,
39};
40use crate::platform::{
41 DoubleLimb, Limb, MUL_FFT_THRESHOLD, MUL_TOOM6H_THRESHOLD, MUL_TOOM8H_THRESHOLD,
42 MUL_TOOM22_THRESHOLD, MUL_TOOM32_TO_TOOM43_THRESHOLD, MUL_TOOM32_TO_TOOM53_THRESHOLD,
43 MUL_TOOM33_THRESHOLD, MUL_TOOM42_TO_TOOM53_THRESHOLD, MUL_TOOM42_TO_TOOM63_THRESHOLD,
44 MUL_TOOM44_THRESHOLD,
45};
46use alloc::vec::Vec;
47use core::cmp::max;
48use core::iter::Product;
49use core::ops::{Mul, MulAssign};
50use malachite_base::num::basic::traits::One;
51use malachite_base::num::basic::traits::Zero;
52
53// Interpreting two slices of `Limb`s as the limbs (in ascending order) of two `Natural`s, returns
54// the limbs of the product of the `Natural`s. `xs` must be as least as long as `ys` and `ys` cannot
55// be empty.
56//
57// # Worst-case complexity
58// $T(n) = O(n \log n \log\log n)$
59//
60// $M(n) = O(n \log n)$
61//
62// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
63//
64// # Panics
65// Panics if `xs` is shorter than `ys` or `ys` is empty.
66//
67// This is equivalent to `mpn_mul` from `mpn/generic/mul.c`, GMP 6.2.1, where `prodp` is returned.
68pub_test! {limbs_mul_greater(xs: &[Limb], ys: &[Limb]) -> Vec<Limb> {
69 let xs_len = xs.len();
70 let ys_len = ys.len();
71 let out_len = xs_len + ys_len;
72 let mut scratch = vec![0; out_len + limbs_mul_greater_to_out_scratch_len(xs_len, ys_len)];
73 let (out, mul_scratch) = scratch.split_at_mut(out_len);
74 limbs_mul_greater_to_out(out, xs, ys, mul_scratch);
75 scratch.truncate(out_len);
76 scratch.shrink_to_fit();
77 scratch
78}}
79
80// Interpreting two slices of `Limb`s as the limbs (in ascending order) of two `Natural`s, returns
81// the limbs of the product of the `Natural`s. Neither slice can be empty. The length of the
82// resulting slice is always the sum of the lengths of the input slices, so it may have trailing
83// zeros.
84//
85// # Worst-case complexity
86// $T(n) = O(n \log n \log\log n)$
87//
88// $M(n) = O(n \log n)$
89//
90// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
91//
92// # Panics
93// Panics if either slice is empty.
94//
95// This is equivalent to `mpn_mul` from mpn/generic/mul.c, GMP 6.2.1, where `un` may be less than
96// `vn` and `prodp` is returned.
97pub_crate_test! {limbs_mul(xs: &[Limb], ys: &[Limb]) -> Vec<Limb> {
98 if xs.len() >= ys.len() {
99 limbs_mul_greater(xs, ys)
100 } else {
101 limbs_mul_greater(ys, xs)
102 }
103}}
104
105pub_crate_test! { limbs_mul_same_length_to_out_scratch_len(len: usize) -> usize {
106 if len < MUL_TOOM22_THRESHOLD {
107 0
108 } else if len < MUL_TOOM33_THRESHOLD {
109 limbs_mul_greater_to_out_toom_22_scratch_len(
110 MUL_TOOM33_THRESHOLD_LIMIT - 1,
111 MUL_TOOM33_THRESHOLD_LIMIT - 1,
112 )
113 } else if len < MUL_TOOM44_THRESHOLD {
114 limbs_mul_greater_to_out_toom_33_scratch_len(len, len)
115 } else if len < MUL_TOOM6H_THRESHOLD {
116 limbs_mul_greater_to_out_toom_44_scratch_len(len, len)
117 } else if len < MUL_TOOM8H_THRESHOLD {
118 limbs_mul_greater_to_out_toom_6h_scratch_len(len, len)
119 } else if len < FFT_MUL_THRESHOLD {
120 limbs_mul_greater_to_out_toom_8h_scratch_len(len, len)
121 } else {
122 0
123 }
124}}
125
126// Interpreting two equal-length slices of `Limb`s as the limbs (in ascending order) of two
127// `Natural`s, writes the `2 * xs.len()` least-significant limbs of the product of the `Natural`s to
128// an output slice. The output must be at least as long as `2 * xs.len()`, `xs` must be as long as
129// `ys`, and neither slice can be empty. Returns the result limb at index `2 * xs.len() - 1` (which
130// may be zero).
131//
132// # Worst-case complexity
133// $T(n) = O(n \log n \log\log n)$
134//
135// $M(n) = O(n \log n)$
136//
137// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
138//
139// # Panics
140// Panics if `out` is too short, `xs` and `ys` have different lengths, or either slice is empty.
141//
142// This is equivalent to `mpn_mul_n` from `mpn/generic/mul_n.c`, GMP 6.2.1.
143pub_crate_test! {limbs_mul_same_length_to_out(
144 out: &mut [Limb],
145 xs: &[Limb],
146 ys: &[Limb],
147 scratch: &mut [Limb]
148) {
149 let len = xs.len();
150 assert_eq!(ys.len(), len);
151 assert_ne!(len, 0);
152 let out = &mut out[..len << 1];
153 if len < MUL_TOOM22_THRESHOLD {
154 limbs_mul_greater_to_out_basecase(out, xs, ys);
155 } else if len < MUL_TOOM33_THRESHOLD {
156 limbs_mul_greater_to_out_toom_22(out, xs, ys, scratch);
157 } else if len < MUL_TOOM44_THRESHOLD {
158 limbs_mul_greater_to_out_toom_33(out, xs, ys, scratch);
159 } else if len < MUL_TOOM6H_THRESHOLD {
160 limbs_mul_greater_to_out_toom_44(out, xs, ys, scratch);
161 } else if len < MUL_TOOM8H_THRESHOLD {
162 limbs_mul_greater_to_out_toom_6h(out, xs, ys, scratch);
163 } else if len < FFT_MUL_THRESHOLD {
164 limbs_mul_greater_to_out_toom_8h(out, xs, ys, scratch);
165 } else {
166 mpn_mul_default_mpn_ctx(out, xs, ys, false);
167 }
168}}
169
170// This is equivalent to `TOOM44_OK` from `mpn/generic/mul.c`, GMP 6.2.1.
171pub_const_crate_test! {toom44_ok(xs_len: usize, ys_len: usize) -> bool {
172 12 + 3 * xs_len < ys_len << 2
173}}
174
175pub_crate_test! { limbs_mul_greater_to_out_scratch_len(xs_len: usize, ys_len: usize) -> usize {
176 assert!(xs_len >= ys_len);
177 assert_ne!(ys_len, 0);
178 if xs_len == ys_len {
179 limbs_mul_same_length_to_out_scratch_len(xs_len)
180 } else if ys_len < MUL_TOOM22_THRESHOLD {
181 0
182 } else if ys_len < MUL_TOOM33_THRESHOLD {
183 if xs_len >= 3 * ys_len {
184 let two_ys_len = ys_len << 1;
185 let three_ys_len = two_ys_len + ys_len;
186 let four_ys_len = two_ys_len << 1;
187 let mut xs_len = xs_len - two_ys_len;
188 while xs_len >= three_ys_len {
189 xs_len -= two_ys_len;
190 }
191 let four_xs_len = xs_len << 2;
192 let first_mul_scratch_len =
193 limbs_mul_greater_to_out_toom_42_scratch_len(two_ys_len, ys_len);
194 let second_mul_scratch_len = if four_xs_len < 5 * ys_len {
195 limbs_mul_greater_to_out_toom_22_scratch_len(xs_len, ys_len)
196 } else if four_xs_len < 7 * ys_len {
197 limbs_mul_greater_to_out_toom_32_scratch_len(xs_len, ys_len)
198 } else {
199 limbs_mul_greater_to_out_toom_42_scratch_len(xs_len, ys_len)
200 };
201 max(first_mul_scratch_len, second_mul_scratch_len) + four_ys_len
202 } else if 4 * xs_len < 5 * ys_len {
203 limbs_mul_greater_to_out_toom_22_scratch_len(xs_len, ys_len)
204 } else if 4 * xs_len < 7 * ys_len {
205 limbs_mul_greater_to_out_toom_32_scratch_len(xs_len, ys_len)
206 } else {
207 limbs_mul_greater_to_out_toom_42_scratch_len(xs_len, ys_len)
208 }
209 } else if (xs_len + ys_len) >> 1 < MUL_FFT_THRESHOLD || 3 * ys_len < MUL_FFT_THRESHOLD {
210 if ys_len < MUL_TOOM44_THRESHOLD || !toom44_ok(xs_len, ys_len) {
211 // Use ToomX3 variants
212 if xs_len << 1 >= 5 * ys_len {
213 let two_ys_len = ys_len << 1;
214 let four_ys_len = two_ys_len << 1;
215 let first_mul_scratch_len = if ys_len < MUL_TOOM42_TO_TOOM63_THRESHOLD {
216 limbs_mul_greater_to_out_toom_42_scratch_len(two_ys_len, ys_len)
217 } else {
218 limbs_mul_greater_to_out_toom_63_scratch_len(two_ys_len, ys_len)
219 };
220 let mut xs_len = xs_len - two_ys_len;
221 while xs_len << 1 >= 5 * ys_len {
222 xs_len -= two_ys_len;
223 }
224 let second_mul_scratch_len = limbs_mul_to_out_scratch_len(xs_len, ys_len);
225 max(first_mul_scratch_len, second_mul_scratch_len) + four_ys_len
226 } else if 6 * xs_len < 7 * ys_len {
227 limbs_mul_greater_to_out_toom_33_scratch_len(xs_len, ys_len)
228 } else if xs_len << 1 < 3 * ys_len {
229 if ys_len < MUL_TOOM32_TO_TOOM43_THRESHOLD {
230 limbs_mul_greater_to_out_toom_32_scratch_len(xs_len, ys_len)
231 } else {
232 limbs_mul_greater_to_out_toom_43_scratch_len(xs_len, ys_len)
233 }
234 } else if 6 * xs_len < 11 * ys_len {
235 if xs_len << 2 < 7 * ys_len {
236 if ys_len < MUL_TOOM32_TO_TOOM53_THRESHOLD {
237 limbs_mul_greater_to_out_toom_32_scratch_len(xs_len, ys_len)
238 } else {
239 limbs_mul_greater_to_out_toom_53_scratch_len(xs_len, ys_len)
240 }
241 } else if ys_len < MUL_TOOM42_TO_TOOM53_THRESHOLD {
242 limbs_mul_greater_to_out_toom_42_scratch_len(xs_len, ys_len)
243 } else {
244 limbs_mul_greater_to_out_toom_53_scratch_len(xs_len, ys_len)
245 }
246 } else if ys_len < MUL_TOOM42_TO_TOOM63_THRESHOLD {
247 limbs_mul_greater_to_out_toom_42_scratch_len(xs_len, ys_len)
248 } else {
249 limbs_mul_greater_to_out_toom_63_scratch_len(xs_len, ys_len)
250 }
251 } else if ys_len < MUL_TOOM6H_THRESHOLD {
252 limbs_mul_greater_to_out_toom_44_scratch_len(xs_len, ys_len)
253 } else if ys_len < MUL_TOOM8H_THRESHOLD {
254 limbs_mul_greater_to_out_toom_6h_scratch_len(xs_len, ys_len)
255 } else {
256 limbs_mul_greater_to_out_toom_8h_scratch_len(xs_len, ys_len)
257 }
258 } else {
259 0
260 }
261}}
262
263pub_const_crate_test_const! {FFT_MUL_THRESHOLD: usize = 1000;}
264
265// Interpreting two slices of `Limb`s as the limbs (in ascending order) of two `Natural`s, writes
266// the `xs.len() + ys.len()` least-significant limbs of the product of the `Natural`s to an output
267// slice. The output must be at least as long as `xs.len() + ys.len()`, `xs` must be as least as
268// long as `ys`, and `ys` cannot be empty. Returns the result limb at index `xs.len() + ys.len() -
269// 1` (which may be zero).
270//
271// # Worst-case complexity
272// $T(n) = O(n \log n \log\log n)$
273//
274// $M(n) = O(n \log n)$
275//
276// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
277//
278// # Panics
279// Panics if `out` is too short, `xs` is shorter than `ys`, or `ys` is empty.
280//
281// This is _flint_mpn_mul from mpn_extras/mul.c, FLINT 3.3.0-dev.
282pub_crate_test! {limbs_mul_greater_to_out(
283 out: &mut [Limb],
284 xs: &[Limb],
285 ys: &[Limb],
286 scratch: &mut [Limb],
287) -> Limb {
288 let xs_len = xs.len();
289 let ys_len = ys.len();
290 assert!(xs_len >= ys_len);
291 let out_len = xs_len + ys_len;
292 assert!(out.len() >= out_len);
293 if xs_len == ys_len {
294 limbs_mul_same_length_to_out(out, xs, ys, scratch);
295 } else if ys_len < FFT_MUL_THRESHOLD {
296 let mut scratch = vec![0; limbs_mul_greater_to_out_scratch_len(xs_len, ys_len)];
297 limbs_mul_greater_to_out_old(out, xs, ys, &mut scratch);
298 } else {
299 mpn_mul_default_mpn_ctx(out, xs, ys, false);
300 }
301 out[xs_len + ys_len - 1]
302}}
303
304pub_crate_test! {limbs_mul_greater_to_out_old(
305 out: &mut [Limb],
306 xs: &[Limb],
307 ys: &[Limb],
308 scratch: &mut [Limb]
309) -> Limb {
310 let xs_len = xs.len();
311 let ys_len = ys.len();
312 assert!(xs_len >= ys_len);
313 assert_ne!(ys_len, 0);
314 assert!(out.len() >= xs_len + ys_len);
315 if ys_len < MUL_TOOM22_THRESHOLD {
316 // Plain schoolbook multiplication. Unless xs_len is very large, or else if
317 // `limbs_mul_same_length_to_out` applies, perform basecase multiply directly.
318 limbs_mul_greater_to_out_basecase(out, xs, ys);
319 } else if ys_len < MUL_TOOM33_THRESHOLD {
320 if xs_len >= 3 * ys_len {
321 let two_ys_len = ys_len << 1;
322 let three_ys_len = two_ys_len + ys_len;
323 let four_ys_len = two_ys_len << 1;
324 let (scratch, mul_scratch) = scratch.split_at_mut(four_ys_len);
325 limbs_mul_greater_to_out_toom_42(out, &xs[..two_ys_len], ys, mul_scratch);
326 let mut xs = &xs[two_ys_len..];
327 let mut out_offset = two_ys_len;
328 while xs.len() >= three_ys_len {
329 let out = &mut out[out_offset..];
330 let (xs_lo, xs_hi) = xs.split_at(two_ys_len);
331 limbs_mul_greater_to_out_toom_42(scratch, xs_lo, ys, mul_scratch);
332 let (scratch_lo, scratch_hi) = scratch.split_at(ys_len);
333 out[ys_len..three_ys_len].copy_from_slice(&scratch_hi[..two_ys_len]);
334 assert!(!limbs_slice_add_greater_in_place_left(out, scratch_lo));
335 xs = xs_hi;
336 out_offset += two_ys_len;
337 }
338 let xs_len = xs.len();
339 let out = &mut out[out_offset..];
340 // ys_len <= xs_len < 3 * ys_len
341 let four_xs_len = xs_len << 2;
342 if four_xs_len < 5 * ys_len {
343 limbs_mul_greater_to_out_toom_22(scratch, xs, ys, mul_scratch);
344 } else if four_xs_len < 7 * ys_len {
345 limbs_mul_greater_to_out_toom_32(scratch, xs, ys, mul_scratch);
346 } else {
347 limbs_mul_greater_to_out_toom_42(scratch, xs, ys, mul_scratch);
348 }
349 let (scratch_lo, scratch_hi) = scratch.split_at(ys_len);
350 out[ys_len..ys_len + xs_len].copy_from_slice(&scratch_hi[..xs_len]);
351 assert!(!limbs_slice_add_greater_in_place_left(out, scratch_lo));
352 } else if 4 * xs_len < 5 * ys_len {
353 limbs_mul_greater_to_out_toom_22(out, xs, ys, scratch);
354 } else if 4 * xs_len < 7 * ys_len {
355 limbs_mul_greater_to_out_toom_32(out, xs, ys, scratch);
356 } else {
357 limbs_mul_greater_to_out_toom_42(out, xs, ys, scratch);
358 }
359 } else if (xs_len + ys_len) >> 1 < MUL_FFT_THRESHOLD || 3 * ys_len < MUL_FFT_THRESHOLD {
360 // Handle the largest operands that are not in the FFT range. The 2nd condition makes very
361 // unbalanced operands avoid the FFT code (except perhaps as coefficient products of the
362 // Toom code).
363 if ys_len < MUL_TOOM44_THRESHOLD || !toom44_ok(xs_len, ys_len) {
364 // Use ToomX3 variants
365 if xs_len << 1 >= 5 * ys_len {
366 let two_ys_len = ys_len << 1;
367 let four_ys_len = two_ys_len << 1;
368 let (scratch, mul_scratch) = scratch.split_at_mut(four_ys_len);
369 let (xs_lo, mut xs) = xs.split_at(two_ys_len);
370 if ys_len < MUL_TOOM42_TO_TOOM63_THRESHOLD {
371 limbs_mul_greater_to_out_toom_42(out, xs_lo, ys, mul_scratch);
372 } else {
373 limbs_mul_greater_to_out_toom_63(out, xs_lo, ys, mul_scratch);
374 }
375 let mut out_offset = two_ys_len;
376 // xs_len >= 2.5 * ys_len
377 while xs.len() << 1 >= 5 * ys_len {
378 let out = &mut out[out_offset..];
379 let (xs_lo, xs_hi) = xs.split_at(two_ys_len);
380 if ys_len < MUL_TOOM42_TO_TOOM63_THRESHOLD {
381 limbs_mul_greater_to_out_toom_42(scratch, xs_lo, ys, mul_scratch);
382 } else {
383 limbs_mul_greater_to_out_toom_63(scratch, xs_lo, ys, mul_scratch);
384 }
385 let (scratch_lo, scratch_hi) = scratch.split_at(ys_len);
386 out[ys_len..ys_len + two_ys_len].copy_from_slice(&scratch_hi[..two_ys_len]);
387 assert!(!limbs_slice_add_greater_in_place_left(out, scratch_lo));
388 xs = xs_hi;
389 out_offset += two_ys_len;
390 }
391 let xs_len = xs.len();
392 let out = &mut out[out_offset..];
393 // ys_len / 2 <= xs_len < 2.5 * ys_len
394 limbs_mul_to_out(scratch, xs, ys, mul_scratch);
395 let (scratch_lo, scratch_hi) = scratch.split_at(ys_len);
396 out[ys_len..xs_len + ys_len].copy_from_slice(&scratch_hi[..xs_len]);
397 assert!(!limbs_slice_add_greater_in_place_left(out, scratch_lo));
398 } else if 6 * xs_len < 7 * ys_len {
399 limbs_mul_greater_to_out_toom_33(out, xs, ys, scratch);
400 } else if xs_len << 1 < 3 * ys_len {
401 if ys_len < MUL_TOOM32_TO_TOOM43_THRESHOLD {
402 limbs_mul_greater_to_out_toom_32(out, xs, ys, scratch);
403 } else {
404 limbs_mul_greater_to_out_toom_43(out, xs, ys, scratch);
405 }
406 } else if 6 * xs_len < 11 * ys_len {
407 if xs_len << 2 < 7 * ys_len {
408 if ys_len < MUL_TOOM32_TO_TOOM53_THRESHOLD {
409 limbs_mul_greater_to_out_toom_32(out, xs, ys, scratch);
410 } else {
411 limbs_mul_greater_to_out_toom_53(out, xs, ys, scratch);
412 }
413 } else if ys_len < MUL_TOOM42_TO_TOOM53_THRESHOLD {
414 limbs_mul_greater_to_out_toom_42(out, xs, ys, scratch);
415 } else {
416 limbs_mul_greater_to_out_toom_53(out, xs, ys, scratch);
417 }
418 } else if ys_len < MUL_TOOM42_TO_TOOM63_THRESHOLD {
419 limbs_mul_greater_to_out_toom_42(out, xs, ys, scratch);
420 } else {
421 limbs_mul_greater_to_out_toom_63(out, xs, ys, scratch);
422 }
423 } else if ys_len < MUL_TOOM6H_THRESHOLD {
424 limbs_mul_greater_to_out_toom_44(out, xs, ys, scratch);
425 } else if ys_len < MUL_TOOM8H_THRESHOLD {
426 limbs_mul_greater_to_out_toom_6h(out, xs, ys, scratch);
427 } else {
428 limbs_mul_greater_to_out_toom_8h(out, xs, ys, scratch);
429 }
430 } else {
431 mpn_mul_default_mpn_ctx(out, xs, ys, false);
432 }
433 out[xs_len + ys_len - 1]
434}}
435
436pub_crate_test! {limbs_mul_to_out_scratch_len(xs_len: usize, ys_len: usize) -> usize {
437 if xs_len >= ys_len {
438 limbs_mul_greater_to_out_scratch_len(xs_len, ys_len)
439 } else {
440 limbs_mul_greater_to_out_scratch_len(ys_len, xs_len)
441 }
442}}
443
444// Interpreting two slices of `Limb`s as the limbs (in ascending order) of two `Natural`s, writes
445// the `xs.len() + ys.len()` least-significant limbs of the product of the `Natural`s to an output
446// slice. The output must be at least as long as `xs.len() + ys.len()`, and neither slice can be
447// empty. Returns the result limb at index `xs.len() + ys.len() - 1` (which may be zero).
448//
449// # Worst-case complexity
450// $T(n) = O(n \log n \log\log n)$
451//
452// $M(n) = O(n \log n)$
453//
454// where $T$ is time, $M$ is additional memory, and $n$ is `max(xs.len(), ys.len())`.
455//
456// # Panics
457// Panics if `out` is too short or either slice is empty.
458//
459// This is equivalent to `mpn_mul` from `mpn/generic/mul.c`, GMP 6.2.1, where `un` may be less than
460// `vn`.
461pub_crate_test! {limbs_mul_to_out(
462 out: &mut [Limb],
463 xs: &[Limb],
464 ys: &[Limb],
465 scratch: &mut [Limb]
466) -> Limb {
467 if xs.len() >= ys.len() {
468 limbs_mul_greater_to_out(out, xs, ys, scratch)
469 } else {
470 limbs_mul_greater_to_out(out, ys, xs, scratch)
471 }
472}}
473
474// Interpreting two slices of `Limb`s as the limbs (in ascending order) of two `Natural`s, writes
475// the `xs.len() + ys.len()` least-significant limbs of the product of the `Natural`s to an output
476// slice. The output must be at least as long as `xs.len() + ys.len()`, `xs` must be as least as
477// long as `ys`, and `ys` cannot be empty. Returns the result limb at index `xs.len() + ys.len() -
478// 1` (which may be zero).
479//
480// This uses the basecase, quadratic, schoolbook algorithm, and it is most critical code for
481// multiplication. All multiplies rely on this, both small and huge. Small ones arrive here
482// immediately, and huge ones arrive here as this is the base case for Karatsuba's recursive
483// algorithm.
484//
485// # Worst-case complexity
486// $T(n) = O(n^2)$
487//
488// $M(n) = O(1)$
489//
490// where $T$ is time, $M$ is additional memory, and $n$ is `max(xs.len(), ys.len())`.
491//
492// # Panics
493// Panics if `out` is too short, `xs` is shorter than `ys`, or `ys` is empty.
494//
495// This is equivalent to `mpn_mul_basecase` from `mpn/generic/mul_basecase.c`, GMP 6.2.1.
496pub_crate_test! {limbs_mul_greater_to_out_basecase(out: &mut [Limb], xs: &[Limb], ys: &[Limb]) {
497 let xs_len = xs.len();
498 let ys_len = ys.len();
499 assert_ne!(ys_len, 0);
500 assert!(xs_len >= ys_len);
501 assert!(out.len() >= xs_len + ys_len);
502 let out = &mut out[..(xs_len + ys_len)];
503 // We first multiply by the low order limb. This result can be stored, not added, to out.
504 out[xs_len] = limbs_mul_limb_to_out::<DoubleLimb, Limb>(out, xs, ys[0]);
505 // Now accumulate the product of xs and the next higher limb from ys.
506 let window_size = xs_len + 1;
507 let mut i = 1;
508 let max = ys_len - 1;
509 while i < max {
510 let (out_last, out_init) = out[i..=i + window_size].split_last_mut().unwrap();
511 *out_last = limbs_slice_add_mul_two_limbs_matching_length_in_place_left(
512 out_init,
513 xs,
514 [ys[i], ys[i + 1]],
515 );
516 i += 2;
517 }
518 if i <= max {
519 let (out_last, out_init) = out[i..i + window_size].split_last_mut().unwrap();
520 *out_last = limbs_slice_add_mul_limb_same_length_in_place_left(out_init, xs, ys[i]);
521 }
522}}
523
524impl Mul<Self> for Natural {
525 type Output = Self;
526
527 /// Multiplies two [`Natural`]s, taking both by value.
528 ///
529 /// $$
530 /// f(x, y) = xy.
531 /// $$
532 ///
533 /// # Worst-case complexity
534 /// $T(n) = O(n \log n \log\log n)$
535 ///
536 /// $M(n) = O(n \log n)$
537 ///
538 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
539 /// other.significant_bits())`.
540 ///
541 /// # Examples
542 /// ```
543 /// use core::str::FromStr;
544 /// use malachite_base::num::basic::traits::{One, Zero};
545 /// use malachite_nz::natural::Natural;
546 ///
547 /// assert_eq!(Natural::ONE * Natural::from(123u32), 123);
548 /// assert_eq!(Natural::from(123u32) * Natural::ZERO, 0);
549 /// assert_eq!(Natural::from(123u32) * Natural::from(456u32), 56088);
550 /// assert_eq!(
551 /// (Natural::from_str("123456789000").unwrap()
552 /// * Natural::from_str("987654321000").unwrap())
553 /// .to_string(),
554 /// "121932631112635269000000"
555 /// );
556 /// ```
557 #[inline]
558 fn mul(mut self, other: Self) -> Self {
559 self *= other;
560 self
561 }
562}
563
564impl<'a> Mul<&'a Self> for Natural {
565 type Output = Self;
566
567 /// Multiplies two [`Natural`]s, taking the first by value and the second by reference.
568 ///
569 /// $$
570 /// f(x, y) = xy.
571 /// $$
572 ///
573 /// # Worst-case complexity
574 /// $T(n) = O(n \log n \log\log n)$
575 ///
576 /// $M(n) = O(n \log n)$
577 ///
578 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
579 /// other.significant_bits())`.
580 ///
581 /// # Examples
582 /// ```
583 /// use core::str::FromStr;
584 /// use malachite_base::num::basic::traits::{One, Zero};
585 /// use malachite_nz::natural::Natural;
586 ///
587 /// assert_eq!(Natural::ONE * &Natural::from(123u32), 123);
588 /// assert_eq!(Natural::from(123u32) * &Natural::ZERO, 0);
589 /// assert_eq!(Natural::from(123u32) * &Natural::from(456u32), 56088);
590 /// assert_eq!(
591 /// (Natural::from_str("123456789000").unwrap()
592 /// * &Natural::from_str("987654321000").unwrap())
593 /// .to_string(),
594 /// "121932631112635269000000"
595 /// );
596 /// ```
597 #[inline]
598 fn mul(mut self, other: &'a Self) -> Self {
599 self *= other;
600 self
601 }
602}
603
604impl Mul<Natural> for &Natural {
605 type Output = Natural;
606
607 /// Multiplies two [`Natural`]s, taking the first by reference and the second by value.
608 ///
609 /// $$
610 /// f(x, y) = xy.
611 /// $$
612 ///
613 /// # Worst-case complexity
614 /// $T(n) = O(n \log n \log\log n)$
615 ///
616 /// $M(n) = O(n \log n)$
617 ///
618 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
619 /// other.significant_bits())`.
620 ///
621 /// # Examples
622 /// ```
623 /// use core::str::FromStr;
624 /// use malachite_base::num::basic::traits::{One, Zero};
625 /// use malachite_nz::natural::Natural;
626 ///
627 /// assert_eq!(&Natural::ONE * Natural::from(123u32), 123);
628 /// assert_eq!(&Natural::from(123u32) * Natural::ZERO, 0);
629 /// assert_eq!(&Natural::from(123u32) * Natural::from(456u32), 56088);
630 /// assert_eq!(
631 /// (&Natural::from_str("123456789000").unwrap()
632 /// * Natural::from_str("987654321000").unwrap())
633 /// .to_string(),
634 /// "121932631112635269000000"
635 /// );
636 /// ```
637 #[inline]
638 fn mul(self, mut other: Natural) -> Natural {
639 other *= self;
640 other
641 }
642}
643
644impl Mul<&Natural> for &Natural {
645 type Output = Natural;
646
647 /// Multiplies two [`Natural`]s, taking both by reference.
648 ///
649 /// $$
650 /// f(x, y) = xy.
651 /// $$
652 ///
653 /// # Worst-case complexity
654 /// $T(n) = O(n \log n \log\log n)$
655 ///
656 /// $M(n) = O(n \log n)$
657 ///
658 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
659 /// other.significant_bits())`.
660 ///
661 /// # Examples
662 /// ```
663 /// use core::str::FromStr;
664 /// use malachite_base::num::basic::traits::{One, Zero};
665 /// use malachite_nz::natural::Natural;
666 ///
667 /// assert_eq!(&Natural::ONE * &Natural::from(123u32), 123);
668 /// assert_eq!(&Natural::from(123u32) * &Natural::ZERO, 0);
669 /// assert_eq!(&Natural::from(123u32) * &Natural::from(456u32), 56088);
670 /// assert_eq!(
671 /// (&Natural::from_str("123456789000").unwrap()
672 /// * &Natural::from_str("987654321000").unwrap())
673 /// .to_string(),
674 /// "121932631112635269000000"
675 /// );
676 /// ```
677 fn mul(self, other: &Natural) -> Natural {
678 match (self, other) {
679 (Natural(Small(x)), y) => y.mul_limb_ref(*x),
680 (x, Natural(Small(y))) => x.mul_limb_ref(*y),
681 (Natural(Large(xs)), Natural(Large(ys))) => {
682 Natural::from_owned_limbs_asc(limbs_mul(xs, ys))
683 }
684 }
685 }
686}
687
688impl MulAssign<Self> for Natural {
689 /// Multiplies a [`Natural`] by a [`Natural`] in place, taking the [`Natural`] on the right-hand
690 /// side by value.
691 ///
692 /// $$
693 /// x \gets = xy.
694 /// $$
695 ///
696 /// # Worst-case complexity
697 /// $T(n) = O(n \log n \log\log n)$
698 ///
699 /// $M(n) = O(n \log n)$
700 ///
701 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
702 /// other.significant_bits())`.
703 ///
704 /// # Examples
705 /// ```
706 /// use core::str::FromStr;
707 /// use malachite_base::num::basic::traits::One;
708 /// use malachite_nz::natural::Natural;
709 ///
710 /// let mut x = Natural::ONE;
711 /// x *= Natural::from_str("1000").unwrap();
712 /// x *= Natural::from_str("2000").unwrap();
713 /// x *= Natural::from_str("3000").unwrap();
714 /// x *= Natural::from_str("4000").unwrap();
715 /// assert_eq!(x.to_string(), "24000000000000");
716 /// ```
717 fn mul_assign(&mut self, mut other: Self) {
718 match (&mut *self, &mut other) {
719 (Self(Small(x)), _) => {
720 other.mul_assign_limb(*x);
721 *self = other;
722 }
723 (_, Self(Small(y))) => self.mul_assign_limb(*y),
724 (Self(Large(xs)), Self(Large(ys))) => {
725 *xs = limbs_mul(xs, ys);
726 self.trim();
727 }
728 }
729 }
730}
731
732impl<'a> MulAssign<&'a Self> for Natural {
733 /// Multiplies a [`Natural`] by a [`Natural`] in place, taking the [`Natural`] on the right-hand
734 /// side by reference.
735 ///
736 /// $$
737 /// x \gets = xy.
738 /// $$
739 ///
740 /// # Worst-case complexity
741 /// $T(n) = O(n \log n \log\log n)$
742 ///
743 /// $M(n) = O(n \log n)$
744 ///
745 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
746 /// other.significant_bits())`.
747 ///
748 /// # Examples
749 /// ```
750 /// use core::str::FromStr;
751 /// use malachite_base::num::basic::traits::One;
752 /// use malachite_nz::natural::Natural;
753 ///
754 /// let mut x = Natural::ONE;
755 /// x *= &Natural::from_str("1000").unwrap();
756 /// x *= &Natural::from_str("2000").unwrap();
757 /// x *= &Natural::from_str("3000").unwrap();
758 /// x *= &Natural::from_str("4000").unwrap();
759 /// assert_eq!(x.to_string(), "24000000000000");
760 /// ```
761 fn mul_assign(&mut self, other: &'a Self) {
762 match (&mut *self, other) {
763 (Self(Small(x)), _) => *self = other.mul_limb_ref(*x),
764 (_, Self(Small(y))) => self.mul_assign_limb(*y),
765 (Self(Large(xs)), Self(Large(ys))) => {
766 *xs = limbs_mul(xs, ys);
767 self.trim();
768 }
769 }
770 }
771}
772
773impl Product for Natural {
774 /// Multiplies together all the [`Natural`]s in an iterator.
775 ///
776 /// $$
777 /// f((x_i)_ {i=0}^{n-1}) = \prod_ {i=0}^{n-1} x_i.
778 /// $$
779 ///
780 /// # Worst-case complexity
781 /// $T(n) = O(n (\log n)^2 \log\log n)$
782 ///
783 /// $M(n) = O(n \log n)$
784 ///
785 /// where $T$ is time, $M$ is additional memory, and $n$ is
786 /// `Natural::sum(xs.map(Natural::significant_bits))`.
787 ///
788 /// # Examples
789 /// ```
790 /// use core::iter::Product;
791 /// use malachite_base::vecs::vec_from_str;
792 /// use malachite_nz::natural::Natural;
793 ///
794 /// assert_eq!(
795 /// Natural::product(vec_from_str::<Natural>("[2, 3, 5, 7]").unwrap().into_iter()),
796 /// 210
797 /// );
798 /// ```
799 fn product<I>(xs: I) -> Self
800 where
801 I: Iterator<Item = Self>,
802 {
803 let mut stack = Vec::new();
804 for (i, x) in xs.enumerate().map(|(i, x)| (i + 1, x)) {
805 if x == 0 {
806 return Self::ZERO;
807 }
808 let mut p = x;
809 for _ in 0..i.trailing_zeros() {
810 p *= stack.pop().unwrap();
811 }
812 stack.push(p);
813 }
814 let mut p = Self::ONE;
815 for x in stack.into_iter().rev() {
816 p *= x;
817 }
818 p
819 }
820}
821
822impl<'a> Product<&'a Self> for Natural {
823 /// Multiplies together all the [`Natural`]s in an iterator of [`Natural`] references.
824 ///
825 /// $$
826 /// f((x_i)_ {i=0}^{n-1}) = \prod_ {i=0}^{n-1} x_i.
827 /// $$
828 ///
829 /// # Worst-case complexity
830 /// $T(n) = O(n (\log n)^2 \log\log n)$
831 ///
832 /// $M(n) = O(n \log n)$
833 ///
834 /// where $T$ is time, $M$ is additional memory, and $n$ is
835 /// `Natural::sum(xs.map(Natural::significant_bits))`.
836 ///
837 /// # Examples
838 /// ```
839 /// use core::iter::Product;
840 /// use malachite_base::vecs::vec_from_str;
841 /// use malachite_nz::natural::Natural;
842 ///
843 /// assert_eq!(
844 /// Natural::product(vec_from_str::<Natural>("[2, 3, 5, 7]").unwrap().iter()),
845 /// 210
846 /// );
847 /// ```
848 fn product<I>(xs: I) -> Self
849 where
850 I: Iterator<Item = &'a Self>,
851 {
852 let mut stack = Vec::new();
853 for (i, x) in xs.enumerate().map(|(i, x)| (i + 1, x)) {
854 if *x == 0 {
855 return Self::ZERO;
856 }
857 let mut p = x.clone();
858 for _ in 0..i.trailing_zeros() {
859 p *= stack.pop().unwrap();
860 }
861 stack.push(p);
862 }
863 let mut p = Self::ONE;
864 for x in stack.into_iter().rev() {
865 p *= x;
866 }
867 p
868 }
869}
870
871/// A precomputed object used by FFT code.
872pub mod context;
873/// Code for multiplying large integers. Derived from Daniel Schultz's small-prime FFT
874/// implementation for FLINT.
875pub mod fft;
876/// Code for multiplying a many-limbed [`Natural`] by a single [limb](crate#limbs).
877pub mod limb;
878/// Code for computing only the lowest [limbs](crate#limbs) of the product of two [`Natural`]s.
879pub mod mul_low;
880/// Code for multiplying two [`Natural`]s modulo one less than a large power of 2; used by the
881/// Schönhage-Strassen algorithm.
882pub mod mul_mod;
883/// Code for evaluating polynomials at various points; used in Toom-Cook multiplication.
884pub mod poly_eval;
885/// Code for reconstructing polynomials from their values at various points; used in Toom-Cook
886/// multiplication.
887pub mod poly_interpolate;
888#[cfg(feature = "test_build")]
889/// Code for multiplying several limbs together.
890pub mod product_of_limbs;
891#[cfg(not(feature = "test_build"))]
892/// Code for multiplying several limbs together.
893pub(crate) mod product_of_limbs;
894/// Code for Toom-Cook multiplication.
895pub mod toom;