JavaScript 使用 IEEE 754 标准定义的 64 位浮点格式表示数值。
64位 = 1位符号位(S) + 11位指数位(E) + 52位尾数位(M)
- 符号位(S):0表示正数,1表示负数,决定数值的正负;
- 指数位(E):存储指数的偏移值(偏移量1023),决定数值的数量级;
- 尾数位(M):存储数值的有效数字(二进制),且有一个隐含的1位(规格化数,也叫归一化数,normalized number),所以实际有效位数是 52 + 1 = 53位。
指数位(E)的偏移量 1023 是标准人为规定的,为的是让原本的 11 位无符号位的二进制指数位能表示正负指数,并且正负指数尽可能对称(-1022 ~ 1023)。
尾数位(M)的隐藏位 1 也是标准人为规定的,利用了非零二进制数归一化后整数位必为 1 的特性。
任何一个非零的二进制数,都能唯一表示为 1.xx × 2^e 的形式。
- e 是二进制的指数(整数,可正可负);
- 归一化后整数位必然是固定不变的 1,这是二进制的特性。
IEEE 754 标准正是利用了「归一化后整数位必为 1」的特性,做了一个巧妙设计:
既然这个 1 是所有非零浮点数的固定前缀,那就不用在 64 位中实际存储它,而是「默认存在这个 1」,仅将小数点后的 xx 有效数字部分存入 52 位的尾数位(M)中。
原本尾数位只有 52 位,加上这 1 位隐藏的固定不变的 1 后,实际可用的有效数字位就变成了 53 位(1 + 52),直接提升了浮点数的精度,且没有占用额外的存储空间。
只有非零的归一化浮点数才有隐藏位。对于接近 0 的极小值(非归一化数),IEEE 754 会放弃归一化,此时没有隐藏位,只有 52 位有效数字。
推导:53 位二进制能表示的最大整数是 2^53 - 1
当 53 位二进制尾数位(M)(包含隐藏位 1),所有位都为 1 时,就是它能表示的最大数,计算如下:
111...111(53个1) = 2^52 + 2^51 + ... + 2^1 + 2^0 = 2^53 - 1
这个数就是 JS 中能精确表示的最大安全整数 Number.MAX_SAFE_INTEGER。
一个整数 n 被称为安全整数,当且仅当:它自身和前后相邻的两个整数(n−1、n、n+1),都能被唯一且精确地存储表示,三者的 64 位浮点数编码互不重复,且不存在截断舍入后的失真情况。
在 2^53 ~ 2^1023 这区间内的 2 的整数次幂能精确表示,但都是「孤立的精确数」(相邻数失真,无连续性)。
少数能精确存储的特殊十进制小数
绝大多数小数的二进制,都是无限循环的小数形式,都不能精确存储,只能截断舍入近似存储。
如果一个十进制小数转二进制后是「有限位小数」,就能被 64 位浮点数精确存储,这类小数有明确的数学规则:
十进制小数能精确转为有限位二进制的充要条件:小数部分转化成最简分数形式后,它的分母仅包含质因子 2(即分母是 2 的正整数次幂:2¹、2²、2³...)。
简单说:小数部分是 0.5(1/2)、0.25(1/4)、0.125(1/8)、0.0625(1/16)... 的组合,就能精确存储。
浮点数的「可表示值步长」随数值增大而变大(精度衰减规律)
64 位浮点数的可表示值不是连续的,而是离散的、等步长的(同一量级内步长固定),且数值越大,量级越高,步长越大。这是整数和小数的精度都会随数值增大而衰减的根本原因。
步长是(同一量级内)相邻两个可表示的浮点数之间的差值,由归一化后的指数 e 决定:
步长 = 2^(e-52) (52 是尾数位 M 的位数)。
- 步长越小,可表示值越密集,精度越高;
- 步长越大,可表示值越稀疏,精度越低。
步长对整数和小数的影响:
- 安全整数区(e≤52):步长 = 2^(e-52) ≤1 → 整数的步长为 1,能连续精确表示;小数的步长极小,误差可忽略;
- 2⁵³~2¹⁰²³ 区:步长≥2 → 整数的步长大于 1,无法连续精确表示(相邻整数重叠);小数的步长极大,几乎无法区分相近小数;
- 2¹⁰²³ 以上:超出指数范围,直接变成 Infinity,无法表示为常规数。
MAX_VALUE 和 MIN_VALUE
最大正值:Number.MAX_VALUE = 1.7976931348623157×10³⁰⁸
指数位取归一化数的最大存储值 2046(实际指数 1023),尾数位 52 位全 1(此时浮点数取到归一化数的最大极值,再大就超出指数范围,变成Infinity);
最小正值:Number.MIN_VALUE = 5×10⁻³²⁴(无限接近 0)
指数位取全 0(非归一化数,实际指数 -1023),尾数位仅最后 1 位为 1、其余全 0(此时浮点数取到能表示的最小非 0 正值,再小就会被舍入为 0)。
这是 64 位双精度浮点数基于 IEEE 754 标准的硬件存储极限,是浮点数能表示的所有数值(整数 + 小数)的整体边界,而非专门针对整数的范围。
±Infinity 和 NaN 如何表示
| Infinity(正无穷) | -Infinity(负无穷) | NaN(非数) | |
|---|---|---|---|
| 1位符号位(S) | 0表示正数 | 1表示负数 | 0和1都可,无意义 |
| 11位指数位(E) | 11位全1 | 11位全1 | 11位全1 |
| 52位尾数位(M) | 52位全0 | 52位全0 | 52位非全0(即任意1位是1即可) |
| S0 + E全1 + M全0 | S1 + E全1 + M全0 | S01 + E全1 + M非0 |
E全1 表示 ±Infinity 和 NaN 的特殊值,而 E全0 表示非归一化数(接近 0 的极小值,无隐藏位)。