浮点数的表示
IEEE 754 二进制浮点数由符号位、阶码和尾数字段组成。以单精度 float32 为例:
S(符号位,1 位) | E(阶码,8 位) | F(尾数的小数部分,23 位)
对于规格化数,阶码 满足 ,其数值为:
其中, 是存储的偏置阶码, 才是真实指数; 中的最高位 1 是隐藏位,不实际存入尾数字段。因此,float32 规格化数有 24 位二进制有效数字。
| 格式 | 符号位 | 阶码位数 | 小数位数 | 偏置值(bias) | 规格化数的有效位数 |
|---|---|---|---|---|---|
float32 |
1 | 8 | 23 | 127 | 24 |
float64 |
1 | 11 | 52 | 1023 | 53 |
隐藏位为 1 的规则只适用于规格化数。 非规格化数(subnormal)的尾数为 ,用于表示接近零的极小数。格式说明
加减运算流程
重点:对阶 → 尾数加减 → 规格化 → 舍入 → 检查溢出与特殊情况。
减法可以统一理解为 。将减法转为加法、完成对阶后:
- 同号: 尾数相加,保留共同的符号。
- 异号: 尾数的绝对值相减,非零结果的符号由绝对值较大的操作数决定。
- 完全抵消: 结果为零,其符号按 IEEE 754 的有符号零规则处理。
1. 对阶
小指数向大指数对齐: 将指数较小的数的尾数右移,移动位数等于指数差,同时增大其指数,保持数值不变。
例如,将 与 对阶:
于是,两个尾数变成同一指数下的 和 。
对阶时应保留足够的辅助信息供后续舍入使用。由于最终可保存的位数有限,较小数的贡献仍可能在舍入后消失,出现“大数吃小数”。
2. 尾数加减
对阶完成后,按符号进行二进制尾数运算。例如:
减法可能使高位抵消,例如:
后者尚未规格化,需要继续调整尾数与指数。
3. 规格化
非零规格化数应写成 的形式。
| 情况 | 操作 | 示例 |
|---|---|---|
尾数出现进位,整数部分为 10 或 11 |
尾数右移一位,指数加 1 | |
尾数非零,但整数部分为 0 |
尾数左移,每移一位,指数减 1 |
左移时若达到最小规格化指数仍无法得到前导 1,应按非规格化数处理;结果为零时不再尝试规格化。
4. 舍入
尾数位数有限,超出目标精度的部分需要按舍入规则处理。为正确判断舍入方向,运算中常保留 GRS 位:
| 辅助位 | 含义 |
|---|---|
| G:Guard bit,保护位 | 最低保留位之后的第一位 |
| R:Round bit,舍入位 | G 之后的第二位 |
| S:Sticky bit,粘滞位 | R 之后所有位的逻辑或;只要其中有一个 1,S 就为 1 |
这里的 S 是粘滞位,与浮点数格式中的符号位 S 含义不同。
例如:
保留部分 | G | R | 后续位
101101... | 1 | 0 | 001010...
后续位中存在 1,所以粘滞位为 1,最终 GRS = 101。
默认舍入方式:就近舍入,中间值取偶(round to nearest, ties to even)。 选择最接近精确结果的可表示数;若恰好位于两个可表示数的正中间,则选择最低保留位为 0 的那个数。
在这种舍入方式下,可根据 GRS 判断是否向保留部分加 1:
- GRS =
100: 刚好在中间,选择最低保留位为0的结果;原最低保留位为0时不进位,为1时进位。 - GRS 大于
100: 超过中间值,进位。 - GRS 小于
100: 未到中间值,不进位。
借用“只保留整数”的例子理解:
2.4 → 2 2.6 → 3
2.5 → 2 3.5 → 4
常见的其他舍入方式还有向 、向 和向 0 舍入。
舍入也可能使尾数产生进位,此时还要再做一次右规,并检查指数是否超出范围。
5. 检查溢出与特殊情况
- 上溢: 结果超出有限数的可表示范围时,根据符号和舍入模式得到无穷大或最大有限数。
- 极小结果: 可能表示为非规格化数,或舍入为零,不能一概直接置零。
- 特殊值: IEEE 754 还包含 、、、 和 NaN;它们应按特殊规则处理,例如 得到 NaN。
以上五步是理解普通有限数加减的主线;实际实现还会在运算前识别特殊值。
完整例子:1.5 + 0.75
先将十进制操作数写成二进制规格化形式:
- 对阶: 将 的尾数右移一位,得到 。
- 尾数相加: 。
- 规格化: 。
- 舍入与检查: 结果可以精确表示,无需改变尾数,也没有溢出。
因此:
常见精度问题
大数吃小数
较小数的尾数在对阶时右移;若其贡献不足以改变最终舍入结果,就可能出现:
很大的数 + 很小的数 = 很大的数
这与有限精度和舍入有关,并非数学上的相等。
灾难性消减
两个非常接近的数相减,高位有效数字会大量抵消。例如, 的精确差值只有 。
若操作数已带有表示误差或先前运算的舍入误差,这些误差可能在差值中占据很大比例,使结果的相对误差显著放大。 因此,相近数相减并不一定产生新的舍入误差,关键是抵消后暴露了已有误差。消减误差说明
加法不一定满足结合律
每一步运算都可能舍入,因此,浮点运算中的 与 不保证相等,改变计算顺序可能改变最终结果。
补充:数组对齐
常规数组的自然对齐要求由数组元素的类型决定,不由数组长度决定。