簡體   English   中英

Karatsuba RecursionError:調用Python對象時超出了最大遞歸深度

[英]Karatsuba RecursionError: maximum recursion depth exceeded while calling a Python object

我正在嘗試在Python上實現Karatsuba乘法。 輸入是長度為2的兩個整數。它們的長度相同。

def mult(x,y):
    if int(x) < 10 and int(y) <10:
        return int(x)*int(y)
    x_length = len(str(x))//2
    y_length = len(str(y))//2

    a = str(x)[:x_length]
    b = str(x)[x_length:]
    c = str(y)[:y_length]
    d = str(y)[y_length:]

    n = len(a) + len(b)
    m = n//2

    return 10**n* mult(a,c) + 10**m*(mult(a+b, c+d)-mult(a,c)-mult(b,d)) + mult(b,d)

運行mult(1234,5678)這將產生以下錯誤:

if int(x) < 10 and int(y) <10:
RecursionError: maximum recursion depth exceeded while calling a Python object

但是如果我這樣做

def mult(x,y):
    if int(x) < 10 and int(y) <10:
        return int(x)*int(y)
    x_length = len(str(x))//2
    y_length = len(str(y))//2

    a = str(x)[:x_length]
    b = str(x)[x_length:]
    c = str(y)[:y_length]
    d = str(y)[y_length:]

    n = len(a) + len(b)
    m = n//2

    return 10**n* mult(a,c) + 10**m*(mult(a,d)+mult(b,c)) + mult(b,d)

所以我在最后一行執行4次遞歸(即mult(a,c), mult(a,d), mult(b,c), mult(b,d) ),而不是上面的3次遞歸(即mult(a,c), mult(a+b, c+d), mult(b,d) )。

事實證明還可以。

為什么會這樣呢? 而且只有3個遞歸怎么辦?

a, b, c, d是字符串。 字符串加法是串聯。 "1" + "2""12" 因此,傳遞給mult(a+b, c+d)的不是您打算傳遞的。


TL; DR。

首先,遞歸應該很快終止。 讓我們看看為什么不這樣。 mult的開頭添加print x, y

def mult(x, y):
    print x, y
    ....

並將輸出重定向到文件中。 結果令人驚訝:

1234 5678
12 56
1 5
12 56
1 5
12 56
1 5
12 56
1 5
....

難怪堆棧溢出。 問題是,為什么我們重復12 56例? 讓我們添加更多工具,以找出哪個遞歸調用可以做到:

def mult(x,y,k=-1):
    ....
    print a, b, c, d
    ac = mult(a, c, 0)
    bd = mult(b, d, 2)
    return 10**n* ac + 10**m*(mult(a+b, c+d, 1) - ac - bd) + bd

結果是

-1 :  1234 5678
12 34 56 78
0 :  12 56
1 2 5 6 
0 :  1 5
2 :  2 6
1 :  12 56
1 2 5 6 
0 :  1 5
2 :  2 6
1 :  12 56
1 2 5 6 
0 :  1 5
2 :  2 6
1 :  12 56

您可以看到標記為1的遞歸調用總是得到12 56 它是計算mult(a + b, c + d)的調用。 那好吧。 它們a, b, c, d都是字符串。 "1" + "2""12" 不完全是您的意思。

因此,請確定:參數是整數還是字符串,並相應地對待它們。

請注意,在您的第一個代碼段中,您不是三次調用函數,而是調用5次:

return 10**n* mult(a,c) + 10**m*(mult(a+b, c+d)-mult(a,c)-mult(b,d)) + mult(b,d)

對於其余的代碼,我還不能說清楚,但是快速瀏覽一下Karatsuba上的Wikipedia條目,您可以通過增加所使用的基數(即從10到100或1000)來減少遞歸深度。 您可以使用sys.setrecursionlimit更改遞歸深度,但是python堆棧框架可能會變得很大,因此請避免這樣做,因為這樣做可能很危險。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM