1

I'm trying to understand the Karatsuba multiplication algorithm. I've written the following code:

def karatsuba_multiply(x, y):
    # split x and y
    len_x = len(str(x))
    len_y = len(str(y))
    if len_x == 1 or len_y == 1:
        return x*y

    n = max(len_x, len_y)
    n_half = 10**(n // 2)
    a = x // n_half
    b = x % n_half
    c = y // n_half
    d = y % n_half

    ac = karatsuba_multiply(a, c)
    bd = karatsuba_multiply(b, d)
    ad_plus_bc = karatsuba_multiply((a+b), (c+d)) - ac - bd

    return (10**n * ac) + (n_half * ad_plus_bc) + bd

This test case does not work:

print(karatsuba_multiply(1234, 5678)) ## returns 11686652, should be 7006652‬

But if I use the following code from this answer, the test case produces the correct answer:

def karat(x,y):
    if len(str(x)) == 1 or len(str(y)) == 1:
        return x*y
    else:
        m = max(len(str(x)),len(str(y)))
        m2 = m // 2

        a = x // 10**(m2)
        b = x % 10**(m2)
        c = y // 10**(m2)
        d = y % 10**(m2)

        z0 = karat(b,d)
        z1 = karat((a+b),(c+d))
        z2 = karat(a,c)

        return (z2 * 10**(2*m2)) + ((z1 - z2 - z0) * 10**(m2)) + (z0)

Both functions look like they're doing the same thing. Why doesn't mine work?

Shan S
  • 658
  • 5
  • 18

1 Answers1

1

It seems that in with kerat_multiply implementation you can't use the correct formula for the last return.

In the original kerat implementation the value m2 = m // 2 is multiplied by 2 in the last return (z2 * 10**(2*m2)) + ((z1 - z2 - z0) * 10**(m2)) + (z0) (2*m2)

So you i think you need either to add a new variable as below where n2 == n // 2 so that you can multiply it by 2 in the last return, or use the original implementation.

Hoping it helps :)

EDIT: This is explain by the fact that 2 * n // 2 is different from 2 * (n // 2)

n = max(len_x, len_y)
n_half = 10**(n // 2)
n2 = n // 2
a = x // n_half
b = x % n_half
c = y // n_half
d = y % n_half

ac = karatsuba_multiply(a, c)
bd = karatsuba_multiply(b, d)
ad_plus_bc = karatsuba_multiply((a + b), (c + d)) - ac - bd

return (10**(2 * n2) * ac) + (n_half * (ad_plus_bc)) + bd
PasNinii
  • 634
  • 8
  • 18
  • So, `2 * n // 2` isn't the same as `n`? – Shan S Jun 18 '20 at 12:42
  • 1
    But they are not doing the same `2 * n // 2` is different from `2 * (n // 2)` here the order is important For instance `2 * 1 // 2 = 1` but `2 * (1 // 2) = 0` – PasNinii Jun 18 '20 at 12:52
  • Tested this, realized the problem is that `n` is not the same as using `n // 2 * 2` because `//` is a flooring operation. If `n` is 3, `n // 2 * 2` is 2, so it has to be floored first. – Shan S Jun 18 '20 at 12:54
  • Nice :) hope it helped – PasNinii Jun 18 '20 at 12:57