【发布时间】:2016-04-20 07:14:16
【问题描述】:
我编写了这个简单的程序来测试memoization 技术:
int main() {
function<double(double)> f = [&f](double i) -> double {
if (i == 1)
return 1;
else
return i * f(i - 1);
};
cout << f(100) << endl;
}
我希望在几秒钟内执行这段代码(因为它的递归效率低下),但实际上只花了几毫秒......为什么?我认为引擎盖下有一些编译器优化,但我不明白会发生什么。
额外问题: 您能否给我一个执行效率低下的简单程序(编译器优化与否),以便我测试记忆化的好处?
【问题讨论】:
-
几秒钟计算 100 次乘法?你是在算盘上运行这个吗?
-
这可能是尾递归优化的情况,也可能是其他情况(就像没有那么多调用,真的)。唯一确定的方法是查看生成的汇编代码。
-
您的输入数字太小,无法显示递归实现的缺点。它仍然只计算 100 次乘法——不断增加的堆栈大小还不是问题。尝试使用 10000 或更大来记录问题。奖励问题的答案:尝试斐波那契序列:
f(i) := f(i-1) + f(i-2)和两个基本情况f(0) := 1; f(1) := 1由于它不止一次递归地调用f,因此您的堆栈增长速度快于使用i时的线性增长。 -
只是一个提示 - 尝试使用递归方法计算斐波那契(或将结果乘以
f(i - 2)) -
澄清一下:lambda 中的
f(i - 1)不是直接递归调用(如果您认为function与 lambda 不是同一个对象,那就不足为奇了)。它调用f的operator()(double),后者又调用f包装的lambda 对象的operator()(double)(等等)。在所有语法糖的背后隐藏着很多间接性,编译器可能无法将其全部解开。
标签: c++ recursion memoization