我如何通过递归限制?

时间:2015-01-07 00:39:48

标签: javascript recursion runtime-error

我有一个简单的程序,用JavaScript定义Ackermann函数:

function ack(m,n,p){
    if(p==0) return m+n;
    if(n==0&&p==1) return 0;
    if(n==0&&p==2) return 1;
    if(n==0&&p>2) return m;
    return ack(m,ack(m,n-1,p),p-1)
}

here定义,用于评估tetration和更高扩展名。这适用于添加整数,如:

ack(m,n,0);

乘:

ack(m,n,1);

Expontiation:

ack(m,n,2);

并且,Tetration:

ack(m,n,3);

此尝试因值m, n > 2而失败,抛出:InternalError: too much recursion。我知道这通常发生在非终止递归函数(如var inf_rec = x => inf_rec(x)),但此函数确实终止。

问题

有没有办法绕过InternalError?

修改

我应该怎么做,因为我显然需要更深的细胞堆叠?

3 个答案:

答案 0 :(得分:2)

否这取决于为每个浏览器设置的最大堆栈大小。有一个链接here,其中包含每个浏览器的所有相关堆栈最大大小的答案,以及在该特定浏览器中查看堆栈的方法。

答案 1 :(得分:2)

我以非递归方式重写了您自己的实现,现在它已经完成了ack(2, 3, 3);,这是65536,但它似乎永远不会达到{{1}之类的计算结束}。我没有得到任何堆栈溢出错误,即使等待至少5分钟计算结束......这看起来很可疑。

以下是实施:



ack(3, 3, 3);

var logEl = document.getElementById('log');


log('ack(1, 2, 0)', ack(1, 2, 0));
log('ack(8, 2, 1)', ack(8, 2, 1));
log('ack(4, 2, 2)', ack(4, 2, 2));
log('ack(2, 3, 3)', ack(2, 3, 3));

//ack(3, 3, 3) never seem to end, but I did not get a stack overflow error...

function ack(m, n, p) {
    var callStack = [[m, n, p]],
        valueStack = [],
        item;
    
    while (item = callStack.pop()) {
        m = item[0];
        n = item[1] !== null? item[1] : valueStack.pop();
        p = item[2];
        
        if (p === 0) { valueStack.push(m+n); continue; }
        if (n === 0 && p === 1) { valueStack.push(0); continue; }
        if (n === 0 && p === 2) { valueStack.push(1); continue; }
        if (n === 0 && p > 2) { valueStack.push(m); continue; }
        
        callStack.push([m, null, p - 1]);
        callStack.push([m, n - 1, p]);
        
    }
    
    return valueStack.pop();
}

function log(exp, val) {
    var li = document.createElement('li');
  
    li.textContent = exp + ' -> ' + val + '\n';
    logEl.appendChild(li);
}




答案 2 :(得分:0)

该错误与非终止与终止调用堆栈无关。相反,它与调用堆栈的深度有关。根据浏览器的实现,可以递归地进行多少函数调用是有限制的。绕过此问题的唯一方法是确保您的调用堆栈永远不会达到该限制。