简体   繁体   中英

Implementing karatsuba recursion function in python class, errors

Previously I posted a question on this subject and it was answered quite well. Implementing merge sort function in python class, errors And yet there is still something that escapes me about recursion in a class. In the linked problem above, if I added prefixive self. to the recursion subroutine, I get the exact same error that is produced below in the class output (third block of code in this post). I understand why this happens; object.karatsuba() only takes self as its input, and yet the method as is coded asks for 2 besides, hence the error.

Please, review the below code and then see my intuition as to a solution after the 3rd code block.

For example: I have a working implementation of karatsuba multiplication that doesn't want to work in a class. Standard classroom multiplication works just fine in a class, but...

This is the working code outside of a class:

def zeroPad(numberString, zeros, left = True):
    """Return the string with zeros added to the left or right."""
    for i in range(zeros):
        if left:
            numberString = '0' + numberString
        else:
            numberString = numberString + '0'
    return numberString

def karatsubaMultiplication(x ,y):
    """Multiply two integers using Karatsuba's algorithm."""
    #convert to strings for easy access to digits
    x = str(x)
    y = str(y)
    #base case for recursion
    if len(x) == 1 and len(y) == 1:
        return int(x) * int(y)
    if len(x) < len(y):
        x = zeroPad(x, len(y) - len(x))
    elif len(y) < len(x):
        y = zeroPad(y, len(x) - len(y))
    n = len(x)
    j = n//2
    #for odd digit integers
    if (n % 2) != 0:
        j += 1    
    BZeroPadding = n - j
    AZeroPadding = BZeroPadding * 2
    a = int(x[:j])
    b = int(x[j:])
    c = int(y[:j])
    d = int(y[j:])
    #recursively calculate
    ac = karatsubaMultiplication(a, c)
    bd = karatsubaMultiplication(b, d)
    k = karatsubaMultiplication(a + b, c + d)
    A = int(zeroPad(str(ac), AZeroPadding, False))
    B = int(zeroPad(str(k - ac - bd), BZeroPadding, False))
    return A + B + bd

And this is the code inside a class that fails on line 39:

class Karatsuba(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def zeroPad(self, numberString, zeros, left = True):
        """Return the string with zeros added to the left or right."""
        for i in range(zeros):
            if left:
                numberString = '0' + numberString
            else:
                numberString = numberString + '0'
        return numberString

    def karatsuba(self):
        """Multiply two integers using Karatsuba's algorithm."""
        #convert to strings for easy access to digits
        self.x = str(self.x)
        self.y = str(self.y)
        #base case for recursion
        if len(self.x) == 1 and len(self.y) == 1:
            return int(self.x) * int(self.y)
        if len(self.x) < len(self.y):
            self.x = self.zeroPad(self.x, len(self.y) - len(self.x))
        elif len(self.y) < len(self.x):
            self.y = self.zeroPad(self.y, len(self.x) - len(self.y))
        n = len(self.x)
        j = n//2
        #for odd digit integers
        if (n % 2) != 0:
            j += 1    
        BZeroPadding = n - j
        AZeroPadding = BZeroPadding * 2
        a = int(self.x[:j])
        b = int(self.x[j:])
        c = int(self.y[:j])
        d = int(self.y[j:])
        #recursively calculate
        ac = self.karatsuba(a, c)
        bd = self.karatsuba(b, d)
        k = self.karatsuba(a + b, c + d)
        A = int(self.zeroPad(str(ac), AZeroPadding, False))
        B = int(self.zeroPad(str(k - ac - bd), BZeroPadding, False))
        return A + B + bd

The faulty class version generates the following output:

x = 234523546643636
y = 325352354534656

x = Karatsuba(x,y)
x.karatsuba()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-aa1c267478ee> in <module>()
      4 x = Karatsuba(x,y)
      5 
----> 6 x.karatsuba()

<ipython-input-1-1d1e9825dcc5> in karatsuba(self)
     37         d = int(self.y[j:])
     38         #recursively calculate
---> 39         ac = self.karatsuba(a, c)
     40         bd = self.karatsuba(b, d)
     41         k = self.karatsuba(a + b, c + d)

TypeError: karatsuba() takes 1 positional argument but 3 were given

My initial intuition was to follow the solution outlined in the top paragraph linked question as such:

class Karatsuba(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def zeroPad(self, numberString, zeros, left = True):
        """Return the string with zeros added to the left or right."""
        for i in range(zeros):
            if left:
                numberString = '0' + numberString
            else:
                numberString = numberString + '0'
        return numberString

    def karatsuba(self):
        """Multiply two integers using Karatsuba's algorithm."""
        #convert to strings for easy access to digits
        self.x = str(self.x)
        self.y = str(self.y)
        #base case for recursion
        if len(self.x) == 1 and len(self.y) == 1:
            return int(self.x) * int(self.y)
        if len(self.x) < len(self.y):
            self.x = self.zeroPad(self.x, len(self.y) - len(self.x))
        elif len(self.y) < len(self.x):
            self.y = self.zeroPad(self.y, len(self.x) - len(self.y))
        n = len(self.x)
        j = n//2
        #for odd digit integers
        if (n % 2) != 0:
            j += 1    
        BZeroPadding = n - j
        AZeroPadding = BZeroPadding * 2
        self.a = int(self.x[:j])
        self.b = int(self.x[j:])
        self.c = int(self.y[:j])
        self.d = int(self.y[j:])
        #recursively calculate
#         ac = self.karatsuba(self.a, self.c)
#         bd = self.karatsuba(self.b, self.d)
        ac = Karatsuba(self.a, self.c)
        ac.karatsuba()
        bd = Karatsuba(self.b, self.d)
        bd.karatsuba()
        k = Karatsuba(self.a + self.b, self.c + self.d)
        k.karatsuba()
#         k = self.karatsuba(self.a + self.b, self.c + self.d)

        A = int(self.zeroPad(str(ac), AZeroPadding, False))
        B = int(self.zeroPad(str(k - ac - bd), BZeroPadding, False))
        return A + B + bd

x = 234523546643636
y = 325352354534656

x = Karatsuba(x,y)
x.karatsuba()

This gets past the positional argument error, but then I have a new problem:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-34-a862504dede9> in <module>()
     59 
     60 x = Karatsuba(x,y)
---> 61 x.karatsuba()

<ipython-input-34-a862504dede9> in karatsuba(self)
     44 #         bd = self.karatsuba(self.b, self.d)
     45         ac = Karatsuba(self.a, self.c)
---> 46         ac.karatsuba()
     47         bd = Karatsuba(self.b, self.d)
     48         bd.karatsuba()

<ipython-input-34-a862504dede9> in karatsuba(self)
     44 #         bd = self.karatsuba(self.b, self.d)
     45         ac = Karatsuba(self.a, self.c)
---> 46         ac.karatsuba()
     47         bd = Karatsuba(self.b, self.d)
     48         bd.karatsuba()

<ipython-input-34-a862504dede9> in karatsuba(self)
     44 #         bd = self.karatsuba(self.b, self.d)
     45         ac = Karatsuba(self.a, self.c)
---> 46         ac.karatsuba()
     47         bd = Karatsuba(self.b, self.d)
     48         bd.karatsuba()

<ipython-input-34-a862504dede9> in karatsuba(self)
     51 #         k = self.karatsuba(self.a + self.b, self.c + self.d)
     52 
---> 53         A = int(self.zeroPad(str(ac), AZeroPadding, False))
     54         B = int(self.zeroPad(str(k - ac - bd), BZeroPadding, False))
     55         return A + B + bd

ValueError: invalid literal for int() with base 10: '<__main__.Karatsuba object at 0x108142ba8>00'

At this point I am stuck.

As I was typing up this question, I found myself looking over my code in a different way, ie thinking about how best to explain my problem clearly, and thinking about the ValueError , and I discovered the problem.

I was correct to follow the intuition provided by abarnert in the previously linked question. The problem was in how the rest of the function needed the values from the recursion subroutines; as you can see from the ValueError, the memory location of the recursion subroutine was being passed along instead of the value generated by the subroutine. The solution then was straightforward: Modify ac.karatsuba() to ac = ac.karatsuba(), etc... and voila!

I think this (and the previously linked problem) serves as a good tutorial for those trying to understand how to implement recursion in python classes.

I hope you agree and give me good votes!

Here is the working class code:

class Karatsuba(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def zeroPad(self, numberString, zeros, left = True):
        """Return the string with zeros added to the left or right."""
        for i in range(zeros):
            if left:
                numberString = '0' + numberString
            else:
                numberString = numberString + '0'
        return numberString

    def karatsuba(self):
        """Multiply two integers using Karatsuba's algorithm."""
        #convert to strings for easy access to digits
        self.x = str(self.x)
        self.y = str(self.y)
        #base case for recursion
        if len(self.x) == 1 and len(self.y) == 1:
            return int(self.x) * int(self.y)
        if len(self.x) < len(self.y):
            self.x = self.zeroPad(self.x, len(self.y) - len(self.x))
        elif len(self.y) < len(self.x):
            self.y = self.zeroPad(self.y, len(self.x) - len(self.y))
        n = len(self.x)
        j = n//2
        #for odd digit integers
        if (n % 2) != 0:
            j += 1    
        BZeroPadding = n - j
        AZeroPadding = BZeroPadding * 2
        self.a = int(self.x[:j])
        self.b = int(self.x[j:])
        self.c = int(self.y[:j])
        self.d = int(self.y[j:])
        #recursively calculate
#         ac = self.karatsuba(self.a, self.c)
#         bd = self.karatsuba(self.b, self.d)
        ac = Karatsuba(self.a, self.c)
        ac = ac.karatsuba()
        bd = Karatsuba(self.b, self.d)
        bd = bd.karatsuba()
        k = Karatsuba(self.a + self.b, self.c + self.d)
        k = k.karatsuba()
#         k = self.karatsuba(self.a + self.b, self.c + self.d)

        A = int(self.zeroPad(str(ac), AZeroPadding, False))
        B = int(self.zeroPad(str(k - ac - bd), BZeroPadding, False))
        return A + B + bd

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM