假设我们要计算一些斐波那契数,以 997 为模。
对于 n=500
在 C++ 中我们可以运行
#include <iostream>
#include <array>
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() {
std::cout << fib(500)[0];
}
在 Python 中
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__':
print(fib(500)[0])
两者都会毫无问题地找到答案 996。我们采用模数来保持输出大小合理,并使用对来避免指数分支。
对于 n=5000
,C++ 代码输出 783,但 Python 会报错
RecursionError: maximum recursion depth exceeded in comparison
如果我们添加几行
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(5000)
print(fib(5000)[0])
那么 Python 也会给出正确的答案。
对于 n=50000
C++ 在 Python 崩溃时(至少在我的机器上)在几毫秒内找到答案 151。
为什么 C++ 中的递归调用要便宜得多?我们能否以某种方式修改 Python 编译器以使其更容易接受递归?
当然,一种解决方案是用迭代代替递归。对于斐波那契数,这很容易做到。然而,这将交换初始条件和终止条件,而后者对于许多问题(例如 alpha-beta 剪枝)来说是棘手的。所以一般来说,这需要程序员付出大量的努力。
原文由 jtallk 发布,翻译遵循 CC BY-SA 4.0 许可协议
一个解决方案是一个蹦床:递归函数,而不是调用另一个函数,返回一个函数,该函数使用适当的参数进行调用。有一个更高一级的循环,它在一个循环中调用所有这些函数,直到我们得到最终结果。我可能没有很好地解释它;你可以在网上找到做得更好的资源。
关键是这将递归转换为迭代。我不认为这会更快,甚至可能更慢,但递归深度仍然很低。
实现可能如下所示。为了清楚起见,我将
x
拆分为a
和b
。然后,我将递归函数转换为跟踪a
和b
作为参数的版本,使其成为尾递归。