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 L ≤ D ≤ U, 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
并返回十进制而不更改值。
根据我在网上找到的所有内容,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 L ≤ D ≤ U, 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
并返回十进制而不更改值。