Karatsuba multiplication
Karatsuba multiplication computes the product of two -digit numbers with about single-digit multiplications, fewer than the of the schoolbook method[1][2]. It splits each factor into two halves, and , and observes that the three products , and determine all four products of halves that the full product needs, since the middle term is the third minus the other two. Applying the idea recursively turns the four half-size multiplications of the obvious recursion into three. Anatoly Karatsuba discovered the method in 1960 as a student in Kolmogorov's seminar, refuting Kolmogorov's conjecture that multiplication requires order operations[3]. It was the first subquadratic multiplication algorithm and opened the study of fast arithmetic.
The algorithm
With , and ,
The three products have half the length, up to a carry digit from the additions, and are computed recursively; the additions, subtractions and shifts cost . The running time therefore satisfies , whose solution is [2].
Schoolbook and Karatsuba multiplication of natural numbers in base 10000, counting digit operations.
(* Multiplying natural numbers stored as arrays of base-10000 digits,least significant first, counting single-digit multiplications andthe digits passed through additions and subtractions. *)let base = 10_000let mults = ref 0 and adds = ref 0let normalize a = let n = ref (Array.length a) inwhile !n > 0 && a.(!n - 1) = 0 do decr n done; Array.sub a 0 !nlet carry a = (* propagate carries; digits may be negative on entry *)let a = Array.append a [| 0; 0 |] infor i = 0 to Array.length a - 2 dolet q = if a.(i) >= 0 then a.(i) / base else - ((- a.(i) + base - 1) / base) ina.(i) <- a.(i) - q * base; a.(i + 1) <- a.(i + 1) + qdone;normalize alet add a b = adds := !adds + max (Array.length a) (Array.length b);carry (Array.init (max (Array.length a) (Array.length b)) (fun i ->(if i < Array.length a then a.(i) else 0) + (if i < Array.length b then b.(i) else 0)))let sub a b = adds := !adds + max (Array.length a) (Array.length b);carry (Array.init (max (Array.length a) (Array.length b)) (fun i ->(if i < Array.length a then a.(i) else 0) - (if i < Array.length b then b.(i) else 0)))let shift a k = if a = [||] then a else Array.append (Array.make k 0) a(* Schoolbook: every digit of a times every digit of b. *)let schoolbook a b =if a = [||] || b = [||] then [||]else beginlet r = Array.make (Array.length a + Array.length b) 0 inArray.iteri (fun i x -> Array.iteri (fun j y -> incr mults; r.(i + j) <- r.(i + j) + x * y) b) a;carry rend(* Karatsuba: split at half the length, a = a1 B^m + a0, b = b1 B^m + b0,and use three products instead of four:a b = z2 B^2m + ((a0 + a1)(b0 + b1) - z2 - z0) B^m + z0. *)let rec karatsuba ?(threshold = 1) a b =let n = max (Array.length a) (Array.length b) inif n <= threshold || Array.length a = 0 || Array.length b = 0 then schoolbook a belse beginlet m = n / 2 inlet lo x = normalize (Array.sub x 0 (min m (Array.length x)))and hi x = if Array.length x > m then Array.sub x m (Array.length x - m) else [||] inlet a0 = lo a and a1 = hi a and b0 = lo b and b1 = hi b inlet z0 = karatsuba ~threshold a0 b0 and z2 = karatsuba ~threshold a1 b1 inlet z1 = sub (sub (karatsuba ~threshold (add a0 a1) (add b0 b1)) z2) z0 inadd (add (shift z2 (2 * m)) (shift z1 m)) z0endlet of_string s = (* decimal string to base-10000 digits *)let n = String.length s inArray.init ((n + 3) / 4) (fun i -> let hi = n - 4 * i in let lo = max 0 (hi - 4) in int_of_string (String.sub s lo (hi - lo)))|> normalizelet to_string a = if a = [||] then "0" elselet parts = Array.to_list (Array.mapi (fun i d -> if i = Array.length a - 1 then string_of_int d else Printf.sprintf "%04d" d) a) inString.concat "" (List.rev parts)
Checking against Zarith.
open Kara
Running it.
85397342226735670654635508695465744950348885357650690581833014653136349617576232159238592126769012450schoolbook 169 digit products, Karatsuba 86, both equal to Zarith: true300 random products up to 300 digits agree with Zarith: true
The same identity multiplies polynomials, with the halves taken by degree; there are no carries, and the method is used in computer algebra and in cryptographic implementations of polynomial and binary-field arithmetic.
Cost in practice
Digit multiplications and additions for operands of increasing length: schoolbook, pure Karatsuba, and Karatsuba that switches to schoolbook below 16 digits.
open Kara(* Digit multiplications for n-digit operands (n base-10000 digits). *)
Running it.
digits schoolbook Karatsuba (mul + add) cutoff 16 (mul + add)16 256 133 + 1392 256 + 064 4096 1208 + 13535 2235 + 1356256 65536 11099 + 128224 19719 + 181411024 1048576 100400 + 1176312 176079 + 1858714096 16777216 905724 + 10674789 1581589 + 1756051
Recursing all the way down saves multiplications but spends them on additions, and at small sizes the schoolbook method is faster. Real implementations therefore recurse only above a threshold, tuned to the machine; in GMP the Karatsuba range begins at a few dozen machine words[7]. On 4,096-digit operands the version with a cutoff does about a fifth of the schoolbook work in total.
Generalizations
Karatsuba's method evaluates the linear polynomials and at , multiplies the values, and interpolates the quadratic product. Toom observed in 1963 that splitting into parts and evaluating at points reduces products to , giving exponents that approach 1; Cook made the construction practical in his 1966 thesis[4][9]. Toom-3, with three parts and five products, costs . Evaluating at roots of unity instead, by the fast Fourier transform, gives Schönhage and Strassen's algorithm of 1971[5], and Harvey and van der Hoeven reached in 2019[6]. Montgomery found Karatsuba-like formulae for five, six and seven parts that use fewer products than Toom–Cook for the same number of parts[8]. Libraries combine all of these, each above its own threshold[7].
History
In 1960 Andrey Kolmogorov conjectured in his seminar at Moscow State University that multiplying two -digit numbers requires on the order of elementary operations. Within a week, Anatoly Karatsuba, then 23, found the three-product method and disproved it[3]. The result was published in 1962 under the names of Karatsuba and Yuri Ofman, although Ofman's contribution was a separate result[1][3]. Toom's generalization followed in 1963[4], Cook's thesis in 1966[9], and FFT-based multiplication in 1971[5].
see also
- Fast Fourier transformThe fast Fourier transform (FFT) computes the discrete Fourier transform of n values, the evaluation of a polynomial at the n complex n-th roots of unity, in O(n log n) operations instead of O(n^2). The Cooley-Tukey algorithm splits the input into even and odd positions, transforms each half recursively, and combines them with n/2 butterflies. Because the transform turns convolution into pointwise multiplication, the FFT multiplies polynomials and large integers in near-linear time; over a finite field with suitable roots of unity the same algorithm is exact.
- Knuth's Algorithm DKnuth's Algorithm D divides one multiple-precision integer by another: schoolbook long division in base 2^k, where each quotient digit is guessed from the leading limbs of the remainder and divisor. After normalizing the divisor so its top limb is at least half the base, the guess is never too small and at most two too large, a cheap test with one more limb removes almost all errors, and a rare add-back step fixes the rest. It takes O(mn) operations for an (m+n)-limb dividend and an n-limb divisor.
- Horner's methodHorner's method evaluates a polynomial a_n x^n + ... + a_0 by nesting the multiplications, (...(a_n x + a_(n-1)) x + ...) x + a_0, which takes n multiplications and n additions, the fewest possible for a general polynomial. The intermediate values are the coefficients of the quotient on division by x - c, so the same loop performs synthetic division, and repeated divisions give the derivatives and the shifted polynomial p(x + c). It is backward stable, but near a multiple root the result can be dominated by rounding errors.
further reading
- [1]A. Karatsuba, Yu. Ofman, “Multiplication of multidigit numbers on automata”, Soviet Physics Doklady 7 (1963).
- [2]D. E. Knuth, The Art of Computer Programming, Vol. 2: Seminumerical Algorithms, §4.3.3, Addison-Wesley (3rd ed., 1997).
- [3]A. A. Karatsuba, “The complexity of computations”, Proceedings of the Steklov Institute of Mathematics 211 (1995).
- [4]A. L. Toom, “The complexity of a scheme of functional elements realizing the multiplication of integers”, Soviet Mathematics Doklady 3 (1963).
- [5]A. Schönhage, V. Strassen, “Schnelle Multiplikation großer Zahlen”, Computing 7 (1971).
- [6]D. Harvey, J. van der Hoeven, “Integer multiplication in time O(n log n)”, Annals of Mathematics 193 (2021).
- [7]T. Granlund and the GMP development team, GNU MP: The GNU Multiple Precision Arithmetic Library, “Multiplication algorithms”.
- [8]P. L. Montgomery, “Five, six, and seven-term Karatsuba-like formulae”, IEEE Transactions on Computers 54 (2005).
- [9]S. A. Cook, On the Minimum Computation Time of Functions, PhD thesis, Harvard University (1966).
last updated