Reaves.dev

v0.1.0

built using

Phoenix v1.7.17

Fast Integer Multiplication

Stephen M. Reaves

::

2025-01-08

Using the Divide and Conquer approach to multiply arbitrarily large numbers

Summary

Multiplying is expensive, but addition/subtraction are cheap. Using some clever algebra tricks, we can reduce the number of multiplications that are needed which will decrease the asymptotic runtime of certain algorithms.

Contents

Multiplying Complex Numbers

Multiplication is expensive, adding/subtracting are cheap.

Given two complex numbers, a+bi a + bi and c+di c + di :

(a+bi)(c+di)=ac+bd(i2)+(bc+ad) (a + bi)(c + di) = ac + bd(i^2) + (bc + ad)

(a+bi)(c+di)=ac+bd(1)+(bc+ad) \phantom{(a + bi)(c + di)} = ac + bd(-1) + (bc + ad)

(a+bi)(c+di)=acbd+(bc+ad) \phantom{(a + bi)(c + di)} = ac - bd + (bc + ad)

We need 4 real number multiplications:

Can we get by using only 3 mulitiplications?

We can compute (bc+ad) (bc + ad) without computing bc bc or ad ad

If we notice:

(a+b)(c+d)=ac+bd+(bc+ad) (a + b)(c + d) = ac + bd + (bc + ad)

We see the ac ac and bd bd terms that we want in our previous example. We can then solve for the (bc+ad) (bc + ad) term:

(bc+ad)=(a+b)(c+d)acbd (bc + ad) = (a+b)(c+d) - ac - bd

So we can substitute this in for our original equation:

(a+bi)(c+di)=acbd+(bc+ad) (a + bi)(c + di) = ac - bd + (bc + ad)

(a+bi)(c+di)=acbd+(a+b)(c+d)acbd \phantom{(a + bi)(c + di)} = ac - bd + (a+b)(c+d) - ac - bd

Which gets us down to 3 multiplication operations!

Easy Multiply

Input: n-bit integers x and y, assume n is power of 2

Goa: Compute z=xy z= xy

Start by breaking each input into 2 halves (n/2 bits)

x=2n/2xL+xR x = 2^{n/2}x_L + x_R

y=2n/2yL+yR y = 2^{n/2}y_L + y_R

Example

xxL=182=(10110110)2 x \phantom{x_L} = 182 = (10110110)_2

xLx=182=(10110110)2=11 x_L \phantom{x} = \phantom{182 =} (1011\phantom{0110})_2 = 11

xRx=182=(10110110)2=6 x_R \phantom{x} = \phantom{182 =} (\phantom{1011}0110)_2 = 6

182=11×24+6 182 = 11 \times 2^4 + 6

xy=(2n/2xL+xR)(2n/2yL+yR) xy = \left(2^{n/2}x_L + x_R \right)\left(2^{n/2}y_L + y_R \right)

xy=2nxLyL+2n/2(xLyR+xRyL)+xRyR \phantom{xy} = 2^n x_L y_L + 2^{n/2}\left( x_L y_R + x_R y_L \right) + x_R y_R

We have 4 products of n/2 n/2 numbers which we can recursively compute:

Can we get down to 3?

Psuedocode

EasyMultiply(x,y):
  # xl = first n/2 bits of x
  # xr = last n/2 bits of x
  binary = bin(x)[2:]
  n = len(binary)
  xl = binary[:int(n/2)]
  xl = binary[int(n/2):]

  # O(n) time to compute
  binary = bin(y)[2:]
  yl = binary[:int(n/2)]
  yl = binary[int(n/2):]
  
  # Each takes T(n/2) time to compute
  A = EasyMultiply(xl,yl)
  B = EasyMultiply(xr,yr)
  C = EasyMultiply(xl,yr)
  D = EasyMultiply(xr,yl)

  # Shifts are O(n) and O(n/2) respectively
  Z = (2**n)*A + (2**(n/2))(C + D) + B

  return Z

Runtime is T(n)=O(n+4T(n2)) T(n) = O\left( n + 4T\left(\frac{n}{2}\right) \right) or O(n2) O\left(n^2\right)

Fast Mutliply

Given:

(xL+xR)(yL+yR)=xLyL+xRyR+(xLyR+xRyL) \left( x_L + x_R \right) \left( y_L + y_R \right) = x_L y_L + x_R y_R + \left( x_L y_R + x_R y_L \right)

(xLyR+xRyL)=(xL+xR)(yL+yR)xLyLxRyR \left( x_L y_R + x_R y_L \right) = \left( x_L + x_R \right) \left( y_L + y_R \right) - x_L y_L - x_R y_R

Then:

xy=(2n/2xL+xR)(2n/2yL+yR) xy = \left(2^{n/2}x_L + x_R \right)\left(2^{n/2}y_L + y_R \right)

xy=2nxLyL+2n/2(xLyR+xRyL)+xRyR \phantom{xy} = 2^n x_L y_L + 2^{n/2}\left( x_L y_R + x_R y_L \right) + x_R y_R

xy=2nxLyL+2n/2((xL+xR)(yL+yR)xLyLxRyR)+xRyR \phantom{xy} = 2^n x_L y_L + 2^{n/2}\left( \left( x_L + x_R \right) \left( y_L + y_R \right) - x_L y_L - x_R y_R \right) + x_R y_R

xy=2nA+2n/2(CAB)+B \phantom{xy} = 2^n A + 2^{n/2}\left( C - A - B \right) + B

Psuedocode

FastMultiply(x,y):
  # xl = first n/2 bits of x
  # xr = last n/2 bits of x
  binary = bin(x)[2:]
  n = len(binary)
  xl = binary[:int(n/2)]
  xl = binary[int(n/2):]

  # O(n) time to compute
  binary = bin(y)[2:]
  yl = binary[:int(n/2)]
  yl = binary[int(n/2):]
  
  # Each takes T(n/2) time to compute
  A = FastMultiply(xl,yl)
  B = FastMultiply(xr,yr)
  C = FastMultiply(xl + xr, yl+yr)

  # Shifts are O(n) and O(n/2) respectively
  Z = (2**n)*A + (2**(n/2))(C - A - B) + B

  return Z

Runtime

T(n)=3T(n2)+O(n) T(n) = 3T\left( \frac{n}{2} \right) + O(n)

T(n)cn+3T(n2) \phantom{T(n)} \le cn + 3T\left( \frac{n}{2} \right)

T(n)cn+3T(cn2+3T(n22)) \phantom{T(n)} \le cn + 3T\left( c\frac{n}{2} + 3T\left( \frac{n}{2^2} \right) \right)

T(n)cn(1+32)+32(cn22+3T(n23)) \phantom{T(n)} \le cn \left( 1 + \frac{3}{2} \right) + 3^2\left( c\frac{n}{2^2} + 3T\left( \frac{n}{2^3} \right) \right)

T(n)cn(1+32+(32)2++(32)log2n) \phantom{T(n)} \le cn \left( 1 + \frac{3}{2} + \left( \frac{3}{2} \right)^2 + \cdots + \left( \frac{3}{2} \right)^{\log_2{n}} \right)

Since it is an increasing geometric series, it is on the order of the last term.

See exercise 0.2:

T(n)=O(3log2n) \phantom{T(n)} = O\left( 3^{\log_2{n}} \right)

T(n)O(31.59) \phantom{T(n)} \approx O\left( 3^{1.59} \right)