2017-10-09 61 views
0

我试图得到一个特定的收敛系列函数在JavaScript中摸索出超出错误:最大调用堆栈尺寸上汇聚一系列功能

function cnvg(sum,marker){ 
    if((marker--||1000)>=0){ 
    return cnvg(sum=(sum||0) + 1/Math.pow(-3,marker)/(2*marker+1), marker) 
    } else { 
    return sum; 
    } 
} 

我期待cnvg()回来与Math.PI/Math.sqrt(12)相当于(请参阅下面的图片),但我一直得到“最大调用堆栈大小超出”错误。我认为这可能是迭代的次数,所以我放弃1000参考100,然后10,最后到1,但我似乎仍然收到错误。

enter image description here

从理论上讲,一旦倒计数至0,并执行最后的循环,应立即停止,并返回sum价值,但是这似乎并没有这样的情况?谁能告诉我我做错了什么?

在此先感谢。

回答

1

默认参数

在叶奥尔德次

,我们写默认参数是这样

function add (x, y) { 
    if (x === undefined) x = 0 
    if (y === undefined) y = 0 
    return x + y 
} 
现在ES2015

,后来,我们就可以像这样写出来

function add (x = 0, y = 0) { 
    return x + y 
} 

让事情变得简单

递归过程可以简单地写为

const converge = (k = 0) => 
 
    k < 0 
 
    ? 0 
 
    : converge (k - 1) + (Math.pow (-3, -k)/(2 * k + 1)) 
 

 
console.log (converge (1000))   // 0.9068996821171091 
 
console.log (Math.PI/Math.sqrt (12)) // 0.9068996821171089

当然

,它可以帮助可读性,如果你抽象sigma第一

const sigma = f => k => 
 
    k < 0 
 
    ? 0 
 
    : f (k) + sigma (f) (k - 1) 
 

 
// hey, this looks just like the formula you posted 
 
const converge = 
 
    sigma (k => Math.pow (-3, -k)/(2 * k + 1)) 
 

 
console.log (converge (1000))   // 0.9068996821171091 
 
console.log (Math.PI/Math.sqrt (12)) // 0.9068996821171089


堆栈安全

我想指出的是,栈是从来没有超过四溢的危险 - 它会采取大约10,000 k - 值产生溢出

console.log (converge (1e4)) // RangeError: Maximum call stack size exceeded 

在这种情况下,这并不重要,因为即使是一个微小的k - 10的值已经计算出小数点后六位;一个k - 值100计算14位小数

但不管怎样,也许你有一些库,可以让计算更精确小数和你想convergestack safe ...

const recur = (...args) => 
 
    ({ type: recur, args }) 
 
    
 
const loop = f => 
 
    { 
 
    let acc = f() 
 
    while (acc && acc.type === recur) 
 
     acc = f (...acc.args) 
 
    return acc 
 
    } 
 

 
// now stack-safe 
 
const sigma = f => n => 
 
    loop ((acc = 0, k = n) => 
 
    k < 0 
 
     ? acc 
 
     : recur (acc + f (k), k - 1)) 
 

 
const converge = 
 
    sigma (k => Math.pow (-3, -k)/(2 * k + 1)) 
 

 
console.log (converge (1e4))   // 0.9068996821171089 << super precise !! 
 
console.log (Math.PI/Math.sqrt (12)) // 0.9068996821171089

5

永远不会在cnvg()中分配,导致无限递归。您的意思是:

function cnvg(sum, marker) { 
    marker = (typeof(marker) === 'undefined') ? 1000 : marker; 
    if (marker-- >= 0) { 
    return cnvg(sum=(sum||0) + 1/Math.pow(-3,marker)/(2*marker+1), marker) 
    } else { 
    return sum; 
    } 
} 

但是这给了我3 + Math.PI/Math.sqrt(12)...(3.9068996821171087)

marker--进行减法检查后,导致与marker = -1附加的词。使用--marker> 0,或更清楚:

marker = (typeof(marker) === 'undefined') ? 1000 : marker - 1; 
if (marker >= 0) { 
    // ... 
+0

'marker - '在问题的代码中不会减少'marker'? – naomik

+0

这是密切的...但这是给我'3 + Math.PI/Math.sqrt(12)'...(3.9068996821171087) –

+0

谢谢亚伦,图片上传... –