为什么 Javascript 的 Math.pow() 似乎 return 与 C 中的相同值相比是一个四舍五入的值?

Why does Javascript's Math.pow() seem to return a rounded value compared to the same in C?

我的理解是C的double和Javascript的数都是IEEE 754 64位浮点数。我正在尝试将一些代码从 C 移植到 Nodejs,我 运行 进入 Javascript 的 Math.pow().

中似乎是一个舍入错误

这是我的 C 程序:

#include "stdio.h"
#include "math.h"

int main(int argc, char *argv[]) {
  double shared = 729;
  double exponent = 15;
  double prime = 1500450271;
  double power = pow(shared, exponent);
  double mod = fmod(power, prime);
  int intResult = (int) mod;
  printf("shared: %lf, exponent: %lf, prime: %lf, pow: %lf, mod: %lf, result: %i\n",
      shared, exponent, prime, power, mod, intResult); 
}

其输出为:

shared: 729.000000, exponent: 15.000000, prime: 1500450271.000000, pow: 8727963568087711970669458465954849888403456.000000, mod: 1488486878.000000, result: 1488486878

有趣的是,当我尝试在 Javascript 中执行此计算时(在节点、Chrome、Firefox 中测试)

我得到以下结果:

> Math.pow( 729, 15)
8.727963568087713e+42
> Math.pow( 729, 15 ) % 1500450271;
93655693

此外,当我将 C 的功率结果存储在 Javascript 数字中时:

> 8727963568087711970669458465954849888403456.0
8.727963568087712e+42

注意差异 -> 8.727963568087713e+42 !== 8.727963568087712e+42,因此模运算无法产生相同的结果是可以理解的。

我查看了 v8 实现 Math.pow 的源代码,但 masm 宏在我看来像希腊语 atm。

在此感谢任何帮助。

ECMAScript ("JavaScript") 不对 pow 函数的精度做出任何保证。 ECMA-262 says:

Returns an implementation-dependent approximation to the result of raising x to the power y.

C语言也不行。只有 C99 规范的可选附件 F 引用了 IEC 60559(与 IEEE 754 相同),但 pow 不是有精度保证的基本操作之一。

在你的例子中,你从 Node.js 得到的结果比你的 C 程序的结果稍微不准确,但这并不违反规范。你只需要忍受这种差异。在巨大的浮点数上调用 fmod 无论如何都是愚蠢的。

编辑: 差异的原因可能是 x87 80 位 "double extended" 格式的精度过高。采取以下方案:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char *argv[]) {
    int base = atoi(argv[1]);
    int exp  = atoi(argv[2]);
    printf("pow: %.15e\n", pow(base, exp));
    return 0;
}

使用 gcc 编译且没有特殊选项:

$ gcc -Wall -O2 pow.c -lm -o pow
$ ./pow 729 15
pow: 8.727963568087712e+42

使用 -mpc64 编译:

$ gcc -mpc64 -Wall -O2 pow.c -lm -o pow
$ ./pow 729 15
pow: 8.727963568087713e+42