JS数字之旅——Number(下)

580 阅读2分钟

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

在上一篇文章 JS数字之旅——Number(上) 中,提到的最大/最小正数、最大安全整数、浮点数运算精度问题,将会在这里的深入探讨过程中得到解答。

64位双精度浮点数

存储格式

上篇提到,Number是用64位双精度浮点数表示的。由此可知,一个Number类型的数据,就是64bit(8个字节)。第一个(cao)直(shuai)接的想法,就是可表示的最大数字应该是2^63-1 = 9223372036854776000,但是显然,这个可表示的数字就比较小了。实际上,根据IEEE 754-2019标准的定义,双精度浮点数的内部格式是由 1位表示符号11位表示指数 以及 52位表示尾数 所组成的。

image.png

其中,符号位中,0代表正数,1代表负数;指数是有符号的,采取补码表示法,合法范围是-1022到+1023;52位的尾数表示53位的二进制数字。

表示法

双精度浮点数的表示方式是:

decimalValue=(1)signbit2toDecimal(exponent)toDecimal(1.mantissa)decimalValue = (-1) ^ {signbit} * 2 ^ {toDecimal(exponent)} * toDecimal(1.{mantissa})

实际的执行:

  1. 根据指数 exponent,对1+二进制尾数的 1.mantissa 进行小数点移位(指数为正数右移,负数左移)
  2. 转化为十进制
  3. 根据 signbit,决定正负数

另外,有几个组合代表特别的含义:

指数尾数结果
0x7ff0x0 0000 0000 0000Infinity
0xfff0x0 0000 0000 0000-Infinity
0x0000x0 0000 0000 00000

解答时间

所以,几个最大最小值的存储和计算如下

符号指数尾数计算公式结果
最大正数0x00x7fe0xf ffff ffff ffff253121023522 ^ {53 - 1} * 2 ^ {1023 - 52}1.7976931348623157e+308
最小正数0x00x0000x0 0000 0000 0001210222522 ^ {-1022} * 2 ^ {-52}5e-324
最大安全整数0x00x4330xf ffff ffff ffff253(1253)2 ^ {53} * (1 - 2 ^ {-53})9007199254740991

由此看出,超过最大安全数之后,实际的数值和表示的数字误差越来越大。

前面提到的浮点数误差问题,也在这里得到了解答,因为是以二进制存储的关系,实际上每一个十进制数,都是通过某个数字的2的n次方转换而来的,整数不会有任何问题,但是带小数位的浮点数就会出现无法精确转换的问题。