![](/img/trans.png)
[英]Python RecursionError: maximum recursion depth exceeded while calling a Python object
[英]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.