2011-03-17 85 views
7

退房这个斯卡拉代码:这个尾巴为什么递归?

def rec(n: Int) { 
    if (n > 1) { 
    val d = n/2 
    rec(d) 
// if (d > 1) // abort loop 
     rec(n/d) 
    } 
} 

该代码将导致死循环。由于尾递归优化,我没有得到一个StackOverflowError。

用JAD反编译,我得到这个Java的代码:

public void rec(int n) 
{ 
    int d; 
    for(; n > 1; n /= d) 
    { 
     int i = n; 
     d = i/2; 
     rec(d); 
    } 
} 

在循环的方法调用本身,因此我不明白的尾调用位置的最后一行。任何人都可以解释这一点?

+0

这将是有益的1.http://www.cs.wayne.edu/~artem/main/teaching/csc3200ss2006/slides/recursion/types.html 2.http://stackoverflow.com/questions/ 105834 /做最JVM-防止尾叩优化 – 2011-03-17 09:43:03

回答

9

rec(d)的情况下没有尾部呼叫。对于rec(N)(其中N > 1)堆栈在log2(N)调用后不再生长(因为此后n永远等于2或3,且d为1)。之后,它只是无限循环,每次立即返回内部rec(1)调用。这就是为什么没有堆栈溢出。

3

在您的方法的递归形式中,您有两个递归调用。 StackOverflowError是由最后一个造成的。

由于尾递归优化,最后一次调用变为循环(而第一次调用保持递归),因此你有无限循环而不是无限递归,并且StackOverflowError不会发生。