[英]Is tail call optimization applicable to this function?
如果bar如果i是偶数,则调用bar(i / 2),否则,如果bar(3 * i + 1)调用bar,则递归函数bar将进行尾递归。
const int bar(const int i)
{
if (i < 2) return i;
return i % 2 ? bar(i/2) : bar(3*i + 1);
}
但是,如果bar调用bar或foo,而后者具有与bar完全不同的局部变量集,该怎么办?
const int bar(const int i)
{
if (i < 2) return i;
return i % 2 ? bar(i/2) : foo(3*i + 1);
// where foo is very complicated recursive call that has
// 11 different user-defined/primitive type of
// local variables that can't be optimized out
}
我的理解是尾部递归优化将使用调用方的堆栈。 在调用被调用方之前,调用方已经使用其局部变量完成了操作。 因此,被调用者可以重用它。 当调用方和被调用方具有相同的功能时,我的理解听起来不错(例如foo调用foo,bar调用bar)。 但是,如果堆栈大小和布局完全不同,并且被调用方可能是具有不同堆栈布局的多个不同功能之一,那么会发生什么?
首先,是尾递归吗? (现在,我知道可以对尾部“调用”进行优化,但不是尾部“递归”。)其次,诸如gcc,clang等主要编译器会优化这种尾部调用吗? (答案似乎是。)
如果被调用者(第二个代码示例中的foo)复杂得多怎么办? 如果被叫方和主叫方互相调用(相互递归),那么在我的第二个代码示例中,该调用是否会优化尾部调用? 如果被调用方(例如foo)是一个复杂的递归调用,它绝对不是尾部递归,并且对于编译器来说很难将其缩减为一个循环左右,那么它是否仍会进行尾部调用优化?
术语“尾递归”是呼叫站点的本地属性。 完全不受同一方法中其他调用的影响。
粗略地讲,如果在返回和封闭方法之间无需执行任何可执行代码,则该调用为尾部递归。
因此,示例中对bar()
所有调用都是尾递归的。
但是请注意,如果您说
return i % 2 ? bar(i/2) : 1 + bar(3*i + 1);
那么第一个调用是尾递归调用,但是第二个调用不是因为加法1 +
必须在返回后执行。
尾递归优化是否适用于此功能?
是的,尾递归优化适用于您的示例。 请查看汇编器https://godbolt.org/g/cSpUZw以获取第二个示例。 应用了更渐进的优化。 递归被循环替换。
bar(int):
cmp edi, 1
jg .L12
jmp .L6
.L15:
sar edi
cmp edi, 1
je .L14
.L12:
test dil, 1
jne .L15
lea edi, [rdi+1+rdi*2]
jmp foo(int)
.L14:
mov eax, 1
ret
.L6:
mov eax, edi
ret
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.