**要点速览:**对于普通二进制数值,IEEE 754 使用 :一个符号位、偏置指数,以及带隐含前导 1 的尾随有效数字段。保留的指数模式编码带符号零、次正规数、无穷大与 NaN。由于大多数精确实数结果都必须舍入到有限格式,浮点加法与乘法通常不满足结合律。
当范围与缩放比例已知时,定点二进制很好用;当一次计算必须覆盖相差许多个数量级的数值时,它就会变得不方便。例如,带 16 个小数位的有符号 32 位定点数,步长为 ,范围大约是 到 。
浮点表示把部分比特分配给指数,让基数点随数值大小移动。IEEE 754 于 1985 年首次发布,当前有效修订版为 IEEE 754-2019。标准定义了二进制与十进制格式、运算、舍入、异常及交换行为。实现可以采用硬件、软件或两者结合,因此符合标准并不表示每颗 CPU 都在硅片中实现每一种格式。
为什么需要浮点数?
科学记数法在纸上解决同一问题: 把较小的有效数字与较大的指数分开。IEEE 754 就是具有严格规则的二进制科学记数法,规定每个部分获得多少比特,以及如何编码。
格式由两项设计压力塑造:
- **规定的编码与运算。**数学数值与位模式并非一一对应:零有两个符号,NaN 则有许多载荷编码。标准规定运算与比较如何处理它们。
- **可实现的算术。**指数比较与有效数字对齐必须映射到有限的硬件或软件算法,并具有明确的舍入与异常行为。
为同时满足两者而作出的权衡——偏置指数、隐含前导位、特殊用途指数码——赋予 IEEE 754 独特的形状。
单精度布局(32 位)
| 31 | 30 ............ 23 | 22 ........................... 0 |
| s | e (8 bits) | m (23 bits) |
| 1 | | |
- 符号位 :1 位。0 表示非负,1 表示负。
- 指数 :8 位,以无符号整数形式存储,偏置为 127。
- 尾随有效数字段 :23 位。对于正规数,它存储隐含前导 1 之后的小数部分。
对于规格化数(最常见情况),数值为:
有效数字中的“”是隐含的——每一个规格化二进制数都能通过选择指数写成前导位为 1 的形式,因此格式可以省下一位。
双精度布局(64 位)
结构相同,但字段更宽:
| 63 | 62 ........... 52 | 51 ............................. 0 |
| s | e (11 bits) | m (52 bits) |
- 符号位 :1 位。
- 指数 :11 位,偏置为 1023。
- 尾随有效数字段 :52 位。
数值(规格化):
范围约为 ,并具有约 15–17 位有效十进制数字。
为什么指数要加偏置?
把指数存为 而不是二进制补码,有一项微妙但重要的好处:浮点比较可以归约为对位模式进行整数比较(并翻转符号位)。如果把两个非负浮点数视作 32 位无符号整数,较大的浮点数也对应较大的整数。二进制补码指数会在正负指数边界上破坏这种单调关系。
全零指数段保留给零与次正规数,全 1 指数段保留给无穷大与 NaN。对于 binary32,普通指数段 1 到 254 对应无偏指数 到 。
特殊情况
| 指数位 | 尾随有效数字位 | 含义 |
|---|---|---|
| 全零 | 全零 | (由符号位决定) |
| 全零 | 非零 | 次正规数 |
| 中间任意值 | 任意值 | 规格化数 |
| 全 1 | 全零 | |
| 全 1 | 非零 | NaN(非数) |
零有两种编码( 与 )。在 IEEE 比较中两者相等,但某些运算会产生不同的带符号结果,例如 、。
次正规数(历史上也称非规格化数)填补零与最小正规数之间的空隙。隐含前导 1 变为 0,binary32 使用有效指数 。这实现渐进下溢:次正规范围内的绝对间距保持恒定,而相对精度在接近零时逐渐下降。
无穷大来自溢出或除以零。它按直观方式在算术中传播:,。
NaN表示无效运算:、、。NaN 具有传染性——任何包含 NaN 的算术都得到 NaN。关键是,在 IEEE 754 比较中 ,所以测试套件使用 isnan(),而不是 ==。
解码示例:0x40490FDB
这是一个著名的 32 位常数。写成二进制:
0x40490FDB = 0100 0000 0100 1001 0000 1111 1101 1011
分割字段:
- 符号:
0——正数 - 指数:
1000 0000= ——实际指数 - 尾随有效数字:
100 1001 0000 1111 1101 1011
有效数字为 ,即:
计算存储的小数部分:
因此有效数字为 ,乘以 :
这就是单精度下的 。常数 0x40490FDB 是 的经典 IEEE 754 单精度编码,广泛出现在数值库、GPU 着色器与世界各地的考试题中。
编码示例:5.75
把 转换为单精度 IEEE 754。
第 1 步:转换为二进制。。。合在一起:。
**第 2 步:规格化。**把二进制点向左移动,直到左侧恰好只剩一位:
因此实际指数为 。
第 3 步:编码各字段。
- 符号:正数,所以 。
- 指数:实际值 加偏置 得 ,也就是
1000 0001。 - 尾随有效数字:删除前导 1,存储接下来的 23 位:
0111后跟 19 个零,即01110000 00000000 0000000。
第 4 步:组装。
0 | 10000001 | 01110000000000000000000
十六进制为 0x40B80000。反向执行解码过程,可以验证该模式准确恢复 5.75。
注意,5.75 具有精确二进制表示——其小数部分是二的负幂之和()。大多数十进制小数并非如此。单精度下, 是 0x3DCCCCCD,解码回来约为 ,误差约为 。这个微小误差就是初学者每次遇到“”惊讶的根源。
舍入方向
IEEE 754-2019 规定五种舍入方向属性:
- 舍入到最近值,中间值取偶数(默认)。选择较接近的可表示值;恰好位于中间时,选择有效数字最低位为 0 的值。
- **舍入到最近值,中间值远离零。**该属性尤其与十进制算术相关,并非每个二进制浮点环境都会暴露它。
- 向零舍入(截断)。
- 向 舍入(上取整)。
- 向 舍入(下取整)。
默认模式可以减小统计偏差——直接“逢半向上”会在累积大量数值时引入轻微向上偏差,而逢半取偶能够将其平均掉。
应用能够选择哪些方向,取决于语言、运行时、编译器与硬件环境。可复现性还取决于求值顺序、中间精度、融合运算、库函数与次正规数处理,而不仅是选定的舍入方向。
浮点算术为什么不满足结合律
考虑三个 IEEE 754 单精度值:。
:先算 ,结果精确(抵消干净);再算 。最终结果为 。
:先算 。 的指数约为 67, 的指数为 0。对齐有效数字会把 移到远超 binary32 精度的位置。舍入后 ,随后 。
两种加括号方式产生不同答案,因此浮点加法不满足结合律。编译器是否可以重新结合表达式,取决于语言规则、实现、优化标志与浮点环境。对可复现性敏感的代码应记录这些选择并测试实际工具链,而不是把某一个编译器标志当成通用保证。
同样的性质也适用于减法(抵消情况)、乘法(极小乘积可能下溢到零)与除法(除以极小数可能溢出为无穷大)。
硬件:FPU
硬件浮点加法器通常执行如下阶段;没有 FPU 的处理器可以用软件实现相同语义:
- 解码两个操作数的字段。
- 比较指数;把指数较小的有效数字按差值右移,并保留保护位、舍入位与粘滞位用于舍入。
- 对齐后执行有效数字加减(使用宽超前进位风格加法器)。
- 左移结果直到出现前导 1,完成规格化,并相应调整指数。
- 按当前舍入模式舍入。
- 把结果编码为 IEEE 754 格式。
数据通路需要指数比较、有效数字对齐、加/减逻辑、前导零检测、规格化、舍入、特殊情况处理与异常报告。RISC-V 的 F 扩展定义 binary32 指令,D 则增加 binary64;两者都是可选扩展,说明标准格式与强制硬件之间存在区别。
有效数字路径会复用二进制算术技术,但 FPU 不只是加了额外管线的整数 ALU:舍入、渐进下溢、NaN、无穷大、带符号零与异常都是其体系结构行为的一部分。
更宽格式
除单精度与双精度外,IEEE 754 还定义:
- 半精度(binary16):1 位符号 + 5 位指数 + 10 位尾随有效数字。用于图形与降低精度的数值工作负载。
- 四倍精度(128 位):1 + 15 + 112。较少使用,主要用于数值分析与某些金融计算。
- bfloat16(不是 IEEE 754 基本交换格式):1 + 8 + 7。它保留类似 binary32 的指数范围,但精度低得多,广泛用于机器学习。
每种变体都针对目标工作负载,在范围与精度之间作出权衡。
常见陷阱
- **没有错误模型就使用
==。**对某些不变量与离散值,精确比较完全正确;近似结果则需要领域相关的绝对/相对容差或末位单位策略。 - **忘记
NaN != NaN。**使用isnan()检测 NaN。 - **假定结合律成立。**重新排列求和会改变答案。编译器标志可能允许不安全的重新结合,使用前必须理解其含义。
- 混淆十进制与二进制直觉。 没有有限的精确二进制表示。对于十进制业务规则,可考虑缩放整数、十进制浮点或 BCD,并仍需定义每一个必要边界上的舍入。
- **假定次正规数性能。**有些处理器可以全速处理次正规数,另一些会有性能损失或支持刷新为零模式。应测量目标系统,并在正确性需要时保留渐进下溢。
连接到更广的 CPU 架构
寄存器组织取决于 ISA。有些架构使用分离的整数与浮点寄存器文件,另一些则让部分状态重叠或统一。加载、存储、转换、移动与调用约定共同定义边界。
对于更宽的算术,整数侧依赖与 8 位加法器相关的结构,并按目标规模与优化;浮点侧则加入对齐、规格化、舍入、异常与特殊值处理。
下一步
继续阅读二进制补码详解,理解定宽有符号整数;随后阅读 BCD:二进制编码十进制基础,理解面向数字位的十进制编码。
要在位级进行实验,可使用 ALU 风格的数据通路完成有效数字算术,再把对齐、规格化、保护/舍入/粘滞位与特殊情况分别建模为独立阶段。
规范性参考是当前有效的 IEEE 754-2019 浮点算术标准。
