JavaScript运行时如何将BINARY(双精度浮点格式)转换回DECIMAL

时间:2018-11-07 11:08:52

标签: javascript ieee-754

给出十进制数字0.2

EX

var theNumber= 0.2;

我将其存储为(基于双精度64位浮点格式IEEE 754)

0-01111111100-1001100110011001100110011001100110011001100110011001

该二进制数实际上四舍五入为64位。

如果我们使用该值并将其转换回十进制,我们将得到

0.19999999999999998

(0.1999999999999999833466546306226518936455249786376953125)

不完全是0.2

我的问题是,当我们要求输入theNumber(例如:alert(theNumber))的十进制值时,JavaScript运行时如何知道theNumber最初是0.2?

3 个答案:

答案 0 :(得分:3)

JavaScript默认将Number转换为字符串会产生足够的十进制数字,以唯一地区分Number。 (这是由于ECMAScript 2018 Language Specification的第7.1.12.1节中的第5步而引起的,我将对here进行一些解释。)

让我们首先考虑将十进制数字转换为Number。当数字转换为Number时,其精确的数学值将四舍五入为Number中可表示的最接近值。因此,将源代码中的0.2转换为Number时,结果为0.200000000000000011102230246251565404236316680908203125。

Number转换为十进制时,我们需要产生几位数来唯一区分Number?在0.200000000000000011102230246251565404236316680908203125的情况下,如果我们产生“ 0.2”,则有一个十进制数字,当再次转换为Number时,结果为0.200000000000000011102230246251565404236316680908203125。因此,“ 0.2”唯一地将0.200000000000000011102230246251565404236316680908203125与其他Number值区分开,这就是我们所需要的。

换句话说,JavaScript的规则是产生足以区分Number的数字,这意味着当转换为Number并返回字符串时,任何短的十进制数字都将产生相同的十进制数字(除非无关紧要零),因此“ 0.2000”将变为“ 0.2”或“ 045”将变为“ 45”)。 (一旦十进制数字足够长以与Number值冲突,则它可能不再经过往返转换。例如,“ 0.20000000000000003”将成为Number 0.2000000000000000388578058618804789148271083083787787375,然后字符串“ 0.20000000000000004”。)

如果由于算术的原因,我们有一个接近0.200000000000000011102230246251565404236316680908203125但不相同的数字,例如0.2000000000000000388578058618804789148271083831787109375,则JavaScript在这种情况下将打印更多数字“ 0.20000000000000004”,因为它需要更多的数字来将其与“ 0.2英寸的情况。

答案 1 :(得分:2)

实际上,0.2由您发布的其他位序列表示。
每次结果匹配正确的位序列时,控制台都会输出0.2。但是,如果您的计算结果按其他顺序进行,则控制台将输出类似0.19999999999999998的内容。

类似的情况在最常见的示例0.1 + 0.2上得到输出0.30000000000000004,因为此结果的位序列与0.3的表示形式不同。

console.log(0.2)
console.log(0.05 + 0.15)
console.log(0.02 + 0.18)

console.log(0.3)
console.log(0.1 + 0.2)
console.log(0.05 + 0.25)

根据ECMAScript语言规范:

  

11.8.3.1静态语义:MV
数字文字代表Number类型的值。该值分两个步骤确定:首先,从文字中得出数学值(MV);第二,从公式中得出数学值。其次,将此数学值四舍五入[... (这里将描述整个过程)]

您可能还会对以下部分感兴趣:

  

6.1.6数字类型
[...]
在本规范中,短语“ x的数字值”,其中x表示精确的实数数量是指以下列方式选择的数字值。
[... (描述了整个过程)]
(此过程完全对应于IEEE 754-2008“四舍五入,平整”模式的行为)

答案 2 :(得分:0)

所以,我的假设是错误的。

我写了一个小程序来做实验。

进入内存的二进制值不是

0-01111111100-1001100110011001100110011001100110011001100110011001

尾数部分不是1001100110011001100110011001100110011001100110011001

之所以这样,是因为我舍弃了该值,而不是舍入了它。:((

1001100110011001100110011001100110011001100110011001...[1001]需要四舍五入为52位。如果该系列是1,则位53,因此该系列被四舍五入并变为:1001100110011001100110011001100110011001100110011010

正确的二进制值应为:

0-01111111100-1001100110011001100110011001100110011001100110011010

该值的完整十进制为:

0.200 000 000 000 000 011 102 230 246 251 565 404 236 316 680 908 203 125

不是

0.199 999 999 999 999 983 346 654 630 622 651 893 645 524 978 637 695 312 5

作为埃里克(Eric)的答案,所有十进制数字(如果已转换为二进制数)

0-01111111100-1001100110011001100110011001100110011001100110011010

将被“视为”为0.2(除非我们使用toFixed()打印更多数字);所有这些十进制数字都共享相同的二进制签名(我真的不知道如何描述它)。

相关问题