C++和Python中递归实现计算斐波那契数列,当n=500时,两者都能正常计算,例如,
#include <iostream>
#include <array>
using namespace std;
array<int, 2> fib(unsigned n) {
if (!n)
return {1, 1};
auto x = fib(n - 1);
return {(x[0] + x[1]) % 997, (x[0] + 2 * x[1]) % 997};
}
int main() {
cout << fib(500)[0];
}
但当n=5000
,C++能正常计算,Python会报错:RecursionError: maximum recursion depth exceeded in comparison
但可以通过增加sys.setrecursionlimit(6000)
,例如,
import sys
def fib(n):
if n==1:
return (1, 2)
x=fib(n-1)
return ((x[0]+x[1]) % 997, (x[0]+2*x[1]) % 997)
if __name__=='__main__':
sys.setrecursionlimit(6000)
print(fib(5000)[0])
然而,当n=50000
,Python在我机器上崩溃了,而C++几毫秒得出结果151 。对于斐波那契数列,解决方案是用迭代代替递归。但其它递归问题可能就不这么容易了。下面在看一下问题原因及解决办法。
问题原因:
Python 对递归函数调用的数量有内部限制。该限制是可配置的,但是,函数链太深会导致堆栈溢出。这种潜在的限制¹适用于 C++ 和 Python。此限制也适用于所有函数调用,而不仅仅是递归调用。潜在的限制是执行堆栈大小。默认大小因系统而异,不同的函数调用消耗不同的内存量,因此限制不是指定为调用次数,而是以字节为单位。这在某些系统上也是可配置的。由于便携性问题,通常不建议修改该限制。C++对递归调用深度没有限制,除了栈的大小。作为一种完全编译的语言,循环(包括递归)在 C++ 中比在 Python 中快得多。
解决方法:
将递归函数转换为一个可以跟踪a和b作为参数的版本,使其成为尾递归。
例如,
def fib_acc(n, a, b):
if n == 1:
return (a, b)
return lambda: fib_acc(n - 1, (a+b) % 997, (a+2*b) % 997)
def fib(n):
x = fib_acc(n, 1, 2)
while callable(x):
x = x()
return x
if __name__=='__main__':
print(fib(50000)[0])