Lably
Skip to content

Multiplication algorithm

Algorithm to multiply two numbers

  • 20 min read
  • 5 chapters

Related on Lably

Through Algorithm, Multiplication and Ancient history

The oldest and simplest method, known since antiquity as long multiplication or grade-school multiplication, consists of multiplying every digit in the first number by every digit in the second and adding the results. This has a time complexity of O(n2), where n is the number of digits. When done by hand, this may also be reframed as grid method multiplication or lattice multiplication. In software, this may be called "shift and add" due to bitshifts and addition being the only two operations needed.

In 1960, Anatoly Karatsuba discovered Karatsuba multiplication, unleashing a flood of research into fast multiplication algorithms. This method uses three multiplications rather than four to multiply two two-digit numbers. (A variant of this can also be used to multiply complex numbers quickly.) Done recursively, this has a time complexity of O(nlog2⁡3). Splitting numbers into more than two parts results in Toom–Cook multiplication; for example, using three parts results in the Toom-3 algorithm. Using many parts can set the exponent arbitrarily close to 1, but the constant factor also grows, making it impractical.

In 1968, the Schönhage–Strassen algorithm, which makes use of a Fourier transform over a modulus, was discovered. It has a time complexity of O(nlog⁡nlog⁡log⁡n). In 2007, Martin Fürer proposed an algorithm with complexity O(nlog⁡n2Θ(log∗⁡n)). In 2014, Harvey, Joris van der Hoeven, and Lecerf proposed one with complexity O(nlog⁡n23log∗⁡n), thus making the implicit constant explicit; this was improved to O(nlog⁡n22log∗⁡n) in 2018. Lastly, in 2019, Harvey and van der Hoeven came up with a galactic algorithm with complexity O(nlog⁡n). This matches a guess by Schönhage and Strassen that this would be the optimal bound, although this remains a conjecture today.

Integer multiplication algorithms can also be used to multiply polynomials by means of the method of Kronecker substitution.

Long multiplication

If a positional numeral system is used, a natural way of multiplying numbers is taught in schools as long multiplication, sometimes called grade-school multiplication, sometimes called the Standard Algorithm: multiply the multiplicand by each digit of the multiplier and then add up all the properly shifted results. It requires memorization of the multiplication table for single digits.

This is the usual algorithm for multiplying larger numbers by hand in base 10. A person doing long multiplication on paper will write down all the products and then add them together; an abacus-user will sum the products as soon as each one is computed.

Example

This example uses long multiplication to multiply 23,958,233 (multiplicand) by 5,830 (multiplier) and arrives at 139,676,498,390 for the result (product).

23958233 × 5830 ——————————————— 00000000 ( = 23,958,233 × 0) 71874699 ( = 23,958,233 × 30) 191665864 ( = 23,958,233 × 800) + 119791165 ( = 23,958,233 × 5,000) ——————————————— 139676498390 ( = 139,676,498,390)

Other notations

In some countries such as Germany, the above multiplication is depicted similarly but with the original product kept horizontal and computation starting with the first digit of the multiplier:

23958233 · 5830 ——————————————— 119791165 191665864 71874699 00000000 ——————————————— 139676498390

Below pseudocode describes the process of above multiplication. It keeps only one row to maintain the sum which finally becomes the result. Note that the '+=' operator is used to denote sum to existing value and store operation (akin to languages such as Java and C) for compactness.

<span id="mwRg"></span><span class="linenos" data-line="1" id="mwRw"></span><span class="n" id="mwSA">multiply</span><span class="p" id="mwSQ">(</span><span class="n" id="mwSg">a</span><span class="p" id="mwSw">[</span><span class="mi" id="mwTA">1</span><span class="o" id="mwTQ">..</span><span class="n" id="mwTg">p</span><span class="p" id="mwTw">]</span><span class="o" id="mwUA">,</span><span class="w" id="mwUQ"> </span><span class="n" id="mwUg">b</span><span class="p" id="mwUw">[</span><span class="mi" id="mwVA">1</span><span class="o" id="mwVQ">..</span><span class="n" id="mwVg">q</span><span class="p" id="mwVw">]</span><span class="o" id="mwWA">,</span><span class="w" id="mwWQ"> </span><span class="n" id="mwWg">base</span><span class="p" id="mwWw">)</span><span class="w" id="mwXA"> </span><span class="c1" id="mwXQ">// Operands containing rightmost digits at index 1</span> <span class="linenos" data-line="2" id="mwXg"></span><span class="w" id="mwXw"> </span><span class="n" id="mwYA">product</span><span class="w" id="mwYQ"> </span><span class="o" id="mwYg">=</span><span class="w" id="mwYw"> </span><span class="p" id="mwZA">[</span><span class="mi" id="mwZQ">1</span><span class="o" id="mwZg">..</span><span class="n" id="mwZw">p</span><span class="o" id="mwaA">+</span><span class="n" id="mwaQ">q</span><span class="p" id="mwag">]</span><span class="w" id="mwaw"> </span><span class="c1" id="mwbA">// Allocate space for result</span> <span class="linenos" data-line="3" id="mwbQ"></span><span class="w" id="mwbg"> </span><span class="k" id="mwbw">for</span><span class="w" id="mwcA"> </span><span class="n" id="mwcQ">b_i</span><span class="w" id="mwcg"> </span><span class="o" id="mwcw">=</span><span class="w" id="mwdA"> </span><span class="mi" id="mwdQ">1</span><span class="w" id="mwdg"> </span><span class="k" id="mwdw">to</span><span class="w" id="mweA"> </span><span class="n" id="mweQ">q</span><span class="w" id="mweg"> </span><span class="c1" id="mwew">// for all digits in b</span> <span class="linenos" data-line="4" id="mwfA"></span><span class="w" id="mwfQ"> </span><span class="n" id="mwfg">carry</span><span class="w" id="mwfw"> </span><span class="o" id="mwgA">=</span><span class="w" id="mwgQ"> </span><span class="mi" id="mwgg">0</span> <span class="linenos" data-line="5" id="mwgw"></span><span class="w" id="mwhA"> </span><span class="k" id="mwhQ">for</span><span class="w" id="mwhg"> </span><span class="n" id="mwhw">a_i</span><span class="w" id="mwiA"> </span><span class="o" id="mwiQ">=</span><span class="w" id="mwig"> </span><span class="mi" id="mwiw">1</span><span class="w" id="mwjA"> </span><span class="k" id="mwjQ">to</span><span class="w" id="mwjg"> </span><span class="n" id="mwjw">p</span><span class="w" id="mwkA"> </span><span class="c1" id="mwkQ">// for all digits in a</span> <span class="linenos" data-line="6" id="mwkg"></span><span class="w" id="mwkw"> </span><span class="n" id="mwlA">product</span><span class="p" id="mwlQ">[</span><span class="n" id="mwlg">a_i</span><span class="w" id="mwlw"> </span><span class="o" id="mwmA">+</span><span class="w" id="mwmQ"> </span><span class="n" id="mwmg">b_i</span><span class="w" id="mwmw"> </span><span class="o" id="mwnA">-</span><span class="w" id="mwnQ"> </span><span class="mi" id="mwng">1</span><span class="p" id="mwnw">]</span><span class="w" id="mwoA"> </span><span class="o" id="mwoQ">+=</span><span class="w" id="mwog"> </span><span class="n" id="mwow">carry</span><span class="w" id="mwpA"> </span><span class="o" id="mwpQ">+</span><span class="w" id="mwpg"> </span><span class="n" id="mwpw">a</span><span class="p" id="mwqA">[</span><span class="n" id="mwqQ">a_i</span><span class="p" id="mwqg">]</span><span class="w" id="mwqw"> </span><span class="o" id="mwrA">*</span><span class="w" id="mwrQ"> </span><span class="n" id="mwrg">b</span><span class="p" id="mwrw">[</span><span class="n" id="mwsA">b_i</span><span class="p" id="mwsQ">]</span> <span class="linenos" data-line="7" id="mwsg"></span><span class="w" id="mwsw"> </span><span class="n" id="mwtA">carry</span><span class="w" id="mwtQ"> </span><span class="o" id="mwtg">=</span><span class="w" id="mwtw"> </span><span class="n" id="mwuA">product</span><span class="p" id="mwuQ">[</span><span class="n" id="mwug">a_i</span><span class="w" id="mwuw"> </span><span class="o" id="mwvA">+</span><span class="w" id="mwvQ"> </span><span class="n" id="mwvg">b_i</span><span class="w" id="mwvw"> </span><span class="o" id="mwwA">-</span><span class="w" id="mwwQ"> </span><span class="mi" id="mwwg">1</span><span class="p" id="mwww">]</span><span class="w" id="mwxA"> </span><span class="o" id="mwxQ">/</span><span class="w" id="mwxg"> </span><span class="n" id="mwxw">base</span> <span class="linenos" data-line="8" id="mwyA"></span><span class="w" id="mwyQ"> </span><span class="n" id="mwyg">product</span><span class="p" id="mwyw">[</span><span class="n" id="mwzA">a_i</span><span class="w" id="mwzQ"> </span><span class="o" id="mwzg">+</span><span class="w" id="mwzw"> </span><span class="n" id="mw0A">b_i</span><span class="w" id="mw0Q"> </span><span class="o" id="mw0g">-</span><span class="w" id="mw0w"> </span><span class="mi" id="mw1A">1</span><span class="p" id="mw1Q">]</span><span class="w" id="mw1g"> </span><span class="o" id="mw1w">=</span><span class="w" id="mw2A"> </span><span class="n" id="mw2Q">product</span><span class="p" id="mw2g">[</span><span class="n" id="mw2w">a_i</span><span class="w" id="mw3A"> </span><span class="o" id="mw3Q">+</span><span class="w" id="mw3g"> </span><span class="n" id="mw3w">b_i</span><span class="w" id="mw4A"> </span><span class="o" id="mw4Q">-</span><span class="w" id="mw4g"> </span><span class="mi" id="mw4w">1</span><span class="p" id="mw5A">]</span><span class="w" id="mw5Q"> </span><span class="k" id="mw5g">mod</span><span class="w" id="mw5w"> </span><span class="n" id="mw6A">base</span> <span class="linenos" data-line="9" id="mw6Q"></span><span class="w" id="mw6g"> </span><span class="n" id="mw6w">product</span><span class="p" id="mw7A">[</span><span class="n" id="mw7Q">b_i</span><span class="w" id="mw7g"> </span><span class="o" id="mw7w">+</span><span class="w" id="mw8A"> </span><span class="n" id="mw8Q">p</span><span class="p" id="mw8g">]</span><span class="w" id="mw8w"> </span><span class="o" id="mw9A">=</span><span class="w" id="mw9Q"> </span><span class="n" id="mw9g">carry</span><span class="w" id="mw9w"> </span><span class="c1" id="mw-A">// last digit comes from final carry</span> <span class="linenos" data-line="10" id="mw-Q"></span><span class="w" id="mw-g"> </span><span class="n" id="mw-w">return</span><span class="w" id="mw_A"> </span><span class="n" id="mw_Q">product</span>

Usage in computers

Some chips implement long multiplication, in hardware or in microcode, for various integer and floating-point word sizes. In arbitrary-precision arithmetic, it is common to use long multiplication with the base set to 2w, where w is the number of bits in a word, for multiplying relatively small numbers. To multiply two numbers with n digits using this method, one needs about n2 operations. More formally, multiplying two n-digit numbers using long multiplication requires Θ(n2) single-digit operations (additions and multiplications).

When implemented in software, long multiplication algorithms must deal with overflow during additions, which can be expensive. A typical solution is to represent the number in a small base, b, such that, for example, 8b is a representable machine integer. Several additions can then be performed before an overflow occurs. When the number becomes too large, we add part of it to the result, or we carry and map the remaining part back to a number that is less than b. This process is called normalization. Richard Brent used this approach in his Fortran package, MP.

Computers initially used a very similar algorithm to long multiplication in base 2, but modern processors have optimized circuitry for fast multiplications using more efficient algorithms, at the price of a more complex hardware realization. In base two, long multiplication is sometimes called "shift and add", because the algorithm simplifies and just consists of shifting left (multiplying by powers of two) and adding. Most currently available microprocessors implement this or other similar algorithms (such as Booth encoding) for various integer and floating-point sizes in hardware multipliers or in microcode.

On currently available processors, a bit-wise shift instruction is usually (but not always) faster than a multiply instruction and can be used to multiply (shift left) and divide (shift right) by powers of two. Multiplication by a constant and division by a constant can be implemented using a sequence of shifts and adds or subtracts. For example, there are several ways to multiply by 10 using only bit-shift and addition.

<span id="mwASQ"></span> <span class="p" id="mwASU">((</span><span class="nx" id="mwASY">x</span> <span class="o" id="mwASc"><<</span> <span class="mi" id="mwASg">2</span><span class="p" id="mwASk">)</span> <span class="o" id="mwASo">+</span> <span class="nx" id="mwASs">x</span><span class="p" id="mwASw">)</span> <span class="o" id="mwAS0"><<</span> <span class="mi" id="mwAS4">1</span> <span class="c1" id="mwAS8"># Here 10*x is computed as (x*2^2 + x)*2</span> <span class="p" id="mwATA">(</span><span class="nx" id="mwATE">x</span> <span class="o" id="mwATI"><<</span> <span class="mi" id="mwATM">3</span><span class="p" id="mwATQ">)</span> <span class="o" id="mwATU">+</span> <span class="p" id="mwATY">(</span><span class="nx" id="mwATc">x</span> <span class="o" id="mwATg"><<</span> <span class="mi" id="mwATk">1</span><span class="p" id="mwATo">)</span> <span class="c1" id="mwATs"># Here 10*x is computed as x*2^3 + x*2</span>

In some cases such sequences of shifts and adds or subtracts will outperform hardware multipliers and especially dividers. A division by a number of the form 2n or 2n±1 often can be converted to such a short sequence.

Sign in to keep reading

4 more chapters are free with a Lably account.

More in Computing and communication