从我在网上可以找到的所有内容来看,据称JavaScript使用IEEE 754双精度数作为其数字,但是我发现可以在C双精度数中使用的数字,但不能在JavaScript中使用。例如,
#include <stdio.h>
int main(){
double x = 131621703842267136.;
printf("%lf\n", x);
}
打印131621703842267136.000000
注意:在该问题的早期版本中,我用C表示错误的数字,但使用JavaScript
console.log(131621703842267136)
输出131621703842267140
。从我在网上阅读的所有内容来看,C双打和JavaScript数字都是64位浮点数,因此我很困惑为什么它们会输出不同的结果。有什么想法吗?
答案 0 :(得分:2)
JavaScript默认将Number
转换为字符串会产生足够的十进制数字,以唯一地区分Number
。 (这是由于ECMAScript 2018 Language Specification的第7.1.12.1节中的第5步引起的,我对here进行了一些解释。)ECMAScript规范未涵盖通过console.log
进行格式化,但是可能Number
使用与NumberToString
相同的规则转换为字符串。
由于停在十位数,即产生131621703842267140,足以将浮点数与两个相邻的可表示值131621703842267120和131621703842267152区别开来,因此JavaScript会在那里停止。
您可以使用toPrecision
请求更多数字;以下产生“ 131621703842267136.000”:
var x = 131621703842267136;
console.log(x.toPrecision(21))
(请注意,131621703842267136可以用IEEE-754基本的64位二进制格式精确表示,JavaScript用于Number
,许多C实现用于double
。因此,在这个问题归因于浮点格式。所有更改均来自十进制和浮点之间的转换。)
C标准对其浮点格式要求不严格,但是为131621703842267136生成“ 131621703737409536.000000”违反了它们。这受C 2018(和2011)7.21.6.1 13中的此句子的约束:
否则,源值由两个相邻的十进制字符串 L < U 界定,它们都具有
DECIMAL_DIG
个有效数字;所得的十进制字符串 D 的值应满足 L ≤ D ≤ U ,并另外规定错误应在当前取整方向上带有正确的符号。
DECIMAL_DIG
必须至少为10,以5.2.4.2.2 12.数字131621703 8 42267136(粗体表示第十位数字)以两个相邻的十位数字为界字符串“ 131621703 8 00000000”和“ 131621703 9 00000000”。字符串“ 131621703 7 37409536.000000”不在两者之间。
这也不可能是因为double
使用不同浮点格式的C实现的结果,因为5.2.4.2.2要求该格式足以将至少十个十进制数字转换为{{1} },然后返回十进制,而不会更改其值。