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

JavaScript seems to be doing floating point wrong (compared to C)

提问人:Oscar Smith 提问时间:5/17/2019 最后编辑:Oscar Smith 更新时间:1/26/2022 访问量:134

问:

从我在网上找到的所有内容来看,据称 JavaScript 使用 IEEE 754 双精度作为其数字,但我发现数字可以在 C 双精度中工作,但在 JavaScript 中不起作用。例如

#include <stdio.h>

int main(){
    double x = 131621703842267136.;
    printf("%lf\n", x);
}

打印 注意:在问题的早期版本中,我复制了 C 的错误数字,但在 JavaScript 中131621703842267136.000000

console.log(131621703842267136)

输出。从我在网上读到的所有内容来看,C 双精度和 JavaScript 数字都是 64 位浮点数,所以我非常困惑为什么它们会输出不同的结果。有什么想法吗?131621703842267140

JavaScript C 点浮 点精度

评论

1赞 Oscar Smith 5/17/2019
虽然这是真的,但它仍然应该是安全的,因为它等于 ,所以 2 位的唯一非幂是它要小得多,所以它可以存储为双倍6**223**22
1赞 Oscar Smith 5/17/2019
为了证明这一点,C 能够将其存储在双精度中,因此这个问题不是重复的
2赞 Shidersz 5/17/2019
输出与问题中的输入不同。例如,查看整数部分的最后几位数字。131621703737409536.000000131621703842267136C4
2赞 Oscar Smith 5/17/2019
afaik IEEE 754 定义了 float 和 double,javascript 使用 IEEE 754 double。en.wikipedia.org/wiki/Double-precision_floating-point_format
2赞 Eric Postpischil 5/17/2019
您使用的是哪种 C 实现?根据我的回答,它似乎违反了 C 标准。您会仔细检查问题中的 C 源是否产生问题中显示的输出吗?

答:

3赞 Eric Postpischil 5/17/2019 #1

JavaScript 默认将 a 转换为字符串会产生足够的十进制数字来唯一区分 .(这源于 ECMAScript 2018 语言规范第 7.1.12.1 条中的第 5 步,我在这里对此进行了一些解释。ECMAScript 规范未涵盖格式化 via,但可能使用与 相同的规则将其转换为字符串。NumberNumberconsole.logNumberNumberToString

由于停在十位数字上,产生131621703842267140,足以将浮点数与其两个相邻的可表示值 131621703842267120 和 131621703842267152 区分开来,因此 JavaScript 就到此为止。

您可以使用 ;以下生成“131621703842267136.000”:toPrecision

var x = 131621703842267136;
console.log(x.toPrecision(21))

(请注意,131621703842267136 完全可以用 IEEE-754 基本 64 位二进制格式表示,JavaScript 使用 这种格式来表示 ,许多 C 实现使用 .因此,由于浮点格式,此问题中没有舍入错误。所有更改都源于小数点和浮点之间的转换。Numberdouble

在 2019-05-17 16:27:53 UTC 进行编辑之前,该问题指出 C 程序显示 131621703842267136 的“131621703737409536.000000”。这不符合C标准。C 标准对其浮点格式要求很宽松,但为 131621703842267136 生成“131621703737409536.000000”违反了这些要求。这受 C 2018(和 2011)7.21.6.1 13 中的这句话的约束:

否则,源值由两个相邻的十进制字符串 L < U 限定,这两个字符串都具有有效数字;生成的十进制字符串 D 的值应满足 LDU,并 额外规定错误应具有当前舍入方向的正确符号。DECIMAL_DIG

DECIMAL_DIG必须至少为 10 个,到 5.2.4.2.2 12.数字 131621703 842267136(粗体标记第十位数字)由两个相邻的十位数字字符串“1316217038000000000”和“1316217039000000000”组成。字符串“131621703737409536.000000”不在这两者之间。

这也不能是 C 语言使用不同浮点格式的结果,因为 5.2.4.2.2 要求该格式足以在不更改值的情况下将至少十个十进制数字转换为十进制或返回十进制。doubledouble