Skip to content

Marina Mele's site

Reflections on family, values, and personal growth

Menu
  • Home
  • About
Menu

3rd-grade & Karatsuba multiplication Algorithms

Posted on September 4, 2016June 1, 2023 by Marina Mele

In this post we’re going to study the third-grade algorithm to compute the product of two numbers, and we’re going to compare it with a much more efficient algorithm: The Karatsuba multiplication algorithm.

Did you know that these two algorithms are the ones used in the built in Python multiplication?

We will talk about the Order of both algorithms and give you Python implementations of both of them.

Maybe you’re thinking, why is she writing now about algorithms? Some time ago, I took the course Algorithms: Design and Analysis, Part 1&2, by Tim Roughgarden,  and it was a lot of fun.

Now I’m taking the course again, but I’m spending more time to review the algorithms and play with them. I really encourage you to take the course if you have some time. But first, read this post 🙂

This is the outline:

  • Third grade multiplication algorithm
  • Python code for the third grade product algorithm
  • The Karatsuba Algorithm
  • Python code for the Karatsuba algorithm

Let’s start! 🙂

Third grade multiplication algorithm

First, we’re going to review the third grade algorithm, which all of you already know 🙂

Let’s start with these two numbers: 5678 x 1234. In order to compute their product you start with 4*5678, represented as:

  (2)(3)(3)
   5  6  7  8
x  1  2  3 |4|
-------------
2  2  7  1  2

Let’s count the number of operations performed in this step:

– If n is the number of digits of the first number, there are n products and at most n sums (carried numbers).

– So in total, you need 2n operations.

If we continue with the product, we have to repeat n times the same operation (where we assume that n is also the number of digits of the second number):

         5  6  7  8
      x  1  2  3  4
      -------------
      2  2  7  1  2
   1  7  0  3  4
1  1  3  5  6
5  6  7  8

which gives a total of 2n2 operations.

Finally, you need to sum all these numbers,

            5  6  7  8
         x  1  2  3  4
         -------------
         2  2  7  1  2
      1  7  0  3  4
   1  1  3  5  6
+  5  6  7  8
----------------------
   7  0  0  6  6  5  2

which takes around n2 operations more.

So in total, the number of operations is ~3n2, which means that it’s quadratic with the input (proportional to n2).

One point I would like to mention about this algorithm is that it’s complete: no matter what x and y you start with, if you perform correctly the algorithm, the algorithm terminates and finds the correct solution.

Python code for the third grade product algorithm

Here I give you an example of an implementation of the third grade algorithm, where I have included a Counter for the sum and product operations:

# third_grade_algorithm.py

def counted(fn):
    # Counter Decorator
    def wrapper(*args, **kwargs):
        if "" in args or " " in args:
            return "".join(map(lambda s: s.strip(), args))
        wrapper.called += 1
        return fn(*args, **kwargs)
    wrapper.called = 0
    wrapper.__name__ = fn.__name__
    return wrapper


@counted
def prod(x, y):
    # x, y are strings --> returns a string of x*y
    return str(eval("%s * %s" % (x, y)))


@counted
def suma(x, y):
    # x, y are strings --> returns a string of x+y
    return str(eval("%s + %s" % (x, y)))


def one_to_n_product(d, x):
    """d is a single digit, x is n-digit --> returns a string of d*x
    """
    result = ""
    carry = "0"
    for i, digit in enumerate(reversed(x)):
        r = suma(prod(d, digit), carry)
        carry, digit = r[:-1], r[-1]
        result = digit + result
    return carry + result


def sum_middle_products(middle_products):
    # middle_products is a list of strings --> returns a string
    max_length = max([len(md) for md in middle_products])
    for i, md in enumerate(middle_products):
        middle_products[i] = " " * (max_length - len(md)) + md
    carry = "0"
    result = ""
    for i in range(1, max_length + 1):
        row = [carry] + [md[-i] for md in middle_products]
        r = reduce(suma, row)
        carry, digit = r[:-1], r[-1]
        result = digit + result
    return carry + result


def algorithm(x, y):
    # x, y are integers --> returns an integer, x*y
    x, y = str(x), str(y)
    middle_products = []
    for i, digit in enumerate(reversed(y)):
        middle_products.append(one_to_n_product(digit, x) + " " * i)
    return int(sum_middle_products(middle_products))

Using that algorithm, if you run

$ python -i third_grade_algorithm.py

where (third_grade_algorithm.py is the name of the file), you will run the previous code and terminate with the Python console open. This way you can call your algorithm function and try:

>>> algorithm(6885, 1600)
1101600
>>> print("Suma was called %i times" % suma.called)
Suma was called 20 times 
>>> print("Prod was called %i times" % prod.called)
Prod was called 16 times

So it took 20 + 16 = 36 operations to compute the product of these two numbers.

Once we have this code, we can average the number of operations used in the product of n-digit numbers:

def random_prod(n):
    suma.called = 0
    prod.called = 0
    x = randint(pow(10, n - 1), pow(10, n))
    y = randint(pow(10, n - 1), pow(10, n))
    algorithm(str(x), str(y))
    return suma.called + prod.called


def average():
    ntimes = 200
    nmax = 10
    result = []
    for n in range(nmax):
        avg = sum([random_prod(n + 1) for i in range(ntimes)]) / float(ntimes)
        result.append([n + 1, avg])
    return result

In the following figure, we plot the result of the previous experiment when ntimes = 200 samples and nmax = 10 digits:

operations-3rd-grade-algorithm

We can see that these points fit the curve f(n) = 2.7 n2.

Note that 2.7 < 3, the proportionality factor we deduced before. This is because we were assuming the worst case scenario, whereas the average product takes into account random numbers.

To sum up, the 3rd grade algorithm is an Ο(n2) complete algorithm.

But can we do better? Is there an algorithm that performs the product of two numbers quicker?

The answer is yes, and in the following section we will study one of them: The Karatsuba Algorithm.

The Karatsuba Algorithm

Let’s first explain this algorithm through an example:

Imagine you want to compute again the product of these two numbers:

x = 5678
y = 1234

In order to do so, we will first decompose them in a singular way:

x = 5678
a = 56; b = 78
--> x = 100 * a + b

and the same for y:

y = 1234
c = 12; d = 34
--> y = 100 * c + d

If we want to know the product x * y:

xy = (100 * a + b)(100 * c + d) = 100^2 * ac + 100 * (ad + bc) + bd

Where we can calculate the following 3 parts separately:

A = ac 
B = ad + bc
C = bd

However, we need two compute two products for the B term. Let’s see how we can compute only one product to reduce calculations 🙂

If we expand the product:

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

we see than the right hand side of the equation contains all A,B and C terms.

In particular, if we isolate B = ad + bc, we get:

B = D - ac - bd = D - A - C

Great! Now we only need three smaller products in order to compute x * y:

xy = 100^2 A + 100(D - A - C) + C
A = ac
B = (a+b)(c+d)
C = bd

Let’s put some numbers into the previous expressions:

xy = 100^2 * A + 100 * (D - A - C) + C
A = ac = 56 * 12 = 672
C = bd = 78 * 34 = 2652
D = (a+b)(c+d) = (56 + 78)(12 + 34) = 134 * 46 = 6164

xy = 100^2 * 672 + 100 * (6164 - 672 - 2652) + 2652 
   = 6720000 + 284000 + 2652
   = 7006652

Yes! the result of 1234 * 5678 = 7006652! 🙂

In the next section, we’ll see the pseudo code for the Karatsuba Algorithm and we’re going to translate it into Python code.

Python code for the Karatsuba Algorithm

In general though, we don’t have 4-digit numbers but n-digit numbers. In that case, the decomposition to be made is:

x = n-digit number
m = n/2 if n is even
m = (n+1)/2 if n is odd

a = 10^m * x1 + x2
--> x1 = First (n-m) digits of x
--> x2 = Last m digits of x

which is slightly different if n is even or odd.

In pseudocode, the Karatsuba Algorithm is:

procedure karatsuba(x, y)
  /* Base Case */
  if (x < 10) or (y < 10)
    return x*y
  /* calculates the number of digits of the numbers */
  m = max(size_base10(x), size_base10(y))
  m2 = m/2
  /* split the digit sequences about the middle */
  a, b = split_at(x, m2)
  c, d = split_at(y, m2)
  /* 3 products of numbers with half the size */
  A = karatsuba(a, c)
  C = karatsuba(b, d)
  D = karatsuba(a+b, c+d)
  return A*10^(2*m2) + (D-A-C)*10^(m2) + C

And the order of this algorithm Ο(nlog23) ≈ Ο(n1.585) is (more info).

Let’s write now the Python code 🙂

def karatsuba(x, y):
    # Base case
    if x < 10 or y < 10:
        return x * y
    # Calculate the number of digits of the numbers
    sx, sy = str(x), str(y)
    m2 = max(len(sx), len(sy)) / 2
    # Split the digit sequences about the middle
    ix, iy = len(sx) - m2, len(sy) - m2
    a, b = int(sx[:ix]), int(sx[ix:])
    c, d = int(sy[:iy]), int(sy[iy:])
    # 3 products of numbers with half the size
    A = karatsuba(a, c)
    C = karatsuba(b, d)
    D = karatsuba(a + b, c + d)
    return A * 10**(2 * m2) + (D - A - C) * 10**m2 + C

assert(karatsuba(1234, 5678) == 7006652)

Which is much simpler than the third-grade algorithm right?

Moreover, if we can compare the number of calculations of this algorithm with respect to the third-grade one:

Karatsuba vs 3rd grade algorithms

where the red line is the Karatsuba algorithm, and the blue lines the 3rd grade one (see above).

Finally, I want to write here one of the quotes mentioned in the Algorithms course, which might encourage you to find a better solution 🙂

Perhaps the most important principle of the good algorithm designer is to refuse to be content.Aho, Hopcroft and Ullman, The Design and Analysis of computer algorithms, 1974
Marina Melé
Marina Mele

Marina Mele has experience in artificial intelligence implementation and has led tech teams for over a decade. On her personal blog (marinamele.com), she writes about personal growth, family values, AI, and other topics she’s passionate about. Marina also publishes a weekly AI newsletter featuring the latest advancements and innovations in the field (marinamele.substack.com)

Categories

  • Personal Growth and Development
  • Artificial Intelligence
  • Mindful Parenting and Family Life
  • Productivity and Time Management
  • Mindfulness and Wellness
  • Values and Life Lessons
  • Posts en català
  • Other things to learn

Recent Posts

  • Understanding Frustration in Children
  • What is ChatGPT and how it compares to Bard and Claude
  • BlueSky Social – A Sneak Peek at the Future of Social Media
  • The Incredible Journey of AI Image Generation
  • AI and Fundamental Rights: How the AI Act Aims to Protect Individuals

RSS

  • Entries RSS
Follow @marina_mele
  • Cookie Policy
  • Privacy Policy
©2025 Marina Mele's site | Built using WordPress and Responsive Blogily theme by Superb
This website uses cookies to improve your experience. If you keep navigating through this website, we'll assume you're ok with this, but you can opt-out if you wish.Accept Read More
Privacy & Cookies Policy

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary
Always Enabled
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Non-necessary
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.
SAVE & ACCEPT