JavaScript中的浮点数(IEEE 754)

问题描述 投票:2回答:3

enter image description here

如果我理解正确,JavaScript编号总是存储为双精度浮点数,遵循国际IEEE 754标准。这意味着它使用52位作为分数有效数。但是在上面的图片中,似乎二进制中的0.57使用了54位。

另一件事是(如果我理解正确的话)二进制中的0.55也是重复数。但为什么0.55 + 1 = 1.55(没有损失)和0.57 + 1 = 1.5699999999999998

4"

javascript ieee-754
3个回答
3
投票

这意味着它使用52位作为分数有效数。但是在上面的图片中,似乎二进制中的0.57使用了54位。

JavaScript的Number类型,基本上是IEEE 754基本的64位二进制浮点,具有53位有效数字。 52位在“尾随有效数”字段中编码。前导位通过指数字段编码(指数字段1-2046表示前导位为1,指数字段0表示前导位为零,指数字段2047表示无穷大或NaN)。

您看到的.57值有53个有效位。领先的“0”是由toString操作产生的;它不是数字编码的一部分。

但为什么0.55 + 1 = 1.55(无损失)和0.57 + 1 = 1.5699999999999998。

当JavaScript使用默认规则格式化某些Number x进行显示时,这些规则会产生最短的十进制数字(有效数字,不计算像前导“0”这样的装饰),当转换回Number格式时,产生x。该规则的目的包括(a)始终确保显示唯一地识别哪个Number值是源值,以及(b)不使用比完成(a)所需的更多数字。

因此,如果你从一个十进制数字开始,如.57并将其转换为Number,你得到一些值x,这是转换的结果必须舍入到Number格式中可表示的数字。然后,当x被格式化以显示时,您将获得原始数字,因为表示生成转换回x的最短数字的规则自然会产生您开始使用的数字。

(但是x并不完全代表0.57。最接近的double到0.57略低于它;见the decimal and binary64 representations of it on an IEEE double calculator)。

另一方面,当您执行某些操作(如.57 + 1)时,您正在执行一些算术,该算术产生的数字y不是以简单的十进制数字开头的。因此,在格式化这样的数字以进行显示时,该规则可能需要使用更多的数字。换一种说法。当你添加.571时,Number格式的结果与你从1.57获得的数字不同。因此,为了格式化.57 + 1的结果,JavaScript必须使用更多数字来区分该数字与从1.57获得的数字 - 它们是不同的并且必须以不同方式显示。


如果0.57完全可以表示为double,则总和的前舍入结果将精确地为1.57,因此1 + 0.57将与double相同的1.57

但情况并非如此,实际上是1 + nearest_double(0.57) = 1.569999999999999951150186916493(前舍入,而不是double)向下舍入到 1.56999999999999984012788445398。数字的这些十进制表示具有比我们需要区分有效数的1ulp(最后位置的单位)或甚至0.5 ulp最大舍入误差所需的更多数字。

1.57轮到~1.57000000000000006217248937901,所以这不是打印1 + 0.57结果的选项。十进制字符串需要将数字与相邻的binary64值区分开来。


碰巧发生在.55 + 1中的舍入产生与将1.55转换为Number相同的数字,因此显示.55 + 1的结果产生“1.55”。


3
投票

toString(2)将字符串打印到最后的非零数字。

1.57具有与1 + 0.57不同的位表示(但是获得结果1.57并非不可能), 但是1 + 0.55的二进制等于1.55,如下面的代码片段所示:

console.log(1.57)
console.log(1.57.toString(2))
console.log((1+.57).toString(2))
console.log("1.32 + 0.25 = ",1.32 + .25)
console.log((1.32 + .25).toString(2))
console.log(1.55)
console.log(1.55.toString(2))
console.log((1+.55).toString(2))

请记住,计算机对二进制数执行操作,1.571.55只是一个人类可读的输出


1
投票

Number.prototype.toString大致实现了ES262规范的以下部分:

7.1.12.1 NumberToString(m)

设n,k和s为整数,使k≥1,10** k-1≤s<10 ** k,

s×10 ** n-k的数值是m,

和k尽可能小。

因此toString只是估计值,它不会返回存储的确切字节。

您在控制台中看到的内容也不是确切的表示。

© www.soinside.com 2019 - 2024. All rights reserved.