具有负数和非整数幂的 Math.pow

问题描述 投票:0回答:2

Math.pow
的ECMAScript规范有以下特殊规则:

  • 如果 x < 0 and x is finite and y is finite and y is not an integer, the result is NaN.

(http://es5.github.com/#x15.8.2.13)

结果

Math.pow(-8, 1 / 3)
给出
NaN
而不是
-2

这条规则的原因是什么?这个规则是否有某种更广泛的计算机科学或 IEEEish 原因,或者它只是 TC39/Eich 从前做出的选择?


更新

感谢 Amadan 与我的交流,我想我现在明白了其中的道理。为了后代,我想扩大我们的讨论。

让我们来看下面的例子:

Math.pow(823543, 1 / 7)
产生
6.999999999999999
尽管它确实应该是
7
。这是由于
1 / 7
必须首先转换为十进制表示形式
0.14285714285714285
而引入的不准确性,它被截断并失去精度。当我们处理正数时,这不是一个糟糕的问题,因为我们仍然得到非常接近真实结果的结果。

然而,一旦我们踏入负面世界,我们就会遇到问题。如果 JavaScript 引擎要尝试计算

Math.pow(-823543, 1 / 7)
,它首先需要将
1 / 7
转换为小数,所以它实际上是在计算
Math.pow(-823543, 0.14285714285714285)
,实际上 没有真正的答案。在这种情况下,它可能不得不返回
NaN
,因为它找不到实数,即使真正的答案应该是
-7
。此外,寻找接近实数的复数以做出“最佳猜测”可能涉及一定程度的复杂性,他们不希望在数学领域需要 JS 引擎。

我的猜测是由于考虑到浮点数的精度损失,导致他们制定了负数对非整数幂的规则应始终为

NaN
——基本上是因为非整数幂是可能由于精度损失而给出一个复数,即使它不应该,并且可能没有好的方法从中恢复。

对此,我相当满意,但我确实欢迎进一步的信息。

javascript floating-point ieee-754 ecmascript-5 ecma262
2个回答
4
投票

我假设是因为那些情况导致结果进入复杂的水域,而 ECMAScript 没有配备虚数。具体来说,您的示例应该产生接近

1 + 1.732i
的结果,以及其他结果。 (事实上 -2 也是一个可能的结果是无关紧要的 - 这是一个意外而不是一个规则。)


4
投票

您可以使用辅助函数。

很快我就遇到了类似的情况。这是为您建议的解决方案:

function checkPower(x, y) {
if (x > 0 || Math.round(y) == y) {
  return Math.pow(x, y)
} else {
  var r = -1 * Math.pow(-x, y);
  if( Math.pow( r, 1/y) == x) 
    return r;
  else 
    return NaN;
}

}

© www.soinside.com 2019 - 2024. All rights reserved.