为什么 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
我的理解是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