JavaScript 中数字的存储
首先提出如下问题:
- JS 中的小数运算是精确的吗?【不是】
- JS 中的整数运算是精确的吗?【不是】
- JS 中的整数运算是连续的吗?【不是】
- JS 中能表示的最小数字是多少?【Number.MIN_VALUE】
- JS 中能表示的最大数字是多少?【Number.MAX_VALUE】
- JS 中能表示的最大连续整数是多少?【Number.MAX_SAFE_INTEGER】
- JS 中能表示的数字的有效位数是多少?【16~17】
警告
最大连续整数是指向下连续且 +1 仍然连续,并非字面意义“最大”!
二进制
现实世界中,十进制共有十个数字,逢十进一。
而在计算机世界中,计算机只能识别电平的高低,因此诞生了只有 0 和 1 两个数字、逢二进一的二进制。
整数转换
二进制转十进制
1101 =>
11.01 =>
十进制转二进制
模 | 商 | 余 |
---|---|---|
13 / 2 | 6 | 1 |
6 / 2 | 3 | 0 |
3 / 2 | 1 | 1 |
1 / 2 | 0 | 1 |
倒序取出余数拼接得到 13 转化为二进制为 1101。
模 | 商 | 余 |
---|---|---|
3 / 2 | 1 | 1 |
1 / 2 | 0 | 1 |
因此,3 转化为二进制的整数部分,应倒序拼接为 11。
乘 | 积 | 小数部分 |
---|---|---|
0.25 * 2 | 0.5 | 0 |
0.5 * 2 | 1.0 | 1 |
计算直到乘积的小数部分为 0 即可,顺序取出小数部分拼接,得到 .01。
所以,3 转化为二进制为 11.01。
为什么 JS 的小数运算不精确?
十进制的小数,转化为二进制之后,可能是无限小数。
比如,0.3 转化为二进制为 0.01 0011 0011 ...
但是,计算机对数字的存储能力有限,因此会丢失一些数据。
JS 如何存储数字?
计算机存储数字的方法
计算机存储数字一般有两种方法:整数法和浮点法。浮点法存放的数字,叫做 浮点数(float),浮点数分为单精度和双精度。
而 JS 中神奇的一点是 —— JS 中的整数也会用浮点法存储,这也解释了为什么 JS 中整数过大也会失去精度。
JS 在计算机中,给每一个数字开辟一块内存空间,尺寸固定为 64 位。
在计算机中,位(bit)是最小的存储单位。
1 byte = 8 bit
1KB = 1024 byte
1 MB = 1024 KB
1GB = 1024 MB
64 位被分为三段,分别有 1、11、52 位:
- 第一位是符号位,分别用 0 和 1 代表正数和负数。
- 第二段的 11 位,表示指数位。
- 最后的 52 位表示有效数字,即尾数。
- 最终数据是
。
text
0 1000 0000 011 1111 0000 ...
相当于:
提示
- 为了解决负数次幂的表示问题,引入了偏移量,第二部分应该减去 1023,因此得到上面的结果。
- 指数部分共 11 位,因此可表示的数字个数为 2048。
特殊情况
- 指数和尾数同时为 0 表示数字 0。
- 符号为 0,指数为 2047,尾数为 0,表示正无穷(Infinity)。
- 符号为 1,指数为 2047,尾数为 0,表示负无穷(-Infinity)。
- 指数为 2047,尾数不为 0,表示 NaN。
- 在 JS 中进行数值计算无法手动得到 NaN,数值计算当指数超出范围会自动清空尾数。
- 一个正常的数字,指数部分最大为 2046 - 1023 = 1023。
能表示的最大数字
text
0 1111 1111 110 1111 1111 ...
相当于:
能表示的最大安全整数
根据之前的原理,尾数部分全部为 1 的时候取最大安全整数,此时指数部分结果为 52,值为