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

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

根据我在网上找到的所有内容,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 double 和 JavaScript 数字都是 64 位浮点数,所以我很困惑为什么它们会输出不同的结果。有什么想法吗?

JavaScript 将 Number 到字符串的默认转换会产生足够的十进制数字来唯一区分 Number。 (这出自 ECMAScript 2018 Language Specification, which I explain a little here 的第 7.1.12.1 条中的第 5 步。)ECMAScript 规范未涵盖通过 console.log 进行格式化,但很可能 Number 被转换为字符串,使用与 NumberToString.

相同的规则

由于停在十位,产生 131621703842267140,足以将 floating-point 数字与其两个相邻的可表示值 131621703842267120 和 131621703842267152 区分开来,JavaScript 停在那里。

您可以使用 toPrecision 请求更多数字;以下生成“131621703842267136.000”:

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

(请注意,131621703842267136 可以用 IEEE-754 基本 64 位二进制格式准确表示,JavaScript 用于 Number,许多 C 实现用于 double。所以由于 floating-point 格式,本题没有舍入误差。所有变化均由十进制和 floating-point 之间的转换产生。)

在 2019-05-17 16:27:53 UTC 编辑之前,问题指出 C 程序显示“131621703737409536.000000”为 131621703842267136。这不符合 C 标准。 C 标准对其 floating-point 格式要求很宽松,但为 131621703842267136 生成“131621703737409536.000000”违反了它们。这受C 2018 (and 2011) 7.21.6.1 13:

这句话约束

Otherwise, the source value is bounded by two adjacent decimal strings L < U, both having DECIMAL_DIG significant digits; the value of the resultant decimal string D should satisfy LDU, with the extra stipulation that the error should have a correct sign for the current rounding direction.

DECIMAL_DIG 必须至少为 10,按 5.2.4.2.2 12。数字 131621703842267136(粗体标记第十位数字)由两个相邻的 ten-digit 字符串“131621703800000000”和“131621703900000000”。字符串“131621703737409536.000000”不在这些之间。

这也不能是 C 实现对 double 使用不同的 floating-point 格式的结果,因为 5.2.4.2.2 要求格式足以将至少十位十进制数字转换为double 并返回十进制而不更改值。