☰
乘法器和除法器
2026/10/2 2:32:50 网站建设 项目流程

引言

本篇文章主要是关于《计算机组成原理》的乘法和除法运算的底层进行细节展开,相比于考研的内容,底层的实现可能会更加全面一些。

乘法器

两个数相乘我们在小学的时候就利用竖式进行计算,所以在我们无符号数的时候,我们的计算方式也是一样的。但是对于计算机,底层的实现并不是和我们人的想法一样。

我们的乘数的当前这一位如果是1,那么我们就把被乘数抄过去,如果是0,那么就全部补0,但是我们还必须要实现这个错位的加法,这个其实就是将被乘数左移,这个样子就多了一个0

那我们应该怎么取出乘数的最低一位呢?其实也是比较简单的,将乘数左移以为,然后和1进行按位与,这个样子就可以取出来了。我们看一下完整的操作过程。

这里我们先不考虑符号的问题,我们先讨论无符号数的乘法。

我们在最原始的版本里面,有三个寄存器,这三个寄存器分别存储被乘数,乘数,乘积。我们整个操作的循环一共是m次(乘数的位数)。

在一开始,我们必须要进行初始化操作,乘积全部初始化为0

我们先取出乘数的第一位,然后进入控制测试,如果这个值是0,我们的被乘数左移一位(目的是错位对齐),乘数向右移动一位(目的是取出下一位),然后进行下一轮。如果这个乘数的最低位取出来的是1,那么进入控制测试之后就会被传递到ALU中,然后被乘数也会被传送到ALU中,与乘积进行加法运算,算完的结果直接写入乘积里面(这个步骤的前提是把写使能拉高),方便下一次的运算,然后将被乘数向左移动一位,乘数向右移动一位。

这个就是一个完整的乘法器过程。

接下来我们需要讨论一下原码的乘法运算,这个也比较的简单,我们发现同号为0,异号为1,那不就是异或嘛~~~所以我们单独计算符号那一位,剩余的数值位我们还是和之前一样计算。

但是这个底层的模型并不是最好的,我们还可以减少寄存器的使用,我们的被乘数利用一个寄存器,而乘积和乘数使用同一个寄存器,但是这个寄存器是64位的,这个样子才可以同时存下乘积和乘数。这个模型里面乘数不需要向左移动,我们之前被乘数之所以需要向左移动,是因为我们需要在末尾补0,从而实现错位的相加,这个最后体现在的是乘积结果上,而我们这一次不移动被乘数,而是向右移动乘积,可以理解为一个相对运动,相当于把最后的结果加在了正确的位置。

我们的乘积是分成两个部分,左边的32位是乘积,右边的32位是乘数,而且每一次我们取相应的部分都只取对应的32位,即使是经过了移动,因为我们移动过去的部分之后不会参与运算,当循环结束之后,在乘积里面的数就是我们需要的数。

然后我们要考虑补码的运算,在补码的运算里面,我们所有的运算数都要转化为补码,符号位也需要参与运算,在运算过程中需要考虑符号位乘上被乘数之后的部分积是正数还是负数,最后我们得到的结果也是补码。所以有4种情况:

正数 * 正数 :和无符号一样

正数 * 负数:乘数是负数,那么我们一定要注意乘数的符号位是1,那么这个时候要进行符号扩展用1

负数 * 正数:因为被乘数是负数,所以这一次我们符号扩展的时候无论如何都是补1

负数 * 负数:我们之前一直都强调的是乘数的符号位参与运算才会补1,所以只有在乘数的符号位最后参与运算的时候才会负负得正,也就是补0,其他的情况下还是要符号扩展1

除法器

我们依然按照之前小学的方法进行除法运算,但是如果是计算机怎么模拟这一个过程呢?这一整个过程循环 (被除数位数 - 除数位数 + 1)次。

首先是除数和被除数的位数对齐,然后我们每一次是否上1,取决于被除数和除数的大小,计算机在判断大小的时候做的是减法运算,如果结果大于0,那么我们就记录下减后的余数,这个余数会参与下一次的运算,商 + 1;如果结果小于0,那么我们就把这个数重新加回去,商 + 0。这一个过程结束之后,我们的商向左移动一位,除数向右移动一位,那我们这里会担心会不会除数向右移动导致除数的1被移除了。这个不用担心,因为我们一开始进行了对齐的操作,也就是相当于给除数扩大了2^n倍,而在左移的过程中也就是把这些扩大的位数全部移除了,而扩大多少倍,这个和循环的次数一样,也是m - n + 1倍。

其实比较难理解的就是除数对齐和右移,这个可能和我们人类运算的方式有些不一样,因为计算机的计算底层就是比较,所以我们必须要从最高位开始比较,那为什么可以保证不会把除数的有效的1移出去呢?原因就是当执行到最后一位的时候,如果这个时候商0,说明余数比真实,没有扩大的除数已经要小了,所以这也就是我们得到的余数,而如果商1,那剩下的那个余数一定比我们的除数要小。

那么我们的内部实现还是这一个图,首先除数和商还有余数分别用一个寄存器存储,在上面的过程中我们也发现了,被除数其实就是余数

在开始之前,我们需要初始化每一个寄存器,

然后我们每一轮,先把余数寄存器里面的内容和除数寄存器里面的内容放在ALU里面相减,然后放在余数寄存器里面,如果次数余数寄存器里面的数大于0,进入控制测试,让商 + 1,然后左移一位,除数右移一位,如果小于0,进入控制测试,让商 + 0,然后左移,同时将余数加回去,除数右移一位,最后重复 m - n + 1次。

当然除法器可以进行进一步的优化,余数和商可以放在同一个寄存器里面,因为我们的余数其实最高位每一次经过运算之后就不再有用了,当左移的时候被丢弃不会影响结果,反而因为相对的运动,除数不需要向右移动了。

有符号原码运算和乘法一样,符号位通过异或的操作可以确定。

补码的运算相对于比较的难,其中难点主要在于相减的操作,因为涉及到了正数和负数的减法。因为我们判断商是不是1,其实方法是统一的,就是看两个数的绝对值谁大,所以我们这里就需要调整比较的方法了

符号参与运算,除数和被除数,余数和商均用补码表示。符号拓展。

如果是正数除以正数,这个和刚才说明的一模一样

如果是正数除以负数(15/-9),我们在相减的时候应该抛弃符号的影响,因为我们需要知道的是15和9谁更大,这里到底商是不是1,所以我们这里计算的是15 + (-9),如果结果是0那么就说明商是1,如果不是就商是0。

如果是负数除以正数,相当于是(-15)+ 9,如果结果是正数说明不够减,除数更大,如果是负数说明被除数更大,商是1。

如果是负数除以负数,相当于是(-15)- (-9),如果结果是正数说明是不够减,如果是负数说明够减。

总的来说,无论是变成加法还是减法,我们最后的结果只要和被除数同号,那么就可以商1,因为证明的是被除数更大。

但是在计算的过程里面,我们一定要注意的:我们的余数和商并不是都是补码,如果是异号相除,那么我们得到的其实是原码,因为我们初始化的时候全部初始化为0,但是异号相除结果一定是负数,所以我们最后的结果还需要求其补码,否则得到的就是原码。

总结

本篇文章到这里就结束了!!!希望可以帮助大家理解~~~~

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询