JavaScript似乎在做浮点错误(与C相比)

时间:2019-05-17 03:42:59

标签: javascript c floating-point floating-accuracy

从我在网上可以找到的所有内容来看,据称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位浮点数,因此我很困惑为什么它们会输出不同的结果。有什么想法吗?

1 个答案:

答案 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} },然后返回十进制,而不会更改其值。