2017-10-09 65 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

謝謝亞倫,圖片上傳... –