为啥 JavaScript 中的 Math.pow()(有时)不等于 **?

Posted

技术标签:

【中文标题】为啥 JavaScript 中的 Math.pow()(有时)不等于 **?【英文标题】:Why is Math.pow() (sometimes) not equal to ** in JavaScript?为什么 JavaScript 中的 Math.pow()(有时)不等于 **? 【发布时间】:2017-05-31 10:58:02 【问题描述】:

我刚刚发现了 ECMAScript 7 功能 a**b 作为 Math.pow(a,b) (MDN Reference) 的替代品,并在 that post 中进行了讨论,其中它们的行为显然不同。我已经在 Chrome 55 中对其进行了测试,并且可以确认结果有所不同。

Math.pow(99,99) 返回3.697296376497263e+197

99**99 返回3.697296376497268e+197

因此记录差异 Math.pow(99,99) - 99**99 会导致 -5.311379928167671e+182

到目前为止,可以说它只是另一种实现,但将其包装在函数中的行为又有所不同:

function diff(x) 
  return Math.pow(x,x) - x**x;

调用diff(99) 返回0

为什么会这样?

正如xszaboj 所指出的,这可以缩小到这个问题:

var x = 99;
x**x - 99**99; // Returns -5.311379928167671e+182

【问题讨论】:

听起来好像有人重写了他们使用的算法,发现了一个floating point error。数字很​​难...... @krillgar 听起来很合理,但为什么函数中没有发生同样的错误呢? @AndersonPimentel MDN 链接指向compatibility table。 这两者之间的区别是:var x = 99; x * * x ;和 99 * * 99。或 function diff(x) return 99 * * 99 - (x * * x); ;差异(99)。对不起,评论过滤了两颗星:( @xszaboj 将代码放入反引号 `likethis` 以使其可读并避免粗体/斜体问题 【参考方案1】:

99**99 是evaluated at compile time(“常量折叠”),编译器的pow routine 与runtime one 不同。在运行时评估** 时,结果与Math.pow 相同——难怪** 实际上是compiled 到Math.pow 调用:

console.log(99**99);           // 3.697296376497268e+197
a = 99, b = 99;
console.log(a**b);             // 3.697296376497263e+197
console.log(Math.pow(99, 99)); // 3.697296376497263e+197

其实

99 99 SUP> = 369729637649726772657187905628805440595668764281741102430259972423552570455277523421410650010128232727940978889548326540119429996769494359451621570193644014418071060667659301384999779999159200499899 SUP>

所以第一个结果是一个更好的近似值,但常量表达式和动态表达式之间不应该出现这种差异。

这种行为看起来像 V8 中的一个错误。它has been reported 并有望很快得到修复。

【讨论】:

所以它基本上是 JS 试图通过预先计算 99**99 来提高性能?这可以被认为是一个错误,因为Math.pow 为数字和变量创建了相同的输出,而** 没有? @ThomasAltmann: Math.row 始终是运行时的,const 折叠只能对操作符进行。是的,这绝对是一个错误。 一个错误has been logged,从这里的 OP 看来。 我正在使用 MS Edge,所有 3 个结果都相同:分别为 3.697296376497263e+1973.697296376497263e+1973.697296376497263e+197。这绝对是一个 Chrome 错误。 @ThomasAltmann 如果常量折叠产生的 worse 值比运行时 impl 值,那么它就是一个错误。如果它产生比运行时更好 的值,那么它可能会或可能不会被视为错误。在这种情况下,它会更好——正确的值是“... 26772...”,常量折叠产生“...268”(正确舍入),运行时产生“...263”(关闭 4+单位在最后)。

以上是关于为啥 JavaScript 中的 Math.pow()(有时)不等于 **?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这段代码使用 Math.pow 打印“HELLO WORLD”?

指数运算符 ^ 和 Math.pow() 之间的区别

JS中的Math.pow(a,b)方法

javascript Math.pow

JavaScript Math 对象

JavaScript中计算N次方的方法**和math.pow()-讲解