Skip to main content

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;