解答:
(1) 乘法运算可以通过加法和移位来实现。编译器可以将乘法运算转换为一个循环代码段,
在循环代码段中通过比较、加法和移位等指令实现乘法运算。例如Booth乘法。
(2) 控制逻辑的作用是控制循环次数,控制加法和移位操作。
C语言整型用补码表示,通常采用Booth乘法。
Booth乘法对乘数从低位开始判断,根据两个数据位的情况决定进行加法、减法还是仅仅移位操作。判断的两个数据位为当前位及其右边的位(初始时需要增加一个辅助位0),移位操作是向右移动。其中booth算法在操作时,需要遵循一个操作表:
具体步骤如下:
被乘数X与乘数Y均以补码的形式参加乘法运算,运算结果是积的补码。部分积和被乘数X采用双符号位,乘数Y采用单符号位。初始部分积为0。运算前,在乘数Y的补码末位添加一位附加位 Yn+1 ,初始值为0。根据 YnYn+1 的值,按照上表进行累加右移操作,右移时遵循补码的移位规则。累加n+1次,右移n次,最后一次不右移。这个过程累加n+1次,右移n次,所以控制逻辑的作用是控制循环次数,还需要根据操作表控制加法和移位操作。
(3) ①的执行时间最长,③的执行时间最短。
对于①,需要使用其他指令和算法来模拟乘法操作。常见的方法是通过编写(软件)程序使用加法、位移和逻辑操作来实现乘法功能。这种方法通常需要多条指令和多个时钟周期来完成乘法运算,因此会比硬件乘法指令的执行时间更长。②和③都是硬件乘法指令,所以①的执行时间最长。
对于②和③,都只需用一条乘法指令实现乘法操作。
对于③,阵列乘法器是专门用于执行乘法操作的硬件电路,可以在一个时钟周期内完成乘法运算。由于其硬件实现的特性,阵列乘法器通常是执行乘法操作最高效的方式。所以③的执行时间最短。
对于②,ALU和位移器实现的乘法指令通常需要多个时钟周期来完成乘法运算。它通过将乘法操作划分为一系列的加法、位移和逻辑操作来实现。尽管比情况①中的方法更高效,但仍然需要多个时钟周期来执行,因此相对于情况③中的阵列乘法器,执行时间较长。
(4) 第一问。当n=32、x= 2^31−1 、y=2时,64位的[x]补=0000 0000 0000 0000 0000 0000 0000 0000 0111 1111 1111 1111 1111 1111 1111 11111B,y=2,x×y相当于对x进行算术左移1位,得到[x×y]补=0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 1111 1111 1111 1111 1111 11110B=00000000FFFFFFFEH。
第二问。此时函数umul()不溢出,imul()的返回结果溢出,因为umul()的返回值类型为unsigned,默认为unsigned int,为32位无符号整型,可以表示32个数值位,结果恰有32个有效数值位,所以其返回结果不溢出。然而imul()返回值类型为int,为32位有符号整型,最高位为符号位,可以表示31个数值位,结果有32个有效数值位,所以其返回结果溢出。
第三问。对于无符号整数乘法运算,当仅取乘积的低位作为乘法结果时,对于2n位乘积,若乘积高n位全为0,即乘积高n位不存在有效数值位,则无溢出,否则溢出。