Javascript 中浮点数的最大精度(小数点后)是多少



我使用的算法需要从Javascript中的浮点数中压缩尽可能多的精度级别。我不介意精度是来自一个很大的数字,还是小数点后有很多数字,我只是需要尽可能多的数字。

(如果你在乎为什么的话,这是一种拖放排名算法,在重新平衡之前必须处理很多停顿。我也知道有更好的基于字符串的算法,但数值方法适合我的目的)

MDN文件说:

JavaScript Number类型是一个双精度64位二进制格式IEEE 754值,类似于Java或C#中的double。这意味着它可以表示分数值,但它可以存储的内容有一些限制。一个数字只保留小数点后17位的精度;算术要四舍五入。

我应该如何最好地使用";精确到小数点后17位">

小数点后17位是否表示";共17位数字,包括小数点前和小数点后的数字";

例如(为了可读性,添加下划线表示千个分隔符)

# 17 numerals: safe
111_222_333_444_555_66
# 17 numerals + decimal point: safe
111_222_333_444_555_6.6
1.11_222_333_444_555_66
# 18 numerals: unsafe
111_222_333_444_555_666
# 18 numerals + decimal point: unsafe
1.11_222_333_444_555_666
111_222_333_444_555_66.6

我认为数字的精度决定了你可以使用的数字的数量,并且小数点在这些数字中的位置实际上是学术性的。

  • 我是否正确地思考了这个问题
  • 小数点的存在与计算有任何关系吗?还是只是数字数量的问题
  • 我是否应该假设17个数字是安全的/18个数字是不安全的
  • 这是否因浏览器而异(不仅在今天,而且在10年的窗口期内,是否应该假设浏览器的精度可能会提高)

简短的回答:你可能会挤出15"安全";数字,小数点放在哪里并不重要。

任何人都不知道JavaScript标准将如何发展并使用其他数字表示。

注意MDN文档如何说";大约17个小数";?对,这是因为有时你可以代表那么多数字,有时更少。这是因为浮点表示法不能将1比1映射到我们的十进制。

即使是信息看似较少的数字,也会出现舍入误差。

例如0.1 + 0.2 => 0.30000000000000004

console.log(0.1 + 0.2);

然而,在这种情况下,我们在精度上有很大的余量,所以你可以要求你想要摆脱舍入误差的精度

console.log((0.1 + 0.2).toPrecision(1));

为了更详细地说明这一点,请考虑以下片段:

for(let i=0;i<22;i++) { 
console.log(Number.MAX_SAFE_INTEGER / (10 ** i)); 
}

你会在第16位看到很多舍入错误。然而,在某些情况下,即使是小数点后16位也会出现舍入误差。如果你看这里

https://en.wikipedia.org/wiki/IEEE_754

它表示二进制64具有CCD_ 2十进制数字。这就是为什么我猜15位数是你从中得到的最大精度。

您必须执行操作,在将数字保存回任何表示形式之前,您必须执行.toPrecision(15)

最后,这有一些很好的解释。https://floating-point-gui.de/formats/fp/

顺便说一句,我读这个问题很好奇,所以我边写答案边读。有很多人比我更了解这一点。

小数点的存在与计算有任何关系吗?还是只是存在的数字数量的问题

Kinda。要回答这个问题,您需要了解64位";双精度";浮点数字在存储器中表示。";数字的数目";大致翻译为";尾数的长度";,其实际上是固定的并且独立于点的位置。但是:它是二进制数字和一个二进制点,而不是十进制数字和小数点。它们并不直接对应。还有一些东西,比如低于标准的数字。

我应该假设17个数字是安全的/18个数字是不安全的吗?

否。事实上,只有15个十进制数字是"0";"安全";如果这是你开始的表示,并且想要精确地表示为一个二重。

这是否因浏览器而异(不仅在今天,而且在10年的窗口期内,是否应该假设浏览器的精度可能会提高)?

不,没有变化。JavaScriptnumber类型将始终为64位双精度。

我对这个问题的思考正确吗?

否。

你说你是在拖放排名算法的背景下考虑这一点的,而你不想这样做基于字符串。然而,考虑数字中的小数位数本质上就是考虑数字的字符串表示。不要这样做——要么一直到字符串,要么把数字当作二进制。

既然你还提到";再平衡";,我假设您想使用数字来编码二进制树中每个项目的位置。这是一种合理的方法,但您确实需要考虑数字的二进制表示。你真的应该在那里使用整数,而不是浮点数,否则逻辑会复杂得多。从决定要使用多少比特开始。每个都有一些限制,所以明智地选择:

  • 31/32位是number的JS逐位运算符。所有浏览器都可以轻松支持
  • 53位是您可以用浮点numbers精确表示的整数范围。整数运算将按预期工作到该大小。按位操作需要额外的代码
  • 8的固定倍数(比如64位)是您可以用类型化数组表示的。按位运算可以按部分进行,算术运算需要额外的代码。或者使用一个提供64位的BigUint64Array作为bigint进行计算/操作,但在旧浏览器中不支持
  • bigint数字可以实现任意精度,它同时支持按位和算术运算,但在旧浏览器中不起作用。不过,Polyfills和bigint库是可用的

最新更新