hushicai/hushicai.github.io

JavaScript Numbers

Opened this issue · 5 comments

JavaScript浮点数相关资料。

双精度浮点数存储格式:

image

sign(符号): 用来表示正负号

exponent(指数): 用来表示次方数

mantissa(尾数): 用来表示精确度

符号

0代表数值为正,1代表数值为负。

指数

双精度浮点数在存储指数位时,会加上一个固定的偏移值。

IEEE 754标准规定该固定值为2^(e-1) - 1,其中e为指数位的长度,即2^(11 - 1) - 1 = 1023

尾数

尾数一般要求规格化,把尾数处理到(0, 2)区间内,这样可以省去小数点前的1

例子

例如0.1 转成二进制:

0.1.toString(2)
// "0.0001100110011001100110011001100110011001100110011001101"

科学计数法:

1.100110011001100... x 2^-4

我们自己算出来的是-4,但实际计算机存储时,会加上偏移值,即E = -4 + 1023 = 1019

Number(1019).toString(2)
// "1111111011"

M 舍去首位的1,得到 100110011001100...,最终就是:

image

references

安全整数

(-2^53, 2^53)范围内,所有的整数都有唯一的浮点数表示,这就是所谓的安全整数。

2^53

二进制表示:

1000000...000 (一个1,53个0)

科学计数法:

1.000000...000 x 2^53(小数点后53个0)

其实就相当于小数点往左移动了53位。

双精度表示法:

符号位:0,指数:53,尾数:1.000000...000 (小数点后52个0)

由于双精度浮点数的尾数位数限制,最后一位0丢失了,精度丢失了,所以不认为是一个安全整数

2^53 - 1

二进制表示:

11111111111111111111111111111111111111111111111111111(53个1)

科学计数法:

1.111111...111 x 2^52(小数点后52个1)

双精度表示法:

符号位:0,指数:52,尾数:1.111111....111 (小数点后52个1)

2^53 - 2

二进制表示:

11111111111111111111111111111111111111111111111111110(52个1,一个0)

科学计数法:

1.111111...1110 x 2^52(小数点后51个1,一个0)

双精度表示法:

符号位:0,指数:52,尾数:1.111111....110 (小数点后51个1,一个0)

以此类推,以上范围内的整数都可以由一个唯一的浮点数表示。

如果超出了以上范围,存储就可能不唯一了,例如2^53 + 1

2^53 + 1

二进制表示:

1000000...001 (一个1,52个0,一个1)

科学计数法:

1.000000...001 x 2^53(小数点后52个0,一个1)

双精度表示法:

符号位:0,指数:53,尾数:1.000000...000 (小数点后52个0)

由于双精度浮点数的尾数位数限制,最后一位1要丢掉。

所以实际上2^53 + 12^53的存储是一样的:

Math.pow(2, 53) === Math.pow(2, 53) + 1 // true

整数和浮点数不再一一对应,所以就不安全了。