4.6.1浮点加减运算
浮点数的加减运算是计算机组成原理中的重点和难点,需遵循IEEE 754标准,具体步骤分为五个主要阶段。
1. 对阶(Exponent Alignment)
目的: 统一两个操作数的阶码,使其相等,以便尾数可以直接相加/减。
规则: 小阶向大阶对齐,通过右移小阶的尾数实现。右移时丢弃低位,可能引入舍入误差。
示例:
两个浮点数:
X
=
0.1101
×
2
5
X = 0.1101 \times 2^5
X=0.1101×25(阶码5),
Y
=
0.1010
×
2
3
Y = 0.1010 \times 2^3
Y=0.1010×23(阶码3)
- 阶差为5 Y ′ = 0.001010 × 2 5 Y' = 0.001010 \times 2^5 Y′=0.001010×25
2. 尾数加减(Mantissa Arithmetic)
对阶后,直接对尾数执行加减操作(补码运算):
加法:
[
X
]
补
+
[
Y
]
补
[X]_{\text{补}} + [Y]_{\text{补}}
[X]补+[Y]补
减法:
[
X
]
补
+
[
−
Y
]
补
[X]_{\text{补}} + [-Y]_{\text{补}}
[X]补+[−Y]补
示例:
X
=
00.110
1
补
X = 00.1101_补
X=00.1101补,
Y
′
=
00.00101
0
补
Y' = 00.001010_补
Y′=00.001010补
X
+
Y
′
=
00.1101
+
00.001010
=
01.001110
X + Y' = 00.1101 + 00.001010 = 01.001110
X+Y′=00.1101+00.001010=01.001110(发生尾数上溢,需右规)
3. 规格化(Normalization)
左规(左移缩小): 若尾数为00.0xx...
或11.1xx...
,需左移直到最高位为有效数值。
右规(右移放大): 若尾数溢出(如01.xx...
或10.xx...
),需右移一次,阶码+1。
4. 舍入处理(Rounding)
舍入方法:
- 就近舍入(默认): 若舍去部分的值大于最低位权值的1/2,则进位。
- 强制置1(恒置1): 将最右有效位强制设为1。
- 截断法(朝向0): 直接丢弃多余位,但可能积累误差。
示例:
尾数右移后若丢弃位为101
(大于0.5),则需进行舍入。
5. 溢出判断(Overflow Check)
阶码溢出:
- 上溢: 阶码超过能表示的最大值(如单精度的127→结果±∞)。
- 下溢: 阶码低于最小值(如单精度的-126→舍入为0)。
完整流程图
示例计算
计算 0.5 + 0.25 0.5 + 0.25 0.5+0.25(单精度):
- 0. 5 ( 10 ) = 1.0 × 2 − 1 0.5_{(10)} = 1.0 \times 2^{-1} 0.5(10)=1.0×2−1(符号0,阶码126,尾数全0)
-
0.2
5
(
10
)
=
1.0
×
2
−
2
0.25_{(10)} = 1.0 \times 2^{-2}
0.25(10)=1.0×2−2(符号0,阶码125,尾数全0)
步骤:
- 对阶:将0.25的阶码提升为 0.1 × 2 − 1 0.1 \times 2^{-1} 0.1×2−1
- 尾数加法: 1.0 + 0.1 = 1.1 1.0 + 0.1 = 1.1 1.0+0.1=1.1(无需规格化)
- 结果: 1.1 × 2 − 1 = 0.7 5 ( 10 ) 1.1 \times 2^{-1} = 0.75_{(10)} 1.1×2−1=0.75(10)
常见问题
Q1:为什么选择小阶对齐大阶?
- 减少精度损失: 大阶对齐小阶需要大幅右移尾数,导致更多有效位丢失。
Q2:如何避免精度误差?
- 扩展精度(保护位): 在对阶和计算时保留额外位数,最后舍入。
- 使用高精度库(如BigDecimal): 用整数模拟小数运算。
4.6.2浮点乘除运算
浮点数的乘除运算相比加减运算更为复杂,主要涉及符号位处理、阶码运算、尾数操作、规格化和舍入等步骤。
一、浮点乘法运算
流程图
详细步骤
-
符号位处理
结果的符号位由操作数的符号位异或决定:
S = S 1 ⊕ S 2 S = S_1 \oplus S_2 S=S1⊕S2。 -
阶码相加
浮点数的实际指数为 E A = Exp 1 − Bias E_{\text{A}} = \text{Exp}_1 - \text{Bias} EA=Exp1−Bias 和 E B = Exp 2 − Bias E_{\text{B}} = \text{Exp}_2 - \text{Bias} EB=Exp2−Bias。
乘积的阶码为:
Exp result = ( Exp 1 + Exp 2 ) − Bias \text{Exp}_{\text{result}} = (\text{Exp}_1 + \text{Exp}_2) - \text{Bias} Expresult=(Exp1+Exp2)−Bias。- 特殊值处理:若结果为无穷大、零或 NaN,直接返回对应结果。
-
尾数相乘
- 隐含位的还原:IEEE 754 的尾数为
1.M
形式(隐藏前导 1)。 - 定点乘法:
Mantissa result = ( 1. M 1 ) × ( 1. M 2 ) \text{Mantissa}_{\text{result}} = (1.M_1) \times (1.M_2) Mantissaresult=(1.M1)×(1.M2)。
使用定点数乘法(如布斯算法)计算结果。
示例:
1.10 1 2 × 1.01 1 2 = 10.01111 1 2 1.101_2 \times 1.011_2 = 10.011111_2 1.1012×1.0112=10.0111112。
若结果超过1.xxx
,需右移一位并调整阶码:10.011111 → 右移 → 1.0011111(当前阶码 +1)
- 隐含位的还原:IEEE 754 的尾数为
-
规格化尾数
- 若尾数最高位为
2 ≤ 尾数 < 4
,右移一位,阶码加 1。 - 若尾数 < 1(因舍入导致),左移一位,阶码减 1。
- 若尾数最高位为
-
舍入处理
- 舍入模式(IEEE 754):就近舍入(四舍五入)、向零、向下、向上舍入等。
- 例如:保留 23 位尾数时,根据第 24 位的值决定是否进位。
-
溢出处理
- 阶码上溢(超过最大值 2 k − 1 2^k - 1 2k−1):结果为无穷大。
- 阶码下溢(低于最小值):结果为非规格化数或零。
二、浮点除法运算
流程图
详细步骤
-
符号位处理
S = S 1 ⊕ S 2 S = S_1 \oplus S_2 S=S1⊕S2。 -
阶码相减
商的阶码为:
Exp result = ( Exp 1 − Exp 2 ) + Bias \text{Exp}_{\text{result}} = (\text{Exp}_1 - \text{Exp}_2) + \text{Bias} Expresult=(Exp1−Exp2)+Bias。 -
尾数相除
- 隐含位的还原:尾数视为
1.M
格式。 - 定点除法:
Mantissa result = ( 1. M 1 ) / ( 1. M 2 ) \text{Mantissa}_{\text{result}} = (1.M_1) / (1.M_2) Mantissaresult=(1.M1)/(1.M2)。
示例:
1.10 1 2 ÷ 1.01 1 2 = 1.00011 1 2 1.101_2 ÷ 1.011_2 = 1.000111_2 1.1012÷1.0112=1.0001112。
若商 < 1,左移一位,阶码减 1:0.1001 → 左移 → 1.001(当前阶码 -1)
- 隐含位的还原:尾数视为
-
规格化尾数
- 确保尾数为
1.xxx
形式,必要时左移或右移。
- 确保尾数为
-
舍入处理
- 规则同乘法运算。
-
溢出处理
- 除数为零时,结果为无穷大(满足被除数 ≠ 0)。
- 被除数与除数均为零时,结果为 NaN。
三、示例演示
浮点乘法示例
输入:
A
=
1.
5
10
A = 1.5_{10}
A=1.510(单精度:符号 0,阶码 127
B
=
2.
0
10
B = 2.0_{10}
B=2.010(单精度:符号 0,阶码 10000000,尾数 000…0)
步骤:
- 符号位异或 → 0 ⊕ 0 = 0。
- 阶码相加:01111110 + 10000000 = 11111110,减 127 → 实际指数 = (127-1) + 127 -127 = 126.
- 尾数相乘:1.100…0 × 1.000…0 = 10.000…0 → 右移 → 1.000…0 → 阶码 +1,最终阶码 128。
- 结果: 1.00 0 2 × 2 128 − 127 = 3. 0 10 1.000_2 \times 2^{128-127} = 3.0_{10} 1.0002×2128−127=3.010。
浮点除法示例
输入:
A
=
4.
0
10
A = 4.0_{10}
A=4.010,
B
=
2.
0
10
B = 2.0_{10}
B=2.010。
步骤:
- 符号位异或 → 0。
- 阶码相减:10000001 - 10000000 + 127 = 128。
- 尾数相除:1.000…0 ÷ 1.000…0 = 1.000…0。
- 结果: 1.00 0 2 × 2 128 − 127 = 2. 0 10 1.000_2 \times 2^{128-127} = 2.0_{10} 1.0002×2128−127=2.010。
四、关键问题总结
- 规格化:必须保证尾数形式为
1.xxx
,必要时调整阶码。 - 舍入影响:可能引发二次规格化(如舍入导致尾数溢出)。
- 异常处理:检测 NaN、无穷大、零等特殊值。
浮点数的乘除运算能够高效处理复杂数值运算,兼顾精度和范围。
4.6.3浮点运算器的实现
浮点运算器的设计与实现是计算机组成原理中的核心内容,支持浮点数的加、减、乘、除等运算。
一、浮点数的IEEE 754标准表示
单精度浮点数(32位)格式如下:
| 1位 | 8位 | 23位 |
|-----|-------|----------|
| S | 阶码E | 尾数M |
- S:符号位(0表示正,1表示负)。
- E:阶码(移码表示,实际指数为
E - 127
)。 - M:尾数(隐含最高位1,实际值为
1.M
)。
二、浮点运算的通用流程
浮点运算需实现对阶、尾数运算、规格化、舍入、溢出判断五个步骤。以加法为例:
-
对阶(Alignment)
- 比较两数的阶码,较小阶码的尾数右移,直至阶码相等。
- 例如:
x = 1.011×2^3
和y = 1.110×2^1
,对齐后y
的尾数右移2位,变为0.0111×2^3
。
-
尾数运算(Fraction Operation)
- 对调整后的尾数进行加减乘除运算。
- 例如:加法结果为
1.011 + 0.0111 = 1.1101
。
-
规格化(Normalization)
- 左规:若尾数首位为0,左移直至首位为1,并减少阶码。
- 右规:若结果尾数溢出(如
>=2.0
),右移并增加阶码。
-
舍入(Rounding)
- 根据保护位(Guard bit)和舍入模式(如“就近舍入”)调整尾数。
-
溢出处理(Overflow Handling)
- 若阶码超出表示范围(
E > 255
或E < 0
),触发溢出异常。
- 若阶码超出表示范围(
三、硬件模块组成
以下为浮点运算器的典型架构:
-
拆分模块
- 分离符号、阶码、尾数,并将尾数补回隐含的1(如
1.M
)。
- 分离符号、阶码、尾数,并将尾数补回隐含的1(如
-
阶码比较与对齐逻辑
- 计算阶差,控制移位器调整尾数。
- 计算阶差,控制移位器调整尾数。
-
尾数运算单元
- 包含加法器、乘法器等,执行实际运算。
-
规格化模块
- 检测尾数的首位是否为1,控制移位方向。
-
舍入单元
- 根据保护位和舍入规则(如就近舍入)修改尾数。
-
阶码调整与溢出检测
- 更新阶码并判断是否超出上下限。
四、关键设计挑战
- 精度损失控制
- 对阶和移位可能导致低位丢失,需保留保护位(Guard Bit)、舍入位(Round Bit)。
- 流水线优化
- 使用流水线技术提高吞吐量(如分离对阶、运算、规格化阶段)。
- 异常处理
- 处理器需支持溢出(Infinity)、非数(NaN)等特殊值的生成。
五、总结
浮点运算器通过对阶、尾数运算、规格化、舍入等步骤实现高精度运算,硬件上依赖专用加法器、移位器和控制逻辑。IEEE 754标准是设计基础,而具体实现需平衡速度、精度与复杂度。