± (1.尾数) × 2^(指数-1023) 在说什么
上一篇讲完质因子:0.1 在二进制里是无限循环。机器却只有 64 位,必须截成一个有限的近似。截的规则写在 IEEE 754 的这一行里:
1 | 值 ≈ ± (1.尾数) × 2^(指数 − 1023) |
它不是新公式,就是二进制版的科学计数法,再配上「指数不能直接存负数」的偏移。
先看你早就用过的科学计数法
十进制里:
1 | 123.45 = 1.2345 × 10² |
规矩:小数点左边只留 1 位非零数字,其余放进「× 10 的几次方」。
数的大小由指数管,精度由小数点后面那些位管。
float64 完全一样,只是底数从 10 换成 2:
1 | 任意数 = ± 1.xxxxx × 2^真正的指数 |
64 位怎么切开
1 | [正负号 1 位] [存放的指数 11 位] [小数点后的尾数 52 位] |
| 段 | 位数 | 管什么 |
|---|---|---|
| 符号 | 1 | + 或 - |
| 指数 | 11 | 小数点往哪移,也就是 × 2 的几次方 |
| 尾数 | 52 | 小数点后面那些二进制位 |
64 位不是「整数部分 + 小数部分」,而是「符号 + 科学计数法的指数 + 科学计数法的小数」。
「前面隐含一个 1」
规范化之后,小数点前永远是 1。二进制里非零数的最高位只能是 1,没有别的选择。
既然永远是 1,就不必再占 1 位存储,默认它在。这叫隐含位(hidden bit)。
你真正拥有的有效数字:
1 | 隐含的 1 + 存下来的 52 位尾数 = 53 位 |
类比:十进制如果规定一定写成 1.xxx × 10^e,那个 1 也可以不写,只记后面的 xxx。
公式里的 (1.尾数) 就是这个意思:点前面的 1 不占存储,点后面的 52 位才写进那 64 位里。
为什么是 2^(指数 − 1023)
11 位指数存的是 0~2047 的整数,不能直接存负数。做法是先加一个偏移 1023 再存:
1 | 存放的指数 = 真正的指数 + 1023 |
| 真正要乘的 | 存进去的数 |
|---|---|
× 2⁰(1) |
1023 |
× 2¹(2) |
1024 |
× 2⁻¹(0.5) |
1022 |
× 2⁻⁴(0.1 规范化后就是这种) |
1019 |
读出来再减 1023,得到真正的指数。所以公式里会看到 2^(指数 − 1023)。
1023 不是魔法数,是 11 位能表示的范围对半切开,留给正负两边用:
1 | 11 位最大值 2047 |
(全 0、全 1 留给 0、无穷、NaN,这里先不展开。)
0.1 怎样被截成 53 位
把 0.1 写成二进制科学计数法(过程不用背,看形状):
1 | 0.1₁₀ = 0.00011001100110011...₂ (0011 一直重复) |
理想中 1. 后面的 1001 要写无限位。机器只给 52 个空位,第 53 位及以后只能四舍五入掉。
于是内存里不是「精确的 0.1」,而是「离 0.1 最近的、用 53 个二进制位能写出的那个数」,大约是:
1 | 0.10000000000000000555... |
打印时常显示成 0.1,那是显示时又圆了一下,不是内存里真的等于十分之一。
上一篇说的是「为什么循环」:分母多了个质因子 5。
这篇说的是「循环之后机器怎么存」:只留 53 位有效数字,多出来的丢掉。
两件事叠在一起,才变成「先写 float64 再转 decimal 救不回来」。
对照成一句
| 公式里的词 | 日常对应 | 在 float64 里 |
|---|---|---|
± |
正负号 | 最高 1 位 |
1.尾数 |
科学计数法里小数点前的 1,加上后面那些位 | 1 是隐含的,后面存 52 位,一共 53 位有效数字 |
2^ |
十进制里的 10^ |
底数换成 2 |
指数 − 1023 |
真正的移位次数 | 存的时候先加 1023,读的时候再减回去 |
一句话:(1.尾数) 是精度,2^(指数 − 1023) 是小数点往哪移。0.1 的精度是无限的,盒子只有 53 位,只好截成近似。
- Title: ± (1.尾数) × 2^(指数-1023) 在说什么
- Author: Jeffery
- Created at : 2026-09-05 16:07:00
- Updated at : 2026-09-06 07:11:38
- Link: https://redefine.ohevan.com/2026/09/05/float64科学计数法/
- License: This work is licensed under CC BY-NC-SA 4.0.