这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战
在上一篇文章 JS数字之旅——Number(上) 中,提到的最大/最小正数、最大安全整数、浮点数运算精度问题,将会在这里的深入探讨过程中得到解答。
64位双精度浮点数
存储格式
上篇提到,Number是用64位双精度浮点数表示的。由此可知,一个Number类型的数据,就是64bit(8个字节)。第一个(cao)直(shuai)接的想法,就是可表示的最大数字应该是2^63-1 = 9223372036854776000,但是显然,这个可表示的数字就比较小了。实际上,根据IEEE 754-2019标准的定义,双精度浮点数的内部格式是由 1位表示符号、11位表示指数 以及 52位表示尾数 所组成的。
其中,符号位中,0代表正数,1代表负数;指数是有符号的,采取补码表示法,合法范围是-1022到+1023;52位的尾数表示53位的二进制数字。
表示法
双精度浮点数的表示方式是:
实际的执行:
- 根据指数 exponent,对1+二进制尾数的 1.mantissa 进行小数点移位(指数为正数右移,负数左移)
- 转化为十进制
- 根据 signbit,决定正负数
另外,有几个组合代表特别的含义:
| 指数 | 尾数 | 结果 |
|---|---|---|
0x7ff | 0x0 0000 0000 0000 | Infinity |
0xfff | 0x0 0000 0000 0000 | -Infinity |
0x000 | 0x0 0000 0000 0000 | 0 |
解答时间
所以,几个最大最小值的存储和计算如下
| 值 | 符号 | 指数 | 尾数 | 计算公式 | 结果 |
|---|---|---|---|---|---|
| 最大正数 | 0x0 | 0x7fe | 0xf ffff ffff ffff | 1.7976931348623157e+308 | |
| 最小正数 | 0x0 | 0x000 | 0x0 0000 0000 0001 | 5e-324 | |
| 最大安全整数 | 0x0 | 0x433 | 0xf ffff ffff ffff | 9007199254740991 |
由此看出,超过最大安全数之后,实际的数值和表示的数字误差越来越大。
前面提到的浮点数误差问题,也在这里得到了解答,因为是以二进制存储的关系,实际上每一个十进制数,都是通过某个数字的2的n次方转换而来的,整数不会有任何问题,但是带小数位的浮点数就会出现无法精确转换的问题。