提问人:Oscar Smith 提问时间:5/17/2019 最后编辑:Oscar Smith 更新时间:1/26/2022 访问量:134
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);
}
打印 注意:在问题的早期版本中,我复制了 C 的错误数字,但在 JavaScript 中131621703842267136.000000
console.log(131621703842267136)
输出。从我在网上读到的所有内容来看,C 双精度和 JavaScript 数字都是 64 位浮点数,所以我非常困惑为什么它们会输出不同的结果。有什么想法吗?131621703842267140
答:
JavaScript 默认将 a 转换为字符串会产生足够的十进制数字来唯一区分 .(这源于 ECMAScript 2018 语言规范第 7.1.12.1 条中的第 5 步,我在这里对此进行了一些解释。ECMAScript 规范未涵盖格式化 via,但可能使用与 相同的规则将其转换为字符串。Number
Number
console.log
Number
NumberToString
由于停在十位数字上,产生131621703842267140,足以将浮点数与其两个相邻的可表示值 131621703842267120 和 131621703842267152 区分开来,因此 JavaScript 就到此为止。
您可以使用 ;以下生成“131621703842267136.000”:toPrecision
var x = 131621703842267136;
console.log(x.toPrecision(21))
(请注意,131621703842267136 完全可以用 IEEE-754 基本 64 位二进制格式表示,JavaScript 使用 这种格式来表示 ,许多 C 实现使用 .因此,由于浮点格式,此问题中没有舍入错误。所有更改都源于小数点和浮点之间的转换。Number
double
在 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 的值应满足 L ≤ D ≤ U,并 额外规定错误应具有当前舍入方向的正确符号。
DECIMAL_DIG
DECIMAL_DIG
必须至少为 10 个,到 5.2.4.2.2 12.数字 131621703 842267136(粗体标记第十位数字)由两个相邻的十位数字字符串“1316217038000000000”和“1316217039000000000”组成。字符串“131621703737409536.000000”不在这两者之间。
这也不能是 C 语言使用不同浮点格式的结果,因为 5.2.4.2.2 要求该格式足以在不更改值的情况下将至少十个十进制数字转换为十进制或返回十进制。double
double
评论
6**22
3**22
131621703737409536.000000
131621703842267136
C
4