MATLAB是否执行尾调用优化?

时间:2011-03-16 14:31:21

标签: matlab functional-programming tail-recursion tail-call-optimization

我最近学习了Haskell,并尝试在可能的情况下将纯函数式传递给我的其他代码。这一点的一个重要方面是将所有变量视为不可变的,即常量。为了做到这一点,许多将使用命令式循环实现的计算必须使用递归来执行,这通常由于为每个函数调用分配新的堆栈帧而导致存储器损失。在尾调用的特殊情况下(其中被调用函数的返回值立即返回给被调用者的调用者),然而,这种惩罚可以被称为尾调用优化的过程绕过(在一种方法中,这可以通过在正确设置堆栈后,基本上用jmp替换一个调用)。 MATLAB默认是执行TCO,还是有办法告诉它?

1 个答案:

答案 0 :(得分:11)

如果我定义一个简单的尾递归函数:

function tailtest(n)
  if n==0; feature memstats; return; end
  tailtest(n-1);
end

并调用它以便它会非常深入地进行处理:

set(0,'RecursionLimit',10000);
tailtest(1000);

然后它看起来不像堆栈帧占用了大量内存。但是,如果我让它更加深入:

set(0,'RecursionLimit',10000);
tailtest(5000);

然后(在我的机器上,今天)MATLAB简单崩溃:这个过程毫不客气地死了。

我不认为这与MATLAB做任何TCO一致;函数尾部调用自身的情况,只在一个地方,除了单个参数之外没有局部变量,就像任何人都希望的那样简单。

所以:不,看起来MATLAB根本没有做TCO,至少在默认情况下是这样。我(到目前为止)还没有找到可能启用它的选项。如果有的话,我会感到惊讶。

如果我们没有炸掉堆栈,递归费用是多少?请参阅我对Bill Cheatham的回答的评论:看起来时间开销是非常重要但不是疯狂。

......除非Bill Cheatham在我发表评论后删除了答案。好。因此,我对Fibonacci函数和一个简单的尾递归函数进行了简单的迭代实现,在两者中进行了基本相同的计算,并在fib(60)上对它们进行了计时。递归实现比迭代实现的运行时间长约2.5倍。当然,对于执行更多工作的函数而言,相对开销将小于每次迭代的一次加法和一次减法。

(我也同意delnan的观点:在Haskell中感觉很自然的高递归代码在MATLAB中通常可能是单一的。)