我正在尝试在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
,但我似乎仍然收到错误
理论上,一旦marker
倒数到0并执行最后一个循环,它应该停止并返回sum
的值,但这似乎不是这样的......任何人都可以告诉我我做错了什么?
提前致谢。
答案 0 :(得分:5)
marker
中分配 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) {
// ...
答案 1 :(得分: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
&#13;
当然,如果先抽象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
&#13;
堆栈安全性
我想指出堆栈永远不会出现溢出危险 - 它需要k
- 大约10,000的值才会导致溢出
console.log (converge (1e4)) // RangeError: Maximum call stack size exceeded
在这种情况下,它并不重要,因为即使很小的k
- 值10也已经计算出第六个小数位; k
- 值为100计算14位小数
但无论如何,也许你有一些库可以让你更精确地计算小数,你想让converge
stack 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
&#13;