收敛系列函数

时间:2017-10-09 03:35:53

标签: javascript math recursion

我正在尝试在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

理论上,一旦marker倒数到0并执行最后一个循环,它应该停止并返回sum的值,但这似乎不是这样的......任何人都可以告诉我我做错了什么?

提前致谢。

2 个答案:

答案 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;
&#13;
&#13;

当然,如果先抽象sigma

,它有助于提高可读性

&#13;
&#13;
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;
&#13;
&#13;

堆栈安全性

我想指出堆栈永远不会出现溢出危险 - 它需要k - 大约10,000的值才会导致溢出

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

在这种情况下,它并不重要,因为即使很小的k - 值10也已经计算出第六个小数位; k - 值为100计算14位小数

但无论如何,也许你有一些库可以让你更精确地计算小数,你想让converge stack safe ......

&#13;
&#13;
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;
&#13;
&#13;