Purpose: Multiply two -bit integers in using an FFT over the ring , where the “roots of unity” are powers of 2 — so every twiddle multiplication is a shift. Schönhage and Strassen, 1971.

The Idea

An ordinary FFT over the complex numbers loses precision, and over a prime field it needs modular multiplications. Schönhage-Strassen picks a ring where the transform costs almost nothing:

In , the element has order , because . So is a -th root of unity, and multiplying by a power of it is a cyclic shift — no multiplication at all.

Algorithm

  1. Split each -bit operand into blocks of bits each.
  2. Choose so that can hold the largest possible coefficient of the product without wraparound, and so that a -th root of unity (a power of 2) exists in the ring.
  3. Run the FFT in . All twiddle multiplications are shifts: bit operations for the whole transform.
  4. Multiply pointwise — this needs multiplications of -bit numbers, done by recursing into Schönhage-Strassen.
  5. Inverse transform, then carry-propagate to recombine.

The is the recursion depth: block sizes shrink roughly as a square root each level.

The multiplication complexity story

YearResultTime
antiquityschoolbook
1960Karatsuba
1963Toom-Cook
1971Schönhage-Strassen
2007Fürer
2019Harvey-van der Hoevenconjectured optimal

The 2019 result finally achieved the that Schönhage and Strassen conjectured in the same 1971 paper. It is entirely theoretical: the algorithm only beats Schönhage-Strassen for numbers with more than about bits.

In practice

GMP uses Schönhage-Strassen above roughly 30 000-100 000 bits. Below that, Toom-Cook variants win. This makes it the only one of the sub-quadratic asymptotic improvements that is both used in production and asymptotically strong — Fürer and Harvey-van der Hoeven are galactic algorithms.

Why competitive programmers should still care

Not to implement it, but for the idea: choose an algebraic setting where the expensive operation becomes cheap. The specific instance — a ring where roots of unity are powers of 2, so transforms are shifts — reappears whenever you need convolution without floating point. It is the same instinct behind choosing an NTT-friendly prime like , whose -adic structure gives cheap roots of unity.

Variants / Use Cases