0

I am doing the Stanford's Algorithms MOOC and got stuck with Karatsuba multiplication algorithm programming assignment.
Karatsuba multiplication is simply an algorithm for multiplication of two integer that is asymptotically faster than usual multiplication.

RESTRICTIONS

  • I restricted myself to only use single-digit multiplication and padding numbers (adding zeros at the end, i.e. multiplying by 10 to some power), so there are 3 base cases
  • I also decided to convert the numbers into strings and take several numbers instead of dividing it by 10 to some power, but I tried the other way, it does not help
  • I also decided to generalise the algorithm, i.e. do not assume that number1 and number2 have similar length therefore I use both n1 and n2 (see the code)
  • Because of the point above, I also decided not to use the Gauss's trick

I know, the restrictions might see meaningless, but I used it as a programming exercise rather than some practical solution, hence I am mainly interesting in spotting my mistake rather than finding some "simpler solution".

Here is my code:

    def karatsuba(number1, number2):
        n1 = len(str(number1)) # number of digits in the first number
        n2 = len(str(number2)) # number of digits in the second number

        if n1 == 1 and n2 == 1: # base case number 1 - both numbers are single-digit
            kara = number1*number2
            return kara

        elif n1 == 1: # base case number 2 - only one number is single-digit
            c = int(str(number2)[:(n2//2)])
            d = int(str(number2)[(n2//2):])
            kara = 10**((n2+1)//2)*c*number2 + d*number2
            return kara

        elif n2 == 1: # base case number 3 - only one number is single digit
            a = int(str(number1)[:(n1//2)])
            b = int(str(number1)[(n1//2):])
            kara = 10**((n2+1)//2)*a*number2 + b*number2
            return kara

        elif n1 != 1 and n2 != 1: # loop
            a = int(str(number1)[:(n1 // 2)])
            b = int(str(number1)[(n1 // 2):])
            c = int(str(number2)[:(n2 // 2)])
            d = int(str(number2)[(n2 // 2):])
            z1 = karatsuba(a, c)
            z2 = karatsuba(a, d)
            z3 = karatsuba(b, c)
            z4 = karatsuba(b, d)
            kara = 10**((n1+1)//2+(n2+1)//2)*z1 + 10**((n1+1)//2)*z2 + 10**((n2+1)//2)*z3 + z4
            return kara
  • 1
    One immediate problem: `number1` does not participate in _base case number 2_ at all. – user58697 Jun 26 '20 at 22:05
  • user58697 thank you, I've fixed that, but the algorithm still don't work. When I try it with large enough numbers, a few first digits are correct, but in the middle there's mismatch. – ryabchenko-a Jun 27 '20 at 07:46
  • The code presented, the algorithm to implement has *nothing* to do with [Анато́лий Алексе́евич Карацу́ба(Karatsuba)'s multiplication algorithm](https://en.m.wikipedia.org/wiki/Karatsuba_algorithm) other that implementing the same operation. It is a divide-and-conquer implementation of "multi-word multiplication" - the complexity of divide-and-conquer without any gain as compared to *iterate over multiplicand* or *over multiplier* or *product*, to be explicit. (Then again, the title spells `Karotsuba`.) – greybeard Jun 27 '20 at 13:25
  • @greybeard, thank you for your comment. Yes, as I said in the post, I put some restrictions on code, so it is impossible to implement Karotsuba in its original form (i.e. do the Gauss's trick and don't compute a*d and b*c, but instead compute (a+b)(c+d) and substract z1 and z4 from it), because I "generalize" it to the way that it can deal with numbers such that number1 has less than half of number of digits of number2 or vice versa. I agree that it is not Karatsuba per se, but it's a divide-and-conquer algo of the same structure expect the Gauss's trick. Yes, it has no gain in complexity. – ryabchenko-a Jun 27 '20 at 14:40

2 Answers2

1

This is not a Karatzuba algorithm. The point of Karatzuba is to make only 3 recursive invocations; you do 4 of them. The recursive invocations, in your notation, should be

karatzuba(a, c)
karatzuba(b, d)
karatzuba(a + b, c + d)

Besides that, there is a problem with base case 2: number1 does not participate in it at all.

user58697
  • 7,808
  • 1
  • 14
  • 28
  • Thank you for the base case problem. I've fixed it, but it still does not work with large enough numbers. – ryabchenko-a Jun 27 '20 at 07:44
  • for example, with 3141592653589793238462643383279502884197169399375105820974944592 and 2718281828459045235360287471352662497757247093699959574966967627 the algorithm outputs 8539734222673567065463550869546645055581685977789053412178053379125352813007789759003309903096065770503301272120255716421814554 instead of 8539734222673567065463550869546574495034888535765114961879601127067743044893204848617875072216249073013374895871952806582723184 – ryabchenko-a Jun 27 '20 at 07:45
  • I am sorry, this actually solved the problem. I don't know why it did not work at first, but now it's okay – ryabchenko-a Jun 27 '20 at 14:45
1

These are some mistakes to be corrected if you haven't yet.

kara = 10**((n2+1)//2)*c*number1 + d*number1 #in base case 2 
kara = 10**((n1+1)//2)*a*number2 + b*number2 #in base case 3. your code has n2+1

Conventional Karatsuba has 3 recursions. but I can see why are you making 4 recursions. can't say which is faster though.

working code for the example you've given above in the comments

def karatsuba(number1, number2):
    n1 = len(str(number1)) # number of digits in the first number
    n2 = len(str(number2)) # number of digits in the second number

    if n1 == 1 and n2 == 1: # base case number 1 - both numbers are single-digit
        kara = number1*number2
        return kara

    elif n1 == 1: # base case number 2 - only one number is single-digit
        c = int(str(number2)[:(n2//2)])
        d = int(str(number2)[(n2//2):])
        kara = 10**((n2+1)//2)*c*number1 + d*number1 #a mistake here
        return kara

    elif n2 == 1: # base case number 3 - only one number is single digit
        a = int(str(number1)[:(n1//2)])
        b = int(str(number1)[(n1//2):])
        kara = 10**((n1+1)//2)*a*number2 + b*number2 #a mistake here
        return kara

    elif n1 != 1 and n2 != 1: # loop
        a = int(str(number1)[:(n1 // 2)])
        b = int(str(number1)[(n1 // 2):])
        c = int(str(number2)[:(n2 // 2)])
        d = int(str(number2)[(n2 // 2):])
        z1 = karatsuba(a, c) 
        z2 = karatsuba(a, d) 
        z3 = karatsuba(b, c)
        z4 = karatsuba(b, d) 
        kara = 10**((n1+1)//2+(n2+1)//2)*z1 + 10**((n1+1)//2)*z2 + 10**((n2+1)//2)*z3 + z4
        return kara
num1 = 3141592653589793238462643383279502884197169399375105820974944592
num2 = 2718281828459045235360287471352662497757247093699959574966967627
k_res = karatsuba(num1,num2)
ac_res = num1*num2
print(k_res)
print(ac_res)
assert k_res==ac_res
sudheer naidu
  • 164
  • 2
  • 10