为什么JavaScript中Math.pow()(有时)不等于**?


118

我刚刚发现ECMAScript 7功能可以a**b作为Math.pow(a,b)MDN参考)的替代产品,并且在该帖子中遇到了一个讨论,在这些讨论中它们的行为显然有所不同。我已经在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

7
听起来好像有人重写了他们使用的算法,但发现了浮点错误。数字很​​难...
krillgar

4
@krillgar听起来很合理,但是为什么在函数中没有发生相同的错误呢?
Thomas Altmann

3
@AndersonPimentel MDN链接指向兼容性表
阿尔瓦罗·冈萨雷斯

7
两者之间的区别是:var x = 99; x * * x; 或函数diff(x){返回99 * * 99-(x * * x);和99 * * 99。}; 差异(99)。抱歉,间距
太小

1
@xszaboj将代码放入反引号中`likethis`,以使其易于阅读,并避免了大胆/斜体的问题
phuclv

Answers:


126

99**99在编译时评价(“常量折叠”),以及编译器的pow程序是从不同的运行时一个**在运行时进行评估时,结果与Math.pow— 相同-难怪,因为**实际上已编译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 = 369729637649726772657187905628805440595668764281741102430259972423552570455277523421410650010128232727940978889548326540119429996769494359451621570193644014418071060667659301384999779999159200499899

因此第一个结果是更好的近似,但常量和动态表达式之间的这种差异仍然不应该发生。

此行为看起来像是V8中的错误。据报道,有望尽快修复。


19
因此,基本上是JS试图99**99事先通过计算来提高性能?因为Math.pow可以为数字和变量创建相同的输出,但是**不是,这可以被认为是错误吗?
Thomas Altmann

3
@ThomasAltmann:Math.row始终是运行时,只能对运算符进行const折叠。是的,绝对是一个错误。
乔治

11
通过此处的OP外观,已记录了一个错误。
James Thorpe

5
我使用MS边缘,所有3个结果都是一样的:3.697296376497263e+1973.697296376497263e+197,和3.697296376497263e+197分别。绝对是Chrome的错误。
Nolonar

4
@ThomasAltmann如果常量折叠产生的值比运行时impl 差,那么这是一个错误。如果它产生的值比运行时更好,则可能会或可能不会将其视为错误。在这种情况下,更好—正确的值为“ ... 26772 ...”,恒定折叠会产生“ ... 268”(正确舍入),运行时会产生“ ... 263”(偏移4+单位放在最后)。
hobbs
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.