计算负数的立方根

Der*_*會功夫 14 javascript math

所以,简而言之,

3 √(-8)=(-8)1/3

console.log(Math.pow(-8,1/3));
//Should be -2
Run Code Online (Sandbox Code Playgroud)

但是当我测试它时,它会输出

NaN
Run Code Online (Sandbox Code Playgroud)

为什么?这是一个错误还是预计会首先出现这种情况?我使用JavaScript绘制图形,但这会弄乱图形.

Ja͢*_*͢ck 17

您可以使用此代码段来计算它.这也适用于其他权力,例如1/4,1/5等等.

function nthroot(x, n) {
  try {
    var negate = n % 2 == 1 && x < 0;
    if(negate)
      x = -x;
    var possible = Math.pow(x, 1 / n);
    n = Math.pow(possible, n);
    if(Math.abs(x - n) < 1 && (x > 0 == n > 0))
      return negate ? -possible : possible;
  } catch(e){}
}

nthroot(-8, 3);
Run Code Online (Sandbox Code Playgroud)

资料来源:http://gotochriswest.com/blog/2011/05/06/cube-root-an-beyond/

仅计算立方根的更快方法:

Math.cbrt = function(x) {
    var sign = x === 0 ? 0 : x > 0 ? 1 : -1;

    return sign * Math.pow(Math.abs(x), 1 / 3);
}

Math.cbrt(-8);
Run Code Online (Sandbox Code Playgroud)

更新

要查找基于整数的立方根,您可以使用以下函数,灵感来自以下答案:

// positive-only cubic root approximation
function cbrt(n)
{
    var a = n; // note: this is a non optimized assumption

    while (a * a * a > n) {
        a = Math.floor((2 * a + (n / (a * a))) / 3);
    }

    return a;
}
Run Code Online (Sandbox Code Playgroud)

它开始与收敛到最接近的整数的假设a为此a^3 <= n.可以以相同的方式调整此功能以支持负底座.


Ray*_*oal 11

没有错误; 你把负数提高到一个分数幂; 因此,NaN.

谷歌的最高点来自Math博士,解释非常好.它表示对于实数(无论如何不是复数),提升到分数幂的负数可能不是实数.最简单的例子可能就是

-4 ^(1/2)

这基本上是计算-4的平方根.即使-8的立方根确实有真正的解决方案,我认为大多数软件库都发现不进行所有复杂算术更有效,只有当虚部非零时才返回NaN,否则会给你很好的答案.

编辑

只是为了清楚地表明NaN预期结果,请参阅官方ECMAScript 5.1规范,第15.8.2.13节.它说:

如果x <0且x是有限的且y是有限的并且y不是整数,则结果是NaN.

同样,即使将负数增加到分数幂的一些实例只有一个真正的根,但是对于所有负数到分数根的情况,许多语言都只做NaN.

请不要认为JavaScript是唯一这样的语言. C++做同样的事情:

如果x是有限负的并且y是有限的但不是整数值,则会导致域错误.

  • @RayToal:实际上坚持,不应该是正确的WA链接[this](http://www.wolframalpha.com/input/?i=%28-8%29+%5E+%281%2F3%29) ? (2认同)

Phi*_*l H 7

两个关键问题:

  1. 在数学上,有一个负数的立方根:-2,但也有2个复数根(见统一立方根).
  2. Javascript的Math对象(以及大多数其他标准数学库)不会对负数进行分数幂.它在函数接收之前将分数幂转换为浮点数,因此您要求函数计算负数的浮点幂,这可能有也可能没有真正的解.所以它做了务实的事情,并拒绝尝试计算这样的价值.

如果你想得到正确的答案,你需要决定你想要的数学校正,并将这些规则写入非标准的实现pow.

限制所有库函数以避免过多的计算时间和不必要的复杂性.


o.v*_*.v. 6

我喜欢其他的答案,但如果覆盖Math.pow如此,它将能够与负数的所有第n个根一起工作:

//keep the original method for proxying
Math.pow_ = Math.pow;

//redefine the method
Math.pow = function(_base, _exponent) {
  if (_base < 0) {
    if (Math.abs(_exponent) < 1) {
      //we're calculating nth root of _base, where n === 1/_exponent
      if (1 / _exponent % 2 === 0) {
        //nth root of a negative number is imaginary when n is even, we could return
        //a string like "123i" but this would completely mess up further computation
        return NaN;
      }/*else if (1 / _exponent % 2 !== 0)*/
      //nth root of a negative number when n is odd
      return -Math.pow_(Math.abs(_base), _exponent);
    }
  }/*else if (_base >=0)*/
  //run the original method, nothing will go wrong
  return Math.pow_(_base, _exponent);
};
Run Code Online (Sandbox Code Playgroud)

摆弄一些测试用例,如果发现错误就给我一个喊叫!