FLINT3.7.0-dev
Algorithm

Truncated FFTs

Cost
At most (t/2)log⁡2L+L(t/2)\log_2 L + L butterflies (or additions) for tt of LL points, forward and inverse.

A convolution with radix-2 FFTs uses a transform length L=2ℓL = 2^\ell at least as large as the length tt of the product. Rounding tt up to a power of two can double the work: a product of length 210+12^{10} + 1 costs as much as one of length 2112^{11}. (A middle product can use a shorter length, since the wrap-around may fall outside the coefficients it needs; see Classical and FFT middle products.) The truncated Fourier transform (TFT) of van der Hoeven [vdH2004; vdH2005] computes only tt of the LL values, and its inverse recovers a polynomial of length tt from them, in time proportional to tlog⁡Lt \log L rather than Llog⁡LL \log L. Harvey made it cache-friendly [Har2009], Harvey and Roche [HR2010] and Arnold [Arn2013] gave in-place variants.

FLINT uses truncated transforms in both of its integer FFTs: fft.h implements van der Hoeven's recursion in fft_truncate and ifft_truncate (and their sqrt2 and matrix Fourier variants), and fft_small implements Harvey's version with separate input and output truncation in sd_fft_trunc and sd_ifft_trunc, and their transposes in sd_fft_trunc_tr and sd_ifft_trunc_tr (Transposed transforms). The algorithms are stated below in the form used by fft.h, with proofs.

Notation#

Let RR be a commutative ring, L=2ℓL = 2^\ell, m=L/2m = L/2, and let ω∈R\omega \in R satisfy ωm=−1\omega^m = -1, with 22 invertible in RR. (In fft.h, R=Z/(2N+1)ZR = \mathbb{Z}/(2^N + 1)\mathbb{Z} and ω=2w\omega = 2^w or 2 w\sqrt 2^{\,w}; see The ring.) Let revL(k)\mathrm{rev}_L(k) be the integer whose ℓ\ell binary digits are those of kk reversed. For a=(a0,…,aL−1)a = (a_0, \ldots, a_{L-1}) and a(x)=∑jajxja(x) = \sum_j a_j x^j, define

a^k=a(ωrevL(k)),0≤k<L,\hat a_k = a\bigl(\omega^{\mathrm{rev}_L(k)}\bigr), \qquad 0 \le k < L,

the transform in bit-reversed order that fft_radix2 computes by radix-2 decimation in frequency (Algorithm 1 of Discrete Fourier transforms over a generic ring). The values at positions below tt are the first tt values.

Lemma 1 (Splitting). For 0≤i<m0 \le i < m let bi=ai+am+ib_i = a_i + a_{m+i} and ci=ωi(ai−am+i)c_i = \omega^i (a_i - a_{m+i}). With the transforms of length mm taken with respect to ω2\omega^2,

a^k=b^kanda^m+k=c^k(0≤k<m).\hat a_k = \hat b_k \quad \text{and} \quad \hat a_{m+k} = \hat c_k \qquad (0 \le k < m).

Proof. For k<mk < m, revL(k)=2 revm(k)\mathrm{rev}_L(k) = 2\,\mathrm{rev}_m(k) and revL(m+k)=2 revm(k)+1\mathrm{rev}_L(m + k) = 2\,\mathrm{rev}_m(k) + 1. Let e=revm(k)e = \mathrm{rev}_m(k). Since ω2em=1\omega^{2em} = 1, a(ω2e)=∑i<m(ai+am+i)ω2ei=b(ω2e)a(\omega^{2e}) = \sum_{i<m} (a_i + a_{m+i}) \omega^{2ei} = b(\omega^{2e}). Since ω(2e+1)m=−1\omega^{(2e+1)m} = -1, a(ω2e+1)=∑i<m(ai−am+i)ωi(2e+1)=∑i<mci(ω2)ei=c(ω2e)a(\omega^{2e+1}) = \sum_{i<m} (a_i - a_{m+i}) \omega^{i(2e+1)} = \sum_{i<m} c_i (\omega^2)^{ei} = c(\omega^{2e}).

The splitting is one layer of decimation-in-frequency butterflies [GS1966]; applied recursively it gives fft_radix2. Truncation consists in skipping all work whose results are not among the first tt values.

The forward transform#

Algorithm 1: TFT with full input (fft_truncate1)

Input: a0,…,aL−1a_0, \ldots, a_{L-1}; an even tt with 2≤t≤L2 \le t \le L.

Output: a^0,…,a^t−1\hat a_0, \ldots, \hat a_{t-1}.

  1. If t=Lt = L, compute the full transform.
  2. If t≤mt \le m: set bi←ai+am+ib_i \gets a_i + a_{m+i} for i<mi < m and return the first tt values of the transform of bb (recursively, with ω2\omega^2).
  3. Otherwise: compute bb and cc by mm butterflies, compute the full transform of bb, and return it followed by the first t−mt - m values of the transform of cc (recursively).
Algorithm 2: TFT with zero padding (fft_truncate)

Input: a0,…,at−1a_0, \ldots, a_{t-1} (and aj=0a_j = 0 for j≥tj \ge t); an even tt with 2≤t≤L2 \le t \le L.

Output: a^0,…,a^t−1\hat a_0, \ldots, \hat a_{t-1}.

  1. If t=Lt = L, compute the full transform.
  2. If t≤mt \le m: then bi=aib_i = a_i, so return the first tt values of the transform of (a0,…,am−1)(a_0, \ldots, a_{m-1}), recursively with zero padding.
  3. Otherwise: for i<t−mi < t - m compute bi,cib_i, c_i by a butterfly; for t−m≤i<mt - m \le i < m, where am+i=0a_{m+i} = 0, set bi←aib_i \gets a_i and ci←ωiaic_i \gets \omega^i a_i. Compute the full transform of bb and the first t−mt - m values of that of cc by Algorithm 1.

Both are correct by Lemma 1 and induction on LL. In step 3 of Algorithm 2 the vector cc is in general not zero-padded, which is why the recursion switches to Algorithm 1.

Theorem 2 (Cost). Algorithm 1 and Algorithm 2 use at most (t/2)log⁡2L+L(t/2) \log_2 L + L butterflies, additions or multiplications by powers of ω\omega.

Proof. Let C(L,t)C(L, t) be the worst count, and C(L,L)=(L/2)log⁡2LC(L, L) = (L/2)\log_2 L for the full transform. If t≤mt \le m, the count is at most m+C(m,t)m + C(m, t). If t>mt > m, it is at most m+(m/2)log⁡2m+C(m,t−m)m + (m/2)\log_2 m + C(m, t - m). We show C(L,t)≤(t/2)log⁡2L+LC(L, t) \le (t/2)\log_2 L + L by induction. The case t=Lt = L is clear. If t≤mt \le m, by induction C(L,t)≤m+(t/2)(log⁡2L−1)+m≤(t/2)log⁡2L+LC(L, t) \le m + (t/2)(\log_2 L - 1) + m \le (t/2)\log_2 L + L. If t>mt > m, C(L,t)≤m+(m/2)(log⁡2L−1)+((t−m)/2)(log⁡2L−1)+m=(t/2)(log⁡2L−1)+LC(L, t) \le m + (m/2)(\log_2 L - 1) + ((t - m)/2)(\log_2 L - 1) + m = (t/2)(\log_2 L - 1) + L.

The full transform costs (L/2)log⁡2L(L/2)\log_2 L, so for tt just above L/2L/2 the truncated transform costs about half. In practice the additive term LL is smaller than the bound suggests, since Algorithm 2 does not add anything in step 2.

The inverse transform#

The inverse must recover a0,…,at−1a_0, \ldots, a_{t-1} from a^0,…,a^t−1\hat a_0, \ldots, \hat a_{t-1} when aj=0a_j = 0 for j≥tj \ge t. Since the evaluation points ωrev(k)\omega^{\mathrm{rev}(k)}, k<tk < t, do not form a subgroup, this is an interpolation problem, but the splitting lemma reduces it to the same recursion if, at each level, the missing values of one half are reconstructed from the other. The general step works with a mixed vector that holds transform values at the positions below tt and (scaled) coefficients at the positions from tt on.

Algorithm 3: Inverse TFT with mixed input (ifft_truncate1)

Input: xk=a^kx_k = \hat a_k for k<tk < t and xj=Lajx_j = L a_j for t≤j<Lt \le j < L; an even tt with 2≤t≤L2 \le t \le L.

Output: xj=Lajx_j = L a_j for j<tj < t.

  1. If t=Lt = L, apply the full inverse transform, which gives LaL a.
  2. If t≤mt \le m:

    1. for t≤i<mt \le i < m: xi←(xi+xm+i)/2x_i \gets (x_i + x_{m+i})/2;
    2. apply the algorithm recursively to x0,…,xm−1x_0, \ldots, x_{m-1} with tt (length mm, root ω2\omega^2);
    3. for i<ti < t: xi←2xi−xm+ix_i \gets 2 x_i - x_{m+i}.
  3. If t>mt > m:

    1. apply the full inverse transform of length mm to x0,…,xm−1x_0, \ldots, x_{m-1};
    2. for t−m≤i<mt - m \le i < m: d←xi−xm+id \gets x_i - x_{m+i}, xm+i←ωidx_{m+i} \gets \omega^i d, xi←xi+dx_i \gets x_i + d;
    3. apply the algorithm recursively to xm,…,xL−1x_m, \ldots, x_{L-1} with t−mt - m;
    4. for i<t−mi < t - m: (xi,xm+i)←(xi+ω−ixm+i,xi−ω−ixm+i)(x_i, x_{m+i}) \gets (x_i + \omega^{-i} x_{m+i}, x_i - \omega^{-i} x_{m+i}).

Theorem 3. Algorithm 3 is correct: on return, xj=Lajx_j = L a_j for j<tj < t.

Proof. Induction on LL; let bb, cc be as in Lemma 1, and note that the inverse transform of length mm returns mm times its argument.

Case t≤mt \le m. After step 2.1, for t≤i<mt \le i < m, xi=(Lai+Lam+i)/2=mbix_i = (L a_i + L a_{m+i})/2 = m b_i, while for k<tk < t, xk=a^k=b^kx_k = \hat a_k = \hat b_k. This is valid input for length mm, so after step 2.2, xi=mbix_i = m b_i for i<ti < t. Since m+i≥tm + i \ge t, xm+i=Lam+ix_{m+i} = L a_{m+i} was given, and step 2.3 yields 2mbi−Lam+i=Lai2m b_i - L a_{m+i} = L a_i.

Case t>mt > m. The first mm values are b^0,…,b^m−1\hat b_0, \ldots, \hat b_{m-1}, so step 3.1 gives xi=mbix_i = m b_i for all i<mi < m. For t−m≤i<mt - m \le i < m, the position m+i≥tm + i \ge t holds Lam+i=2mam+iL a_{m+i} = 2m a_{m+i}, so d=m(ai+am+i)−2mam+i=m(ai−am+i)d = m(a_i + a_{m+i}) - 2m a_{m+i} = m(a_i - a_{m+i}); step 3.2 sets xm+i=mcix_{m+i} = m c_i and xi=2mai=Laix_i = 2m a_i = L a_i, which is final. Now the second half holds c^k=a^m+k\hat c_k = \hat a_{m+k} at its positions k<t−mk < t - m and mcim c_i at its positions i≥t−mi \ge t - m, valid input for length mm, so after step 3.3 it holds mcim c_i for i<t−mi < t - m. Finally, since ω−ici=ai−am+i\omega^{-i} c_i = a_i - a_{m+i}, step 3.4 turns (mbi,mci)(m b_i, m c_i) into (2mai,2mam+i)(2m a_i, 2m a_{m+i}).

Algorithm 4: Inverse TFT with zero padding (ifft_truncate)

Input: a^0,…,a^t−1\hat a_0, \ldots, \hat a_{t-1}, where aj=0a_j = 0 for j≥tj \ge t; an even tt with 2≤t≤L2 \le t \le L.

Output: La0,…,Lat−1L a_0, \ldots, L a_{t-1}.

  1. If t=Lt = L, apply the full inverse transform.
  2. If t≤mt \le m: then b=(a0,…,am−1)b = (a_0, \ldots, a_{m-1}) with zero padding; recursively obtain maim a_i for i<ti < t and double them.
  3. If t>mt > m: apply the full inverse transform of length mm, giving mbim b_i; for t−m≤i<mt - m \le i < m, where am+i=0a_{m+i} = 0 and so ci=ωibic_i = \omega^i b_i, set xm+i←ωixix_{m+i} \gets \omega^i x_i; apply Algorithm 3 to the second half with t−mt - m; apply the inverse butterflies for i<t−mi < t - m and double xix_i for t−m≤i<mt - m \le i < m.

Theorem 4 (Inversion). If aj=0a_j = 0 for j≥tj \ge t, then a^0,…,a^t−1\hat a_0, \ldots, \hat a_{t-1} determine aa, and Algorithm 4 computes La0,…,Lat−1L a_0, \ldots, L a_{t-1} from them. Both inverse algorithms use at most (t/2)log⁡2L+L(t/2)\log_2 L + L butterflies, additions, halvings and multiplications by powers of ω\omega.

Proof. Algorithm 4 is Algorithm 3 with the known values Laj=0L a_j = 0 for j≥tj \ge t substituted: in step 2, xi=(0+0)/2x_i = (0 + 0)/2 makes the first loop trivial and 2xi−02 x_i - 0 the last one a doubling; in step 3, d=xid = x_i, so xm+i=ωixix_{m+i} = \omega^i x_i and the final value xi+dx_i + d is a doubling, which can be done at the end. Correctness follows from Theorem 3, and the algorithm shows that the tt values determine aa, since LL is invertible. For the cost, the loops of step 2 take mm operations in total, and those of step 3 take (2m−t)+(t−m)=m(2m - t) + (t - m) = m operations besides the transform of length mm, so the count satisfies the recursion of Theorem 2.

To multiply polynomials ff and gg whose product has length at most tt, one therefore computes the first tt values of f^\hat f and g^\hat g, multiplies them pointwise (these are the first tt values of the transform of fgfg, because fg^k=(fg)(ωrev(k))=f^kg^k\widehat{fg}_k = (fg)(\omega^{\mathrm{rev}(k)}) = \hat f_k \hat g_k), and applies the inverse TFT. This is fft_convolution: the product costs about 3⋅(t/2)log⁡2L3 \cdot (t/2) \log_2 L butterflies instead of 3⋅(L/2)log⁡2L3 \cdot (L/2) \log_2 L, and its running time grows smoothly with tt.

Use in FLINT#

Referenced from#

References#

  • [vdH2004] J. van der Hoeven, "Truncated FFTs", ISSAC 2004 notes, https://www.texmacs.org/joris/issac04/issac04.html
  • [vdH2005] J. van der Hoeven. Notes on the truncated Fourier transform. Technical report 2005-5, Université Paris-Sud, Orsay, 2005.
  • [Har2009] D. Harvey. A cache-friendly truncated FFT. Theoretical Computer Science 410 (2009), 2649–2658.
  • [HR2010] D. Harvey and D. S. Roche. An in-place truncated Fourier transform and applications to polynomial multiplication. ISSAC 2010, 325–329.
  • [Arn2013] A. Arnold. A new truncated Fourier transform algorithm. ISSAC 2013, 15–22.
  • [GS1966] W. M. Gentleman and G. Sande. Fast Fourier transforms – for fun and profit. AFIPS Fall Joint Computer Conference 29 (1966), 563–578.
Cite this page

The FLINT team, “Truncated FFTs,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/fft/truncated-fft.html (generated 2026-11-02).