Skip to content

JavaScript 中数字的存储

首先提出如下问题:

  • JS 中的小数运算是精确的吗?【不是】
  • JS 中的整数运算是精确的吗?【不是】
  • JS 中的整数运算是连续的吗?【不是】
  • JS 中能表示的最小数字是多少?【Number.MIN_VALUE】
  • JS 中能表示的最大数字是多少?【Number.MAX_VALUE】
  • JS 中能表示的最大连续整数是多少?【Number.MAX_SAFE_INTEGER】
  • JS 中能表示的数字的有效位数是多少?【16~17】

警告

最大连续整数是指向下连续且 +1 仍然连续,并非字面意义“最大”!

二进制

现实世界中,十进制共有十个数字,逢十进一。

而在计算机世界中,计算机只能识别电平的高低,因此诞生了只有 0 和 1 两个数字、逢二进一的二进制。

整数转换

二进制转十进制

1101 => 123+122+021+120=13

11.01 => 121+120+021+122=3.25

十进制转二进制

13 / 261
6 / 230
3 / 211
1 / 201

倒序取出余数拼接得到 13 转化为二进制为 1101。

3 / 211
1 / 201

因此,3 转化为二进制的整数部分,应倒序拼接为 11。

小数部分
0.25 * 20.50
0.5 * 21.01

计算直到乘积的小数部分为 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 位表示有效数字,即尾数。
  • 最终数据是 ±1.[]2
text
0   1000 0000 011   1111 0000 ...

相当于:1.1111210271023

提示

  1. 为了解决负数次幂的表示问题,引入了偏移量,第二部分应该减去 1023,因此得到上面的结果。
  2. 指数部分共 11 位,因此可表示的数字个数为 2048。

特殊情况

  1. 指数和尾数同时为 0 表示数字 0。
  2. 符号为 0,指数为 2047,尾数为 0,表示正无穷(Infinity)。
  3. 符号为 1,指数为 2047,尾数为 0,表示负无穷(-Infinity)。
  4. 指数为 2047,尾数不为 0,表示 NaN。
  5. 在 JS 中进行数值计算无法手动得到 NaN,数值计算当指数超出范围会自动清空尾数。
  6. 一个正常的数字,指数部分最大为 2046 - 1023 = 1023。

能表示的最大数字

text
0   1111 1111 110   1111 1111 ...

相当于:1.1111...21023,也就是 Number.MAX_VALUE。

能表示的最大安全整数

根据之前的原理,尾数部分全部为 1 的时候取最大安全整数,此时指数部分结果为 52,值为 2531,也就是 Number.MAX_SAFE_INTEGER。