FLINT3.7.0-dev
Algorithm

Schönhage–Strassen multiplication

Cost
O(nlog⁡nlog⁡log⁡n)O(n \log n \log \log n) bit operations for nn-bit integers with full recursion; FLINT recurses one level, and its transforms cost O(nlog⁡n)O(n \log n) bit operations.

Schönhage and Strassen [SS1971] multiply integers with a discrete Fourier transform over the ring Z/(2N+1)Z\mathbb{Z}/(2^N + 1)\mathbb{Z}. In this ring 22 has order 2N2N, so the roots of unity needed by the FFT can be chosen as powers of two, and multiplying by them is a shift with wraparound, costing O(N)O(N) bit operations instead of a multiplication. The pointwise products are products in the same kind of ring and can be computed with the same method, which gives O(nlog⁡nlog⁡log⁡n)O(n \log n \log \log n) bit operations for nn-bit integers. Fürer [Fur2009] and Harvey and van der Hoeven [HvdH2021] improved the asymptotic bound to O(nlog⁡n)O(n \log n), but the Schönhage–Strassen algorithm remains the standard exact integer FFT, as in GMP [GKZ2007] and in FLINT's fft module, written by William Hart.

The transforms of fft.h are truncated (Truncated FFTs) and, for large lengths, computed with the matrix Fourier algorithm (The matrix Fourier algorithm).

The ring#

Let n=2depthn = 2^{\mathit{depth}}, let w≥1w \ge 1, and let N=nwN = nw and p=2N+1p = 2^N + 1. Put θ=2w∈Z/pZ\theta = 2^w \in \mathbb{Z}/p\mathbb{Z}.

Lemma 1 (Roots of unity). θ\theta has order exactly 2n2n, and for every integer kk that is not a multiple of 2n2n,

∑j=02n−1θjk=0in Z/pZ.\sum_{j=0}^{2n-1} \theta^{jk} = 0 \quad \text{in } \mathbb{Z}/p\mathbb{Z}.

Moreover, 22 is a unit in Z/pZ\mathbb{Z}/p\mathbb{Z}.

Proof. θn=2N=−1\theta^n = 2^N = -1, so θ2n=1\theta^{2n} = 1 and the order divides 2n2n but not nn; as 2n2n is a power of two, the order is 2n2n. For the sum, we may reduce kk modulo 2n=2t2n = 2^t and assume 0<k<2n0 < k < 2n. Write k=2sk′k = 2^s k' with k′k' odd, so s<ts < t, and let m=2t−1−sm = 2^{t - 1 - s}. Then θmk=θ2t−1k′=θnk′=(−1)k′=−1\theta^{mk} = \theta^{2^{t-1} k'} = \theta^{n k'} = (-1)^{k'} = -1. The indices 0,…,2n−10, \ldots, 2n - 1 fall into blocks of length 2m2m, which divides 2n2n, and within a block the terms jj and j+mj + m cancel, since θ(j+m)k=−θjk\theta^{(j+m)k} = -\theta^{jk}. Finally, 2⋅22N−1=22N=12 \cdot 2^{2N - 1} = 2^{2N} = 1.

The lemma says that θ\theta is a principal root of unity, which is what the inversion formula needs in a ring that is not a field [Pol1971]: for a^k=∑jajθjk\hat a_k = \sum_j a_j \theta^{jk},

∑k=02n−1θ−ika^k=∑jaj∑kθ(j−i)k=2n ai,\sum_{k=0}^{2n-1} \theta^{-ik} \hat a_k = \sum_j a_j \sum_k \theta^{(j - i)k} = 2n \, a_i,

and 2n2n is invertible. Hence pointwise products of transforms are the transforms of cyclic convolutions of length 2n2n, and the inverse transform recovers these after a division by 2n2n, which is a shift.

Multiplication by θi=2iw\theta^i = 2^{iw} is a shift by iwiw bits. Since 2N+s≡−2s2^{N + s} \equiv -2^s, the bits shifted out at the top re-enter at the bottom with a negative sign. FLINT splits the shift into whole limbs, realised by reading or writing at an offset with the wrapped part subtracted, and a remaining shift by fewer than FLINT_BITS\mathtt{FLINT\_BITS} bits. Residues are kept in N/FLINT_BITS+1N/\mathtt{FLINT\_BITS} + 1 limbs in two's complement, and sums and differences are not reduced: the top limb absorbs the carries, and mpn_normmod_2expp1 reduces only where a reduced value is needed. A butterfly (a,b)↦(a+b,2iw(a−b))(a, b) \mapsto (a + b, 2^{iw}(a - b)) is thus a combined addition and subtraction (flint_mpn_sumdiff_n) followed by a shift: a few passes over NN bits. With these butterflies the transforms are radix-2 Cooley–Tukey FFTs (Radix-2 Cooley–Tukey).

The 2\sqrt 2 trick#

A transform of length 2n2n with root 2w2^w needs a ring of N=nw≥nN = nw \ge n bits. The following identity, also used by GMP [GKZ2007], gives a root of unity of order 4n4n in the same ring.

Lemma 2. If 4∣N4 \mid N, then σ=23N/4−2N/4\sigma = 2^{3N/4} - 2^{N/4} satisfies σ2≡2(mod2N+1)\sigma^2 \equiv 2 \pmod{2^N + 1}. Hence φ=σw\varphi = \sigma^w has order 4n4n and φ2=θ\varphi^2 = \theta.

Proof. σ2=23N/2−2⋅2N+2N/2\sigma^2 = 2^{3N/2} - 2 \cdot 2^N + 2^{N/2}. Modulo 2N+12^N + 1 we have 23N/2=2N2N/2≡−2N/22^{3N/2} = 2^N 2^{N/2} \equiv -2^{N/2} and 2⋅2N≡−22 \cdot 2^N \equiv -2, so σ2≡−2N/2+2+2N/2=2\sigma^2 \equiv -2^{N/2} + 2 + 2^{N/2} = 2. Then φ2=σ2w=2w=θ\varphi^2 = \sigma^{2w} = 2^w = \theta and φ2n=θn=−1\varphi^{2n} = \theta^n = -1, so φ\varphi has order 4n4n.

Even powers φ2j=2jw\varphi^{2j} = 2^{jw} are shifts. For odd ii and odd ww, iwiw is odd and φi=σiw=σ⋅2(iw−1)/2\varphi^i = \sigma^{iw} = \sigma \cdot 2^{(iw - 1)/2}. Since σ=2N/4(2N/2−1)\sigma = 2^{N/4} (2^{N/2} - 1), multiplying by φi\varphi^i costs a shift by (iw−1)/2+N/4(iw - 1)/2 + N/4 bits, a shift by N/2N/2 bits and a subtraction; this is fft_adjust_sqrt2 and fft_butterfly_sqrt2. For even ww, φ=2w/2\varphi = 2^{w/2} and nothing special is needed. In a transform of length 4n4n by decimation in frequency, only the first layer uses odd powers of φ\varphi; the two halves are transforms of length 2n2n with root θ\theta. The trick therefore doubles the transform length for a given ring, or halves the ring for a given number of points, at the cost of a slightly more expensive first layer. All _sqrt2 functions of fft.h use it, with NN a multiple of FLINT_BITS\mathtt{FLINT\_BITS}, hence of 4.

Integer multiplication#

To multiply xx and yy, FLINT cuts them into chunks of bb bits, x=∑i<j1xi2bix = \sum_{i < j_1} x_i 2^{bi} and y=∑i<j2yi2biy = \sum_{i < j_2} y_i 2^{bi} with 0≤xi,yi<2b0 \le x_i, y_i < 2^b (fft_split_bits). The product xyxy is the value at 2b2^b of the polynomial ∑kcktk\sum_k c_k t^k with ck=∑i+j=kxiyjc_k = \sum_{i + j = k} x_i y_j, which is computed by a convolution of length 4n4n modulo 2N+12^N + 1 using the 2\sqrt 2 trick.

Algorithm 1: Integer multiplication (mul_truncate_sqrt2)

Input: xx, yy; parameters depth\mathit{depth} and ww with N=nwN = nw a multiple of FLINT_BITS\mathtt{FLINT\_BITS}, n=2depthn = 2^{\mathit{depth}}.

Output: xyxy.

  1. b←⌊(N−depth−1)/2⌋b \gets \lfloor (N - \mathit{depth} - 1)/2 \rfloor. Split xx and yy into j1j_1 and j2j_2 chunks of bb bits; require j1+j2−1≤4nj_1 + j_2 - 1 \le 4n.
  2. t←j1+j2−1t \gets j_1 + j_2 - 1, raised to 2n+12n + 1 if smaller, and rounded up to an even number.
  3. Compute the truncated sqrt2 transforms of length 4n4n of both chunk vectors at the first tt points (fft_truncate_sqrt2).
  4. Reduce the tt transformed values and multiply them pairwise modulo 2N+12^N + 1.
  5. Apply the truncated inverse transform (ifft_truncate_sqrt2), divide by 4n4n and reduce; this gives c0,…,ct−1c_0, \ldots, c_{t - 1}.
  6. Return ∑kck2bk\sum_k c_k 2^{bk} (fft_combine_bits).

Theorem 3. Algorithm 1 returns xyxy.

Proof. Each ckc_k is a sum of at most min⁡(j1,j2)\min(j_1, j_2) products xiyjx_i y_j. From j1+j2≤4n+1j_1 + j_2 \le 4n + 1 we get min⁡(j1,j2)≤2n\min(j_1, j_2) \le 2n, so

0≤ck≤2n(2b−1)2<2depth+1+2b≤2N<p,0 \le c_k \le 2n (2^b - 1)^2 < 2^{\mathit{depth} + 1 + 2b} \le 2^N < p,

using 2b≤N−depth−12b \le N - \mathit{depth} - 1. Since the product polynomial has j1+j2−1≤t≤4nj_1 + j_2 - 1 \le t \le 4n coefficients, it equals the cyclic product of length 4n4n, and by Theorem 4 of Truncated FFTs the truncated transforms at tt points determine it. The residues in [0,p)[0, p) found in step 5 are therefore the integers ckc_k, and step 6 evaluates the product polynomial at 2b2^b.

The bound 2depth+1+2b≤2N2^{\mathit{depth} + 1 + 2b} \le 2^N means that almost half of each transformed coefficient carries data: N≈2bN \approx 2b. The product has about 4n⋅b≈2nN4n \cdot b \approx 2nN bits, so each transform handles about twice the size of the product. mul_mfa_truncate_sqrt2 performs the same steps with the matrix Fourier algorithm, and fft_convolution performs steps 3 to 5 on given coefficient vectors, also with signed coefficients, which are then read from their residues in the symmetric range (−p/2,p/2)(-p/2, p/2). When only a window of the coefficients is wanted, as in a middle product, fft_convolution_choose_mid shortens the cyclic convolution so that the wrap-around misses the window (Partial products), as the small-prime FFT does (Windows and wrap-around).

Multiplication modulo 2N+12^N + 1#

The pointwise products in step 4 are products modulo 2N+12^N + 1. Up to FFT_MULMOD_2EXPP1_CUTOFF limbs (128 limbs, 8192 bits), flint_mpn_mulmod_2expp1_basecase computes the full product with flint_mpn_mul_n and subtracts its high half from its low half. Beyond that, fft_mulmod_2expp1 applies the method of Schönhage and Strassen once more, now with a negacyclic convolution, which reduces modulo 2N+12^N + 1 for free.

Write N=2n′b′N = 2n' b' with n′=2d′n' = 2^{d'} and cut xx and yy, both less than 2N2^N, into 2n′2n' pieces xix_i, yiy_i of b′b' bits. Since (2b′)2n′=2N≡−1(2^{b'})^{2n'} = 2^N \equiv -1, the product xyxy modulo 2N+12^N + 1 is the value at 2b′2^{b'} of X(t)Y(t)X(t) Y(t) modulo t2n′+1t^{2n'} + 1, whose coefficients are

ck=∑i+j=kxiyj−∑i+j=k+2n′xiyj,0≤k<2n′,c_k = \sum_{i + j = k} x_i y_j - \sum_{i + j = k + 2n'} x_i y_j, \qquad 0 \le k < 2n',

so that ∣ck∣<2n′ 22b′|c_k| < 2n' \, 2^{2b'}. The negacyclic convolution is a cyclic convolution of the weighted vectors (φ′ixi)(\varphi'^i x_i) and (φ′iyi)(\varphi'^i y_i), where φ′\varphi' is a root of unity of order 4n′4n', followed by multiplication of coefficient ii by φ′−i\varphi'^{-i} [Nus1980; CF1994]. FLINT computes it modulo p′=2N′+1p' = 2^{N'} + 1 with N′=2b′=n′w′N' = 2b' = n' w' and φ′=2 w′\varphi' = \sqrt 2^{\,w'} (fft_negacyclic, ifft_negacyclic). This ring is too small for the coefficients by d′+2d' + 2 bits; the missing information comes from a second, cheap convolution.

Lemma 4 (Recovering the coefficients). Let p′=2N′+1p' = 2^{N'} + 1 with FLINT_BITS≤N′\mathtt{FLINT\_BITS} \le N', and let B=2FLINT_BITSB = 2^{\mathtt{FLINT\_BITS}}. Suppose ∣c∣<(B/2−1)p′|c| < (B/2 - 1) p', v∈[0,p′)v \in [0, p') with v≡c(modp′)v \equiv c \pmod{p'} and r≡c(modB)r \equiv c \pmod{B}. Then c=v+qp′c = v + q p', where qq is the integer in [−B/2,B/2)[-B/2, B/2) congruent to r−vr - v modulo BB.

Proof. Since BB divides 2N′2^{N'}, p′≡1(modB)p' \equiv 1 \pmod{B}. Write c=v+qp′c = v + q p' with an integer qq. Reducing modulo BB gives q≡c−v≡r−vq \equiv c - v \equiv r - v. From 0≤v<p′0 \le v < p' and the bound on ∣c∣|c|, −(B/2−1)p′−p′<qp′<(B/2−1)p′-(B/2 - 1)p' - p' < q p' < (B/2 - 1)p', so −B/2<q<B/2−1-B/2 < q < B/2 - 1, and qq is determined by its residue modulo BB.

The coefficients satisfy ∣ck∣<2n′ 2N′<(B/2−1)p′|c_k| < 2n' \, 2^{N'} < (B/2 - 1) p' as long as 4n′<B−24n' < B - 2, which holds for any feasible transform. The residues modulo BB are the negacyclic convolution of the lowest limbs of the pieces in wrapping word arithmetic, fft_naive_convolution_1, which costs 4n′24n'^2 word multiplications, negligible next to the rest. Without this trick the inner ring would need 2b′+d′+22b' + d' + 2 bits, which is not of the form n′w′n' w' with a multiple of FLINT_BITS\mathtt{FLINT\_BITS}. Finally, xy mod (2N+1)xy \bmod (2^N + 1) is assembled from the ckc_k as in step 6 of Algorithm 1, with a correction for the negative ones.

Algorithm 2: Multiplication modulo 2N+12^N + 1 (fft_mulmod_2expp1)

Input: reduced xx, yy modulo 2N+12^N + 1, with N/FLINT_BITSN/\mathtt{FLINT\_BITS} a value returned by fft_adjust_limbs.

Output: xy mod (2N+1)xy \bmod (2^N + 1), reduced.

  1. If x=2Nx = 2^N or y=2Ny = 2^N, return the negation of the other.
  2. If N≤128FLINT_BITSN \le 128 \mathtt{FLINT\_BITS}, return flint_mpn_mulmod_2expp1_basecase.
  3. d←⌈log⁡2N⌉d \gets \lceil \log_2 N \rceil and d′←⌊d/2⌋−kd' \gets \lfloor d/2 \rfloor - k with kk from the table MULMOD_TAB; n′←2d′n' \gets 2^{d'}, b′←N/(2n′)b' \gets N/(2n'), w′←N/n′2w' \gets N/n'^2.
  4. Compute the negacyclic convolution of the b′b'-bit pieces modulo 22b′+12^{2b'} + 1 with transforms of length 2n′2n', using flint_mpn_mulmod_2expp1_basecase for its pointwise products, and the negacyclic convolution of the lowest limbs modulo BB.
  5. Recover the ckc_k by Lemma 4 and return ∑kck2b′k mod (2N+1)\sum_k c_k 2^{b' k} \bmod (2^N + 1).

fft_adjust_limbs makes step 3 well defined: it rounds the limb count up so that NN is a multiple of n′2n'^2, making w′w' an integer, and b′b' a multiple of FLINT_BITS\mathtt{FLINT\_BITS}. The pointwise products of step 4 are not split further, so fft_mulmod_2expp1 has one level of recursion; its inner products of 2b′2b' bits are full products by flint_mpn_mul_n. In builds with fft_small, the convolutions of fmpz_poly and fmpzi use instead sd_fft_mpn_mulmod_2expp1, a negacyclic convolution modulo word-size primes in floating point, whenever fft_adjust_limbs_sd_fft finds a suitable ring; it is about twice as fast for N≥16384N \ge 16384. See The negacyclic engine of fft_small and, for the algorithm, Algorithm.

Choice of parameters#

flint_mpn_mul_fft_main chooses (depth,w)(\mathit{depth}, w) in two steps.

  1. It tries (depth,w)(\mathit{depth}, w) in the order (6,1),(6,2),(7,1),(7,2),…(6, 1), (6, 2), (7, 1), (7, 2), \ldots and stops at the first pair for which chunks of b=⌊(nw−depth−1)/2⌋b = \lfloor (nw - \mathit{depth} - 1)/2 \rfloor bits fit, j1+j2−1≤4nj_1 + j_2 - 1 \le 4n.
  2. If depth<11\mathit{depth} < 11, it shortens the transform by the factor 2k2^k given by the table entry FFT_TAB[depth - 6][w - 1] and multiplies ww by 4k4^k, which keeps the capacity 4n⋅b4n \cdot b roughly the same with 2k2^k times fewer, larger coefficients. It then lowers ww in steps of max⁡(1,26−depth)\max(1, 2^{6 - \mathit{depth}}), keeping nwnw a multiple of 64, as long as the product still fits, and calls mul_truncate_sqrt2. Otherwise, if j1+j2−1≤3nj_1 + j_2 - 1 \le 3n, it halves the transform length and triples ww, and then calls mul_mfa_truncate_sqrt2.

For small products, few large coefficients win because the pointwise products, by Toom–Cook and basecase multiplication, are faster per bit than additional transform layers; for large products, the transform must stay long so that the coefficients and the pointwise products remain small. The tables are tuned per processor with src/fft/tune/tune-fft.c. For depth=6,…,10\mathit{depth} = 6, \ldots, 10, each with w=1,2w = 1, 2:

targetFFT_TAB
generic, ARM64, Apple M1, Skylake, Zen 3(4,4),(4,3),(3,2),(2,1),(2,1)(4, 4), (4, 3), (3, 2), (2, 1), (2, 1)
Ice Lake, Sapphire Rapids, Meteor Lake, Arrow Lake(4,4),(4,3),(3,2),(2,2),(2,1)(4, 4), (4, 3), (3, 2), (2, 2), (2, 1)
Raptor Lake(4,4),(4,3),(3,2),(2,2),(1,1)(4, 4), (4, 3), (3, 2), (2, 2), (1, 1)
Tiger Lake(4,4),(4,3),(3,2),(2,1),(1,1)(4, 4), (4, 3), (3, 2), (2, 1), (1, 1)
Broadwell(4,4),(4,3),(3,3),(3,2),(2,1)(4, 4), (4, 3), (3, 3), (3, 2), (2, 1)
Zen 4(4,4),(4,3),(3,2),(2,2),(2,0)(4, 4), (4, 3), (3, 2), (2, 2), (2, 0)

With the generic table, balanced products of ℓ\ell limbs each get the following parameters ("first fit" is the pair found in step 1, "truncate" and "MFA" stand for mul_truncate_sqrt2 and mul_mfa_truncate_sqrt2):

ℓ\ellfirst fitusedfunction4n4nNNbbpointspointwise products
100(6, 2)(2, 416)truncate16166483015basecase
1000(8, 2)(6, 16)truncate2561024508251basecase
10000(10, 1)(8, 10)truncate1024256012751003basecase
32000(10, 2)(9, 8)truncate2048409620432005basecase
10510^5(11, 2)(11, 2)MFA8192409620426269basecase
3⋅1053 \cdot 10^5(12, 2)(11, 6)MFA8192122886138625716 pieces of 768 bits
10610^6(13, 1)(13, 1)MFA327688192408931303basecase
10710^7(15, 1)(14, 3)MFA6553649152245685210132 pieces of 1536 bits
10810^8(16, 2)(15, 6)MFA13107219660898296130219128 pieces of 1536 bits

The pointwise products of fft_mulmod_2expp1 use d′=⌊⌈log⁡2N⌉/2⌋−kd' = \lfloor \lceil \log_2 N \rceil / 2 \rfloor - k with kk from MULMOD_TAB, indexed by ⌈log⁡2N⌉−12\lceil \log_2 N \rceil - 12 and clamped at the last entry. The values lie between 1 and 4; the generic table has 19 entries, 4,4,4,4,4,3,3,3,3,3,3,3,2,2,2,2,2,1,14, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1. The pieces then have between about N\sqrt N and 8N8 \sqrt N bits, as in the last column above. In builds without fft_small, flint_mpn_mul switches from GMP to flint_mpn_mul_fft_main at FLINT_FFT_MUL_THRESHOLD =32000= 32000 limbs.

Complexity#

In this section nn is the bit size of the operands. A transform of length LL with NN-bit coefficients costs O(Llog⁡L)O(L \log L) butterflies of O(N)O(N) bit operations. With LN≈4nLN \approx 4n, the transforms cost O(nlog⁡n)O(n \log n) bit operations, and the LL pointwise products cost L⋅M(N)L \cdot M(N), where M(N)M(N) is the cost of a multiplication modulo 2N+12^N + 1. Choosing N≈nN \approx \sqrt n and applying the method recursively to the pointwise products gives the bound O(nlog⁡nlog⁡log⁡n)O(n \log n \log \log n) of [SS1971], since each of the O(log⁡log⁡n)O(\log \log n) levels costs O(nlog⁡n)O(n \log n). FLINT stops after one negacyclic level and uses the best available multiplication for the remaining products of a few thousand bits. In practice the cost per bit grows slowly with nn and is dominated by the memory traffic of the transforms, which the matrix Fourier algorithm keeps in cache. FFTs modulo word-size primes in floating point are faster on current processors (FFTs modulo word-size primes in floating point); FFTs in FLINT compares the methods.

Referenced from#

References#

  • [SS1971] A. Schönhage and V. Strassen. Schnelle Multiplikation großer Zahlen. Computing 7 (1971), 281–292.
  • [Fur2009] M. Fürer. Faster integer multiplication. SIAM Journal on Computing 39 (2009), 979–1005.
  • [HvdH2021] D. Harvey and J. van der Hoeven. Integer multiplication in time O(nlog⁡n)O(n \log n). Annals of Mathematics 193 (2021), 563–617.
  • [GKZ2007] P. Gaudry, A. Kruppa and P. Zimmermann. A GMP-based implementation of Schönhage-Strassen's large integer multiplication algorithm. ISSAC 2007, 167–174.
  • [Pol1971] J. M. Pollard. The fast Fourier transform in a finite field. Mathematics of Computation 25 (1971), 365–374.
  • [Nus1980] H. J. Nussbaumer. Fast polynomial transform algorithms for digital convolution. IEEE Transactions on Acoustics, Speech and Signal Processing 28 (1980), 205–215.
  • [CF1994] R. Crandall and B. Fagin. Discrete weighted transforms and large-integer arithmetic. Mathematics of Computation 62 (1994), 305–324.
Cite this page

The FLINT team, “Schönhage–Strassen multiplication,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/fft/schonhage-strassen.html (generated 2026-11-02).