Multiplying polynomials over Z
A polynomial over has two sizes: its length and the bit size of its coefficients. A product of two polynomials of length with -bit coefficients has coefficients of at most bits, and its cost is bounded below by the cost of multiplying integers of about bits. Every algorithm described below reaches that cost in some range and is far from it in others: for and the problem is a handful of huge integer products, for and it is essentially a product over a small finite field, and in between both dimensions matter. FLINT therefore selects among more algorithms for than for (Multiplying polynomials over Z/nZ), in a single dispatcher, _fmpz_poly_mulmid, which computes an arbitrary window of coefficients of the product and serves full, low, high and middle products and squares. The generic gr_poly functions over the ring (gr_ctx_init_fmpz) call the same dispatcher through the method table of the ring, so generic algorithms such as power series composition or reversion over inherit it.
Throughout, and have lengths and coefficients of at most and bits, , and . Each coefficient of is a sum of at most products, so
Direct algorithms#
Word accumulation. If (small fmpz values) and fits in one signed word, the products are accumulated directly in machine words, with loops that the compiler vectorises; if it fits in two words, each coefficient is accumulated in a double word with smul_ppmm and add_ssaaaa. No fmpz arithmetic happens until the result is written.
Classical multiplication. Each output coefficient is computed as one dot product of fmpz values with _fmpz_vec_dot_general; squares use . The cost is the number of coefficient products in the window, which makes it the best method for very short operands and for narrow windows.
Packed limbs. _fmpz_poly_mulmid_mpn copies the coefficients into fixed-size limb arrays (unsigned, two's complement, sign-magnitude or with a bias, chosen by _flint_mpn_poly_mulmid_params) and computes each output coefficient modulo for an large enough for the exact value, with classical, Karatsuba and Karatsuba middle-product algorithms on the packed representation. This removes the overhead of the fmpz type, which dominates for coefficients of a few limbs.
Karatsuba and Toom–Cook in the polynomial variable#
For large coefficients, the cost is the number of coefficient products, and evaluation–interpolation in the polynomial variable reduces it.
Proposition 1 (Toom–Cook with points). Let and let be distinct points of , where denotes the leading coefficient. Then is determined by the products , and it can be computed from them with additions, multiplications and exact divisions by small integers.
Proof. has degree , so it is determined by its values at points (at , by its leading coefficient), and . Solving the Vandermonde system over by Newton's divided differences, or with a precomputed inverse, involves divisions by differences of points; since the solution has integer coefficients, the divisions can be arranged to be exact.
With points the product needs multiplications instead of , which is optimal for bilinear algorithms. The additions and the multiplications of the evaluation and interpolation by powers of the points grow quadratically with , so the method pays off only when the coefficient products dominate. Toom used this idea for integers [Too1963], [Coo1966]; Bodrato and Zanoni studied optimal sequences of operations [BZ2007]. _fmpz_poly_mul_toom_scalar uses the points (and one more point for odd ), up to on 64-bit machines, with a table of interpolation operations whose divisions are by single words.
Longer products split recursively: _fmpz_poly_mul_toom_karatsuba applies Karatsuba's algorithm [KO1962] to the polynomials, cutting the longer operand into blocks of the length of the shorter for unbalanced products, with Toom–Cook as base case for products of length up to 5, 11, 15 or 20 as the coefficients grow from below 2500 to over 6000 bits. Truncated products use Mulders' short product [Mul2000] (high products by reversal), and middle windows the Karatsuba middle product of Hanrot, Quercia and Zimmermann [HQZ2004], which computes the middle product of a product in about the time of an product (Middle products and the transposition principle). The Toom–Cook middle product counts multiplications in the same way: a window of length of a product of operands of lengths needs the sum of the two smallest of , minus one.
Kronecker substitution#
Kronecker substitution (Kronecker substitution) packs each operand into one integer by evaluating at and reads the coefficients of from the integer product. Over the coefficients have signs, which the packing represents by borrows.
Lemma 2 (Signed digits). Let and let with for all . Then is determined by : is the residue of modulo in , and evaluated at .
Proof. , so , and is the unique residue in the half-open interval of length . Induction on gives the other coefficients.
_fmpz_poly_mulmid_KS takes , where if a coefficient is negative and 0 otherwise, so that by the bound above. It packs both operands with _fmpz_poly_bit_pack, negated if necessary so that the packed integers are positive, multiplies with flint_mpn_mul (or flint_mpn_sqr), and unpacks with _fmpz_poly_bit_unpack, which propagates the borrows of Lemma 2; without negative coefficients the fields are read as unsigned numbers. For a window it computes only the needed limbs with flint_mpn_mulmid, with three guard limbs below the window: a borrow that the truncated integer product loses is absorbed by the slack in the field size, and the unpacking corrects it. The cost is one integer product of about bits, so KS is within a constant factor of the lower bound whenever is small compared to . The integer product itself goes to fft_small above a few hundred limbs (FFTs in FLINT).
Multimodular FFT#
For long polynomials with small coefficients, KS wastes a large part of each field on the bits of growth and on padding. The small-prime FFT of fft_small instead reduces the coefficients modulo 2 to 8 primes of 50 bits, multiplies the images with number-theoretic transforms, and reconstructs each coefficient by the Chinese remainder theorem in the symmetric range, which is exact if the product of the primes satisfies (Multiplication with several primes and CRT). With eight primes this covers up to about 397 bits; _fmpz_poly_mul_mid_default_mpn_ctx declines larger coefficients, and the dispatcher then uses KS, whose integer product is computed by the same transforms. See Multiplying polynomials.
Schönhage–Strassen convolutions#
_fmpz_poly_mulmid_SS maps each coefficient to an element of with , rounded up as the trick requires, and computes the product as a convolution over of power-of-two length, in which every twiddle factor is a power of 2 (Schönhage–Strassen multiplication). Since , the symmetric residues modulo are the coefficients. The pointwise products modulo are themselves computed by fft_small when a suitable ring exists (Multiplication modulo 2^N + 1). For windows that do not reach the top of the product, a cyclic convolution of length suffices, because the wrapped-around terms fall below (Theorem 3 of Multiplication with several primes and CRT); fft_convolution_choose_mid uses it when it is shorter than the truncated transform of the full product, which saves up to a third of the work for the middle products of Newton iteration. The coefficient ring grows with while the transform length depends only on the lengths, which suits short polynomials with large coefficients, and the convolutions parallelise well.
Classical multiplication in transform space#
For short polynomials with very large coefficients, the integer products dominate, and an classical product multiplies each coefficient by others. _fmpz_poly_mulmid_classical_fft_small transforms each coefficient once with fft_small and computes each output coefficient as a sum of pointwise products, transformed back once (Arithmetic in transform space). This needs one forward transform per input coefficient and one inverse transform per output coefficient, instead of three transforms per coefficient product, and it beats Karatsuba for truncated products with coefficients of tens of thousands of bits up to a few dozen terms.
Selection#
The choice in _fmpz_poly_mulmid was tuned on x86-64 with fft_small for random coefficients of uniform size. Roughly, with the length of the shorter operand:
| bits | bits | |
|---|---|---|
| 2–15 | word accumulation or classical | classical (truncated products), Karatsuba–Toom |
| 20–80 | packed limbs | Karatsuba–Toom up to 4–18 terms; transform-space classical for truncated products up to 21–87 terms when |
| larger | fft_small multimodular if , else KS | KS; SS for huge products or many threads |
Middle products with and around 2000–4400 or above 120000 bits use SS when a short cyclic convolution exists, and operands whose coefficient sizes differ by a factor of at least 8 use the direct algorithms, which pay only for the actual sizes. The exact conditions are listed in Choosing the algorithm. Builds without fft_small use only KS and SS for large inputs, choosing by the number of limbs per coefficient.
Use in FLINT#
_fmpz_poly_mulmiddispatches;_fmpz_poly_mul,_fmpz_poly_mullow,_fmpz_poly_mulhigh,_fmpz_poly_sqr,_fmpz_poly_sqrlowandfmpz_poly_mulhigh_nare thin wrappers, as is the methodGR_METHOD_POLY_MULLOWof the ring ingr.- The algorithms are
_fmpz_poly_mulmid_classical,_fmpz_poly_mulmid_mpn,_fmpz_poly_mulmid_toom_scalar,_fmpz_poly_mulmid_toom_karatsuba,_fmpz_poly_mulmid_KS,_fmpz_poly_mul_mid_default_mpn_ctx(infft_small),_fmpz_poly_mulmid_SSand_fmpz_poly_mulmid_classical_fft_small. fmpz_poly_mul_SS_precache_initkeeps the transform of a fixed operand for repeated products.- Products in
fmpq_poly,fmpz_poly_q,fmpz_mod_poly,padic_polyandnf_elemcall_fmpz_poly_mulor_fmpz_poly_mullow, andarb_polymultiplies blocks of exact midpoints with them.
void _fmpz_poly_mulmid(fmpz * res, const fmpz * poly1, slong len1, const fmpz * poly2, slong len2, slong nlo, slong nhi)void _fmpz_poly_mulmid_classical(fmpz * res, const fmpz * poly1, slong len1, const fmpz * poly2, slong len2, slong nlo, slong nhi)void _fmpz_poly_mulmid_mpn(fmpz * res, const fmpz * poly1, slong len1, const fmpz * poly2, slong len2, slong nlo, slong nhi)void _fmpz_poly_mulmid_toom_karatsuba(fmpz * res, const fmpz * poly1, slong len1, const fmpz * poly2, slong len2, slong nlo, slong nhi)void _fmpz_poly_mulmid_KS(fmpz * res, const fmpz * poly1, slong len1, const fmpz * poly2, slong len2, slong nlo, slong nhi)Referenced from#
- Multiplying polynomials with ball coefficients (algorithm)
- FFTs in FLINT (overview)
- Arithmetic in unramified extensions (algorithm)
- Univariate polynomials (overview)
- Multiplying polynomials over Z/nZ (overview)
- Getting started with fmpz_poly
- fmpz_poly.h (module)
- Multiplying polynomials
padic_poly_mul
References#
- [Too1963] A. L. Toom. The complexity of a scheme of functional elements realizing the multiplication of integers. Soviet Mathematics Doklady 3 (1963), 714–716.
- [Coo1966] S. A. Cook. On the minimum computation time of functions. PhD thesis, Harvard University, 1966.
- [BZ2007] M. Bodrato and A. Zanoni. Integer and polynomial multiplication: towards optimal Toom-Cook matrices. ISSAC 2007, 17–24. https://doi.org/10.1145/1277548.1277552
- [KO1962] A. Karatsuba and Yu. Ofman, "Multiplication of multidigit numbers on automata", Doklady Akademii Nauk SSSR 145 (1962), 293–294; English translation in Soviet Physics Doklady 7 (1963), 595–596
- [Mul2000] Thom Mulders : On Short Multiplications and Divisions, AAECC vol. 11 (2000) 69–88
- [HQZ2004] G. Hanrot, M. Quercia and P. Zimmermann, "The middle product algorithm I. Speeding up the division and square root of power series", Applicable Algebra in Engineering, Communication and Computing 14:6 (2004), 415–438
The FLINT team, “Multiplying polynomials over Z,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/polynomials/multiplication-integers.html (generated 2026-11-02).
@misc{flint-doc-algorithms-polynomials-multiplication-integers,
author = {{The FLINT team}},
title = {{Multiplying polynomials over Z}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/algorithms/polynomials/multiplication-integers.html},
note = {Generated 2026-11-02}
}