Integer Multiplication And Division
乘法
乘法运算常见有三类实现方式:
| 实现方式 | 基本思路 |
|---|---|
| 迭代式乘法器 | 复用同一个 ALU 和寄存器,每轮根据乘数位决定加、减或不操作,再移位。若一次ALU加法和一次移位各需要一个时钟周期,则对于$n$位乘法需要$2n$个时钟周期 |
| 阵列乘法器 | 用大量并行硬件同时生成并累加部分积,可在一个时钟周期内完成一次乘法运算。速度最快但硬件开销大。 |
| 移位-加减法 | 从算法层面把乘法转化为移位、加法、减法,硬件成本最低但速度最慢 |
下面介绍的即迭代式乘法器
无符号乘法
乘法过程可以用三个核心寄存器理解:
| 寄存器 | 作用 |
|---|---|
ACC |
保存部分积的高位,也参与加法 |
MQ |
初始保存乘数,运算结束后保存乘积低位 |
X |
保存被乘数 |
ACC 和 MQ 常连在一起看作一个双倍位宽寄存器:
1 | ACC | MQ |
乘法的核心动作是:
- 看
MQ的最低位。 - 若最低位为
1,则ACC = ACC + X。 - 若最低位为
0,则ACC不变。 - 将
ACC | MQ整体右移一位。 - 重复 n 次后,
ACC | MQ中保存完整乘积。
Note
若 ACC + X 产生进位,进位也要参与后续右移。
若两个 n bit 无符号整数相乘,完整乘积最多需要 2n bit 表示。
例如两个 8 bit 无符号整数:
$$
255 \times 255 = 65025
$$
这个结果需要 16 bit 才能完整保存。
乘积位数
n bit 与 n bit 相乘,结果不一定还能放进 n bit。若只保留低 n bit,高位会被截断。
有符号整数使用Booth 算法直接处理补码乘法。
每轮 Booth 乘法的核心流程是:
- 查看 Y当前的最低位$Y_{0}$与其右边的 $Y_{-1}$(上一轮移出去的$Y_{0}$,初始值为0)。
- 若为
01,则P = P + X。 - 若为
10,则P = P - X。 - 若为
00或11,则P不变。
- 若为
- 将
P | Y | Y-1整体算术右移一位。 - 重复 n 次后,
P | Y保存补码乘积。
引入$Y_{0}Y_{-1}$的思想是:把连续的一串 1 看成两个边界的差。
Example
Booth 算法为什么能处理有符号数
补码的符号位本来就有负权重。Booth 算法用“加一段的开始、减一段的结束”来重写乘数的权重展开,因此可以直接在补码位串上得到有符号乘积。
进入除法过程前,必须先做入口判定:
- 若除数为 0,除法无定义,引起除0异常,不能启动除法运算。
- 若 $|被除数| < |除数|$,商为 0、余数为被除数,直接结束。
只有这些情况都排除后,才需要进入逐位试减的除法过程。也就是恢复余数除法。
使用寄存器说明如下。
| 寄存器 | 作用 |
|---|---|
R |
保存当前部分余数,最后保存余数 |
Q |
初始保存被除数,运算过程中逐步形成商 |
Y |
保存除数 |
恢复余数除法的核心流程是:
- 将
R | Q整体左移一位。 - 试做
R = R - Y。- 若
R非负,说明够减,当前商位记1。 - 若
R为负,说明不够减,恢复原来的R,当前商位记0。
- 若
- 重复 n 次后,
Q中保存商,R中保存余数。
试减需要判断正负
恢复余数除法中,R - Y 的结果可能为负。为了判断是否够减常把 R 看成带符号或带扩展位的部分余数寄存器。
商溢出
商溢出发生在商形成或结果写回阶段。若最终得到的商无法放入目标商寄存器,就不能按正常结果写回,应触发商溢出异常。
以上是无符号数的除法的过程。
有符号除法一般先对绝对值做无符号除法,再根据操作数的符号恢复商和余数的符号,结果按补码保存。若结果超出补码可表示范围,也会发生商溢出;典型情况是 n bit 补码的最小负数除以 -1。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Elian's blog page!