在 python class 中实现 karatsuba 递归函数,错误

Implementing karatsuba recursion function in python class, errors

之前我 post 就这个主题提出了一个问题,并且得到了很好的回答。 然而,关于 class 中的递归,我仍然有一些不明白的地方。在上面的链接问题中,如果我向递归子例程添加前缀 self.,我会得到与下面 class 输出中产生的完全相同的错误(此 post 中的第三个代码块).我明白为什么会这样; object.karatsuba() 仅将 self 作为其输入,但编码的方法还要求 2,因此出现错误。

请查看下面的代码,然后看看我对第三个代码块后的解决方案的直觉。

例如:我有一个 karatsuba 乘法的工作实现,它不想在 class 中工作。标准 class 房间乘法在 class 中工作得很好,但是...

这是 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

这是在第 39 行失败的 class 中的代码:

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

错误的 class 版本生成以下输出:

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

我最初的直觉是遵循最上面一段链接问题中概述的解决方案:

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()

这解决了位置参数错误,但我遇到了一个新问题:

---------------------------------------------------------------------------
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'

此时我卡住了。

当我输入这个问题时,我发现自己正在以不同的方式查看我的代码,即思考如何最好地清楚地解释我的问题, 思考 ValueError,我发现了问题。

我在先前链接的问题中遵循了 abarnert 提供的直觉是正确的。问题在于函数的其余部分如何需要递归子例程中的值;正如您从 ValueError 中看到的那样,传递的是递归子例程的内存位置,而不是子例程生成的值。然后解决方案很简单:将 ac.karatsuba() 修改为 ac = ac.karatsuba(), etc... 瞧!

我认为这个(以及之前链接的问题)对于那些试图理解如何在 python classes 中实现递归的人来说是一个很好的教程。

希望大家点个赞给我投个赞!

这是有效的 class 代码:

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