目录

从零开始学习计算机科学计算机组成原理三数值的运算

【从零开始学习计算机科学】计算机组成原理(三)数值的运算

数值的运算

加减法

原码加/减法运算

加法规则:先判符号位,若相同,绝对值相加,结果符号不变; 若不同,则作减法, |大| - |小|,结果符号与|大|相同。 减法规则:两个原码表示的数相减,首先将减数符号取反,然后将被减数与符号取反后的减数按原码加法进行运算。

补码加法运算

补码加法的公式:[ x ]补码+ [ y ]补码= [ x + y ]补码(mod 2)。 其特点是不需要事先判断符号,符号位与码值位一起参加运算,并且符号位相加后若有进位,则舍去该进位数字。在模2意义下,任意两数的补码之和等于该两数之和的补码,这也是补码加法的理论基础。

补码减法运算

补码减法运算的公式:[ x - y ]补码 = [ x ]补码 - [ y ]补码 = [ x ]补码 + [ - y ]补码

加减法的溢出处理

在定点小数机器中,数的表示范围为|x|<1。在运算过程中如出现大于1的现象,称为 “溢出”。 两个正数相加,若结果大于机器所能表示的最大正数,称为上溢;两个负数相加,若结果小于机器所能表示的最小负数,称为下溢。

溢出的检测方法

单符号位法。其溢出逻辑表达式为: V = S 1 ‾ ⋅ S 2 ‾ ⋅ S c + S 1 ⋅ S 2 ⋅ S c ‾ V=\overline{S_1} · \overline{S_2} · S_c + S_1 · S_2 · \overline{S_c} V=S1​​⋅S2​​⋅Sc​+S1​⋅S2​⋅Sc​​。 双符号位法。一个符号位只能表示正、负两种情况,当产生溢出时,符号位的含义就会发生混乱。如果将符号位扩充为两位( S f 1 , S f 2 Sf_1,Sf_2 Sf1​,Sf2​),其所能表示的信息量将随之扩大,既能判别是否溢出,又能指出结果的符号。双符号位法也称为“变形补码”或“模4补码”。 变形补码为定义: [ x ] = { x , 0 ≤ x < 2 ( m o d 4 ) 4 + x , − 2 ≤ x < 0 ( m o d 4 ) [x]=\left\{ \begin{aligned} x &,0\leq x < 2 (mod 4)\\ 4+x &,-2 \leq x < 0 (mod 4) \end{aligned} \right. [x]={x4+x​,0≤x<2(mod4),−2≤x<0(mod4)​ 采用变形补码后数的表示为任何小于1的正数,两个符号位都是“0”,即 00 x 1 x 2 … x n 00.x_1 x_2 \ldots x_n 00.x1​x2​…xn​;任何大于-1的负数,两个符号位都是“1”,即 11 x 1 x 2 … x n 11.x_1 x_2 \ldots x_n 11.x1​x2​…xn​ 由补码的加法公式我们可以得到模4补码加法公式:[ x ]补码 + [ y ]补码 = [ x + y ]补码(mod 4)。即两数变形补码之和等于两数和的变形补码,其要求两个符号位都看做数码一样参加运算;两数进行以4为模的加法,即最高符号位上产生的进位要丢掉。 运算后双符号位的含义如下: S f 1 S f 2 Sf_1 Sf_2 Sf1​Sf2​=00,即结果为正数,无溢出; S f 1 S f 2 Sf_1 Sf_2 Sf1​Sf2​=01,即结果正溢; S f 1 S f 2 Sf_1 Sf_2 Sf1​Sf2​=10,即结果负溢; S f 1 S f 2 Sf_1 Sf_2 Sf1​Sf2​=11,即结果为负数,无溢出。 即结果的两个符号位的代码不一致时,表示溢出;两个符号位的代码一致时,表示没有溢出。不管溢出与否,最高符号位永远表示结果的正确符号。由此,我们可以得出溢出逻辑表达式为:V= S f 1 ⊕ S f 2 Sf_1\oplus Sf_2 Sf1​⊕Sf2​。其中 S f 1 Sf_1 Sf1​和 S f 2 Sf_2 Sf2​分别为最高符号位和第二符号位,此逻辑表达式可用异或门实现。 利用进位值的判别法 从以上分析中我们看到,当最高有效位有进位而符号位无进位时,产生上溢;当最高有效位无进位而符号位有进位时,产生下溢(简单地说是正数相加为负数或负数相加为正数则产生溢出)。故溢出逻辑表达式为:$V=Cf\oplus Co $。其中Cf为符号位产生的进位,Co为最高有效位产生的进位。此逻辑表达式也可用异或门实现。

一位全加器

一位加法运算定义为 A i + B i + C i = S i ( C i + 1 ) A_i+B_i+C_i=S_i (C_{i+1}) Ai​+Bi​+Ci​=Si​(Ci+1​),其中C为进位输入和进位输出。 通过逻辑代数运算,我们可以得到一位加法运算的逻辑方程 S i = A i ⊕ B i ⊕ C i S_i=A_i\oplus B_i \oplus C_i Si​=Ai​⊕Bi​⊕Ci​ C i + 1 = A i ⋅ B i + B i ⋅ C i + C i ⋅ A i C_{i+1}=A_i·B_i+B_i·C_i+C_i·A_i Ci+1​=Ai​⋅Bi​+Bi​⋅Ci​+Ci​⋅Ai​。 通过逻辑方程我们可以设计并实现一位全加器电路。 https://i-blog.csdnimg.cn/direct/4bb5f622bc954871969a23c130455680.png#pic_center https://i-blog.csdnimg.cn/direct/97e0efc73c5544d1bd1169f8313247c2.png#pic_center

N位加法器

由n个1位的全加器(FA)可级联成一个n位的行波进位加减器。 https://i-blog.csdnimg.cn/direct/92b72f8386c2470f92d55f38ffe5c6e5.png#pic_center 加法器的性能可以通过时间延迟来评估。我们假设T被定义为相应于单级逻辑电路的单位门延迟。一般T通常采用一个“与非”门或一个“或非”门的时间延迟来作为度量单位。典型门电路的延迟时间为:与非门、或非门和非门为T,与门和或门为2T,异或和异或非门为3T。 对一位全加器(FA)来说, S i S_i Si​的时间延迟为6T(每级异或门延迟3T); C i + 1 C_{i+1} Ci+1​的时间延迟为5T。 https://i-blog.csdnimg.cn/direct/b3057797f6d04a7a89dcc80bd56a0c46.png#pic_center 设n位行波进位加法器的延迟时间 t a t_a ta​,即 t a t_a ta​为在加法器的输入端输入加数和被加数后,在最坏的情况下加法器输出端得到稳定的求和输出所需要的最长时间。一般来说, t a t_a ta​越小越好。 考虑溢出检测时,有: t a = n ⋅ 2 T + 9 T = ( 2 n + 9 ) T t_a = n·2T+ 9T=(2n+9)T ta​=n⋅2T+9T=(2n+9)T。9T为最低位上的两极“异或”门再加上溢出“异或”门的总时间;2T为每级进位链的延迟时间。 当不考虑溢出检测时,有 t a = ( n − 1 ) ⋅ 2 T + 9 T t_a = (n-1)·2T+9T ta​=(n−1)⋅2T+9T。 我们可以看出,由一位全加器(FA)构成的行波进位加法器其具有串行进位、运算时间长、只能完成加法和减法两种操作而不能完成逻辑操作等特点。

多功能算术/逻辑运算单元(ALU)

一般的,ALU单元不仅具有多种算术运算和逻辑运算的功能,而且具有先行进位逻辑,从而能实现高速运算。 ALU单元可以通过将全加器的功能扩展以完成多种算术逻辑运算。 比如,我们可以将一位全加器的输入 A i A_i Ai​和 B i B_i Bi​先组合成由控制参数控制的组合函数 X i X_i Xi​和 Y i Y_i Yi​,然后再将 X i X_i Xi​, Y i Y_i Yi​和下一位进位数通过全加器进行全加。这样,不同的控制参数可以得到不同的组合函数,因而能够实现多种算术运算和逻辑运算。这样,我们就得到了一位ALU单元。 https://i-blog.csdnimg.cn/direct/41396cafd27641a3abca9ba9b8282747.png#pic_center 一位ALU单元可以按照一定关系组合为多为ALU单元,下图为4位ALU单元(74181ALU)。 https://i-blog.csdnimg.cn/direct/7b48bacbe1ab47f9b0326c6eb9499e25.png#pic_center 其中,G称为进位发生输出,P称为进位传送输出。在电路中多加这两个进位输出的目的,是为了便于实现多片。控制端M用来控制ALU进行算术运算还是进行逻辑运算。M=0时,M对进位信号没有任何影响。此时Fi 不仅与本位的被操作数 Y i Y_i Yi​ 和操作数 X i X_i Xi​有关,而且与向本位的进位值 C n + i C_{n+i} Cn+i​有关, 因此M=0时, 进行算术操作;M=1时,封锁了各位的进位输出, 即 C n + i = 0 C_{n+i}=0 Cn+i​=0,因此各位的运算结果 F i F_i Fi​仅与 Y i Y_i Yi​和 X i X_i Xi​有关, 故M=1时, 进行逻辑操作。 并且,为了提高运算速度,每个一位ALU单元之间采用了优先进位的方法。 并行加法器与并行ALU单元 影响加法器速度的关键因素是进位信号产生和传递的时间,所以要想提高加法器的速度,就必须尽可能的缩短进位时间,即改进进位方式。超前进位加法器的特点是各级进位信号同时产生,大大减少了进位产生的时间。其进位产生的逻辑表达式为: C 1 = G 1 + P 1 ⋅ C 0 C_1=G_1+P_1·C_0 C1​=G1​+P1​⋅C0​ C 2 = G 2 + P 2 ⋅ G 1 + P 2 ⋅ P 1 ⋅ C 0 C_2=G_2+P_2·G_1+P_2·P_1·C_0 C2​=G2​+P2​⋅G1​+P2​⋅P1​⋅C0​ C 3 = G 3 + P 3 ⋅ G 2 + P 3 ⋅ P 2 ⋅ G 0 + P 3 ⋅ P 2 ⋅ P 1 ⋅ C 0 C_3=G_3+P_3·G_2+P_3·P_2·G_0+P_3·P_2·P_1·C_0 C3​=G3​+P3​⋅G2​+P3​⋅P2​⋅G0​+P3​⋅P2​⋅P1​⋅C0​ C 4 = G 4 + P 4 ⋅ G 3 + P 4 ⋅ P 3 ⋅ G 2 + P 4 ⋅ P 3 ⋅ P 2 ⋅ G 1 + P 4 ⋅ P 3 ⋅ P 2 ⋅ P 1 ⋅ C 0 C_4=G_4+P_4·G_3+P_4·P_3·G_2+P_4·P_3·P_2·G_1+P_4·P_3·P_2·P_1·C_0 C4​=G4​+P4​⋅G3​+P4​⋅P3​⋅G2​+P4​⋅P3​⋅P2​⋅G1​+P4​⋅P3​⋅P2​⋅P1​⋅C0​ ⋯ \cdots ⋯ 从上面的表达式可知:所有各位的进位都不依赖低位的进位,每一位的进位可同时产生。若不考虑 G i G_i Gi​、 P i P_i Pi​的形成时间,则n位超前进位加法器的进位总延迟与字长无关。但随着加法器位数的增加, C i C_i Ci​的表达式会越来越长,电路结构会越来越复杂,而且将受到元器件扇人系数的限制,所以完全采用并行进位是不可能的,实际上通常采用分组并行进位来实现。即把n位字长分为许多小组(每组通常4位),在组内实现先行进位,在组间既可采用RIP进位,也可采用先行进位。一般地,把组内并行,组间串行的方式称为单级超前进位加法器;把组内并行,组间并行的方式称为多级超前进位加法器。 由超前进位加法器进行改造,可以得到并行的ALU单元。

十进制的加法器

十进制加法器可由BCD码(二-十进制码)来设计,它可以在二进制加法器的基础上加上适当的“校正”逻辑来实现。

可控加法/减法(CAS)单元

用于并行除法流水逻辑阵列中。用于控制进行加法或者减法:当P = 0 做加法运算,P = 1 做减法运算。 https://i-blog.csdnimg.cn/direct/38d46536a71e415cb0b7ccf74a258ccd.png#pic_center CAS单元的输入与输出的关系可用如下一组逻辑方程来表示: S i = A i ⊕ ( B i ⊕ P ) ⊕ C i S_i = A_i\oplus (B_i \oplus P) \oplus C_i Si​=Ai​⊕(Bi​⊕P)⊕Ci​ C i + 1 = ( A i + C i ) ⋅ ( B i ⊕ P ) + A i ⋅ C i C_{i+1} = (A_i + C_i)·(B_i \oplus P) + A_i · C_i Ci+1​=(Ai​+Ci​)⋅(Bi​⊕P)+Ai​⋅Ci​ 当P=0时, 即是我们熟悉的一位全加器(FA)的公式: S i = A i ⊕ B i ⊕ C i S_i = A_i \oplus B_i \oplus C_i Si​=Ai​⊕Bi​⊕Ci​ C i + 1 = A i ⋅ B i + B i ⋅ C i + A i ⋅ C i C_{i+1} = A_i·B_i + B_i·C_i + A_i·C_i Ci+1​=Ai​⋅Bi​+Bi​⋅Ci​+Ai​⋅Ci​ 当P=1时, 则得求差公式: S i = A i ⊕ B i ‾ ⊕ C i S_i = A_i \oplus \overline{B_i} \oplus C_i Si​=Ai​⊕Bi​​⊕Ci​ C i + 1 = A i ⋅ B i ‾ + B i ‾ ⋅ C i + A i ⋅ C i C_{i+1} = A_i·\overline{B_i} + \overline{B_i}·C_i + A_i·C_i Ci+1​=Ai​⋅Bi​​+Bi​​⋅Ci​+Ai​⋅Ci​ 其中 B i ‾ = B i ⊕ 1 \overline{B_i} = B_i \oplus 1 Bi​​=Bi​⊕1。 在减法情况下,输入 C i C_i Ci​称为借位输入,而 C i + 1 C_{i+1} Ci+1​称为借位输出。 由上图可知,每一个基本的CAS单元的延迟时间为3T单元。

乘法

原码乘法

首先,我们知道,乘法的手工算法可以表示为乘积 [z]原 = ( x f ⊕ y f ) + ( 0 x n − 1 … x 1 x 0 ) ( 0 y n − 1 … y 1 y 0 ) (x_f \oplus yf_)+(0.x_{n-1} \ldots x_1 x_0)(0.y_{n-1} \ldots y_1 y_0) (xf​⊕yf)​+(0.xn−1​…x1​x0​)(0.yn−1​…y1​y0​),其中n位被乘数和乘数用定点小数表示,即被乘数[x]原 = x f . x n − 1 … x 1 x 0 x_f. x_{n-1}\ldots x_1 x_0 xf​.xn−1​…x1​x0​,乘数 [y]原 = y f . y n − 1 … y 1 y 0 y_f.y_{n-1}\ldots y_1 y_0 yf​.yn−1​…y1​y0​, x f x_f xf​为被乘数符号, y f y_f yf​为乘数符号。乘积符号的运算规则为同号相乘为正,异号相乘为负。 但是,机器与人们习惯的算法有着较大的差异。首先,机器通常只有n位长,两个n位数相乘,乘积可能为2n位。其次,只有两个操作数相加的加法器难以胜任将n位积一次相加起来的运算。 所以,我们需要改进乘法过程,使得其满足机器运算的要求。 https://i-blog.csdnimg.cn/direct/374347638ebe4415adf9213f0d36c46d.png#pic_center 一般而言,设被乘数x,乘数y都是小于1的n位定点正数,即 x = 0 x 1 x 2 … x n < 1 x = 0.x_1 x_2 \ldots x_n < 1 x=0.x1​x2​…xn​<1, y = 0 y 1 y 2 … y n < 1 y = 0.y_1 y_2 \ldots y_n < 1 y=0.y1​y2​…yn​<1, 其乘积为: x ⋅ y = x ⋅ ( 0 y 1 y 2 … y n ) = x ( y 1 ⋅ 2 − 1 + y 2 ⋅ 2 − 2 + ⋯ + y n ⋅ 2 − n ) = 2 − 1 ⋅ ( y 1 ⋅ x + 2 − 1 ⋅ ( y 2 ⋅ x + 2 − 1 ⋅ ( ⋯ + 2 − 1 ⋅ ( y n − 1 ⋅ x + 2 − 1 ⋅ ( y n ⋅ x + 0 ) ) ⋯ ) ) ) x·y = x·(0.y_1 y_2 \dots y_n) = x(y_1 · 2^{-1} + y_2·2^{-2} + \cdots + y_n·2^{-n}) = 2^{-1} · (y_1·x + 2^{-1} · (y_2·x + 2^{-1}·(\cdots + 2^{-1}·(y_{n-1}·x + 2^{-1}·(y_n·x + 0))\cdots ))) x⋅y=x⋅(0.y1​y2​…yn​)=x(y1​⋅2−1+y2​⋅2−2+⋯+yn​⋅2−n)=2−1⋅(y1​⋅x+2−1⋅(y2​⋅x+2−1⋅(⋯+2−1⋅(yn−1​⋅x+2−1⋅(yn​⋅x+0))⋯))) 令 z i z_i zi​表示第i次部分积,则根据从内到外的原则有: z 0 = 0 z_0 = 0 z0​=0 z 1 = 2 − 1 ⋅ ( y n ⋅ x + z 0 ) z_1 = 2^{-1} · (y_n·x + z_0) z1​=2−1⋅(yn​⋅x+z0​) z 2 = 2 − 1 ⋅ ( y n − 1 ⋅ x + z 1 ) z_2 = 2^{-1} · (y_{n-1}·x + z_1) z2​=2−1⋅(yn−1​⋅x+z1​) ⋯ \cdots ⋯ z i = 2 − 1 ⋅ ( y n − i + 1 ⋅ x + z i − 1 ) z_i = 2^{-1} · (y^{n-i+1}·x + z_{i-1}) zi​=2−1⋅(yn−i+1⋅x+zi−1​) ⋯ \cdots ⋯ z n = x ⋅ y = 2 − 1 ⋅ ( y 1 ⋅ x + z n − 1 ) z_n = x · y = 2^{-1} · (y_1·x + z_{n-1}) zn​=x⋅y=2−1⋅(y1​⋅x+zn−1​) 通过以上过程,我们可以看出,每次只需要相加两个数,然后右移一位。且相加的两个数(部分积和位积)都只有n位,因而不需要2n位的加法器。

补码乘法

原码一位乘法的主要问题是符号位不能参与运算,而补码乘法可以实现符号位直接参与运算。 补码一位乘法可以采用比较法实现,而比较法是Booth夫妇首先提出来的,所以又称Booth算法。

Booth算法

设被乘数[x]补码 = x 0 . x 1 x 2 … x n x_0.x_1 x_2 \ldots x_n x0​.x1​x2​…xn​,乘数[y]补码 = y 0 . y 1 y 2 … y n y_0.y_1 y_2 \ldots y_n y0​.y1​y2​…yn​,则有补码乘法算式:[ x · y ]补码 = [x]补码 · y ,由补码的定义可知,设[x]补 = x 0 . x 1 x 2 … x n x_0.x_1 x_2 \ldots x_n x0​.x1​x2​…xn​,则x的真值为 − x 0 + ∑ i = 1 n x i ⋅ 2 − i - x_0 + \sum_{i=1}^{n}x_i·2^{-i} −x0​+∑i=1n​xi​⋅2−i,因此,我们可以得出[ x · y ]补码 = [x]补码 · [ − y 0 + ∑ i = 1 n y i ⋅ 2 − i ] [ - y_0 + \sum_{i=1}^{n}y_i·2^{-i} ] [−y0​+∑i=1n​yi​⋅2−i] 。 由此,可以得到补码一位乘法的算法流程: https://i-blog.csdnimg.cn/direct/1b992754233e4622b66c14af937c9b42.png#pic_center 以下为算法的硬件逻辑图 https://i-blog.csdnimg.cn/direct/370dd65e13a14129ba878defdb3b465c.png#pic_center 当被乘数寄存器R2的每一位用原码(触发器Q端)或反码(触发器Q端)经多路开关送出;送[-x]补码时,即送R2反码且在加法器最末为加1; R0保存部分积,其符号与加法器符号位f始终一致;当计数器i=n+1时,封锁LDR1、LDR0信号,使最后一步不移位。

阵列乘法器

对于普通的乘法器,其不需要很多器件,硬件结构简单,但是速度太慢,执行一次乘法操作的时间至少是加法操作的n倍。但是,由于乘法操作大约占全部算术运算的1/3,故采用高速乘法部件是非常必要的。而阵列乘法器便是高速乘法部件的一种。

不带符号的阵列乘法器

设有两个不带符号的二进制整数 A = a m − 1 … a 1 a 0 A = a^{m-1} \ldots a_1 a_0 A=am−1…a1​a0​, B = b n − 1 … b 1 b 0 B = b^{n-1} \ldots b_1 b_0 B=bn−1…b1​b0​,它们的数值分别为a和b,即: a = ∑ i = 0 m − 1 a i ⋅ 2 i a = \sum_{i=0}^{m-1}a_i·2^i a=∑i=0m−1​ai​⋅2i, b = ∑ j = 0 n − 1 b j ⋅ 2 j b = \sum_{j=0}^{n-1}b_j·2^j b=∑j=0n−1​bj​⋅2j。 在二进制乘法中,被乘数A与乘数B相乘,产生m + n位乘积P,且 P = p m + n − 1 … p 1 p 0 P = p^{m+n-1}\ldots p_1 p_0 P=pm+n−1…p1​p0​,乘积P的数值为: P = a ⋅ b = ∑ i = 0 m − 1 ∑ j = 0 n − 1 ( a i ⋅ b j ) ⋅ 2 i + j P = a · b = \sum_{i=0}^{m-1}\sum_{j=0}^{n-1}(a_i·b_j)·2^{i+j} P=a⋅b=∑i=0m−1​∑j=0n−1​(ai​⋅bj​)⋅2i+j 根据以上公式,我们可以得到不带符号的阵列乘法器的逻辑电路图 https://i-blog.csdnimg.cn/direct/3398a7d0d2f340edbdb700d4b63de270.png#pic_center

带符号的阵列乘法器

带符号的阵列乘法器的原理是通过对2求补电路对不带符号的阵列乘法器的输入和输出进行修正。 对2求补的过程是,从数的最右端 a 0 a_0 a0​开始,由右向左,直到找出第一个“1”,例如 a i = 1 a_i = 1 ai​=1, 0 ≤ i ≤ n 0\leq i\leq n 0≤i≤n。这样, a i a_i ai​以左的每一个输入位都求反, 即1变0, 0变1。 https://i-blog.csdnimg.cn/direct/1559d0bef99147e9835b73f8d8c291b8.png#pic_center 在这种逻辑结构中,共使用三个求补器:两个算前求补器,作用是将两个操作数A和B在被不带符号的乘法阵列(核心部件)相乘以前,先变成正整数;算后求补器,作用则是:当两个输入操作数的符号不一致时,把运算结果变成带符号的数。在必要的求补操作以后,A和B的码值输送给n·n位不带符号的阵列乘法器,并由此产生2n位的乘积: A ⋅ B = P = p 2 n − 1 … p 1 p 0 A·B = P = p_{2n-1} \ldots p_1 p_0 A⋅B=P=p2n−1​…p1​p0​, p 2 n = a n ⊕ b n p_{2n} = a_n\oplus b_n p2n​=an​⊕bn​,其中 P 2 n P^{2n} P2n为符号位。

除法

原码除法

设被除数 x,其原码为[x]原码 = x f . x n − 1 … x 1 x 0 x_f.x_{n-1}\ldots x_1 x_0 xf​.xn−1​…x1​x0​,除数 y,其原码为[y]原码 = y f . y n − 1 … y 1 y 0 yf.y^{n-1}\ldots y_1 y_0 yf.yn−1…y1​y0​,则有商q= x / y,其原码为[q]原码 = ( x f ⊕ y f ) + ( 0 x n − 1 … x 1 x 0 / 0 y n − 1 … y 1 y 0 ) (x_f\oplus y_f) + (0.x_{n-1}\ldots x_1 x_0 / 0.y_{n-1} \ldots y_1 y_0) (xf​⊕yf​)+(0.xn−1​…x1​x0​/0.yn−1​…y1​y0​)。商的符号运算 q f = x f ⊕ y f q_f = x_f \oplus y_f qf​=xf​⊕yf​,与原码乘法一样,并且商的数值部分的运算实质上是两个正数求商的运算。

除法的手算过程

例如,设被除数x = 0.1001, 除数y = 0.1011,仿十进制除法运算,手算求 x / y的过程如下: https://i-blog.csdnimg.cn/direct/ed9c94bb3a4e494ea7e3655c297e9a1a.png#pic_center 由此,得x / y 的商 q = 0.1101,余数为r = 0.00000001。 但是,在计算机中,小数点是固定的,不能简单地采用手算的办法。因此,为便于机器操作,通常采用除数Y固定不变,被除数和余数进行左移(相当于乘2)。而且机器不会心算,必须先作减法,若余数为正, 才知道够减;若余数为负,才知道不够减。不够减时必须恢复原来的余数,以便再继续往下运算。这种方法称为恢复余数法。要恢复原来的余数,只要当前的余数加上除数即可。但由于要恢复余数,使除法进行过程的步数不固定,因此控制比较复杂。 实际中常用不恢复余数法(又称加减交替法)。其特点是运算过程中如出现不够减,则不必恢复余数,根据余数符号可以继续往下运算,因此步数固定,控制简单。

恢复余数法

被除数减除数,够减时,商1;不够减时商0。由于商0时若不够减,即不能作减法,但现在在判断是否商0时,已经减了除数,为了下次能正确运算,必须把已减掉的除数加回去恢复余数。这就是“恢复余数法”。

加减交替法

上述恢复余数法由于要恢复余数,使得除法的步数不固定,控制比较复杂。实际上常用的是加减交替法。 加减交替法的特点是,当运算过程中出现不够减的情况,不必恢复余数,而是根据余数的符号,继续往下运算,因此步数固定,控制简单。 加减交替法的运算规则为当余数为正时,商1,余数左移一位,减除数;当余数为负时,商0,余数左移一位,加除数。

补码一位除法

补码除法的被除数、除数用补码表示,符号位和数位一起参与运算,商的符号位与数位由统一的算法求得。补码除法通常采用加减交替法。 补码加减交替法的运算过程为: (1)若被除数与除数同号,被除数减去除数;若被除数与除数异号,被除数加上除数。 (2)余数和除数同号,商1,余数左移一位,下次减除数;余数和除数异号,商0,余数左移一位,下次加除数。 (3)重复步骤(2),连同符号位在内,共做n+1步。 为统一并简化硬件电路,算法一开始就根据[x]补码和[y]补码的符号位是否相同,判断下次进行何种运算。 如果[x]补码和[y]补码的符号位相同,假商(上一位商 q 0 q_0 q0​,但 q 0 q_0 q0​是真正的商的符号,称其为假商)为1,控制下次做减法;如果[x]补码和[y]补码的符号位不同,假商为0,控制下次做加法。 按同样的规则,共做n+1步运算后,假商 q 0 q_0 q0​移出了存放商的寄存器,剩下 q 0 q_0 q0​至 q n q_n qn​,即运算结果。

商的校正

补码一位除法的算法是在商的末位“恒置1”的舍入条件下推导的,故此算法存在误差,这样引起的最大误差是 2 − n 2^{-n} 2−n。在对计算精度没有特殊要求的情况下,一般就采用商的末位“恒置1”的办法,这样操作比较简单,而且易于实现。 如果需要进一步提高商的精度,可按上述方法多求一位,再用以下方法进行校正:刚好能除尽时,若除数为正,商不必校正;若除数为负,则商加 2 − n 2^{-n} 2−n。不能除尽时,若商为正,则不必校正;若商为负,则商加 2 − n 2^{-n} 2−n。

阵列除法器

阵列式除法器是一种并行运算部件,采用大规模集成电路制造。与早期的串行除法器相比,阵列除法器不仅所需的控制线路少,而且能提供令人满意的高速运算速度。 阵列除法器有多种多样形式,比如不恢复余数阵列除法器、补码阵列除法器等等。

不恢复余数的阵列除法器

在不恢复余数的除法阵列中,当余数为正时( r i ≥ 0 r_i \geq 0 ri​≥0),商“1”,下次做减法运算,减法是用2的补码运算来实现的,此时 [x-y]补码 = [ x ]补码 + [ -y ]补码;当余数为负时($ r_i < 0$),商“0”,下次做加法运算;每次运算完成后要将余数左移一位,再与除数做加或减运算;并且商的符号由两数的符号按位相加求得。 https://i-blog.csdnimg.cn/direct/85e92c57901345d7bdb7d979833d152a.png#pic_center 其中,被除数x是一个6位的小数(双倍长度值): x = 0 x 1 x 2 x 3 x 4 x 5 x 6 x = 0.x_1 x_2 x_3 x_4 x_5 x_6 x=0.x1​x2​x3​x4​x5​x6​,它是由顶部一行和最右边的对角线上的垂直输入线来提供的。除数y是一个3位的小数: y = 0 y 1 y 2 y 3 y = 0.y_1 y_2 y_3 y=0.y1​y2​y3​,它沿对角线方向进入这个阵列。这是因为在除法中所需要的部分余数的左移,可以用下列等效的操作来代替,即让余数保持固定,而将除数沿对角线右移。 最上面一行所执行的初始操作经常是减法。因此最上面一行的控制线P固定置成“1”。减法是用2的补码运算来实现的,这时右端各CAS单元上的反馈线用作初始的进位输入。 每一行最左边的单元的进位输出决定着商的数值,将当前的商反馈到下一行,我们就能确定下一行的操作。由于进位输出信号指示出当前的部分余数的符号,因此,它将决定下一行的操作将进行加法还是减法。 由图看出,该阵列除法器是用一个可控加法/减法(CAS)单元所组成的流水阵列来实现的。 推广到一般情况,一个(n+1)位除(n+1)位的加减交替除法阵列由 ( n + 1 ) 2 (n+1)^2 (n+1)2个CAS单元组成,其中两个操作数(被除数与除数)都是正的。其中n为尾数位数。 对不恢复余数阵列除法器来说,在进行运算时,结果沿着每一行都有进位(或借位)传播;同时所有行在它们的进位链上都是串行连接,而每个CAS单元的延迟时间为3T单元。因此,对一个2n位除以n位的不恢复余数阵列除法器来说,单元的数量为 ( n + 1 ) 2 (n+1)^2 (n+1)2,考虑最大情况下的信号延迟,其除法执行时间为 t d = 3 ⋅ ( n + 1 ) ⋅ 2 ⋅ T t_d = 3·(n+1)·2·T td​=3⋅(n+1)⋅2⋅T,其中n为尾数位数。

浮点数加减法

为便于软件移植,浮点数通常采用使用IEEE754标准。IEEE754 标准规定尾数用原码;阶码用“移码”;基为2。 设有两个浮点数x和y,它们分别为: x = ( − 1 ) S x ⋅ 2 E x ⋅ M x x = (-1)^{S_x} · 2^{E_x} · M_x x=(−1)Sx​⋅2Ex​⋅Mx​, y = ( − 1 ) S y ⋅ 2 E y ⋅ M y y = (-1)^{S_y} · 2^{E_y} · M_y y=(−1)Sy​⋅2Ey​⋅My​,其中 E x E_x Ex​和 E y E_y Ey​分别为数x和y的阶码, M x M_x Mx​和 M y M_y My​为数x和y的尾数。 由数学推导可知,两浮点数进行加法和减法的运算规则是 x ± y = ( M x ⋅ 2 ( E x − E y ) ± M y ) ⋅ 2 E y x \pm y = ( M_x · 2^{(E_x - E_y)} \pm M_y ) · 2^{E_y} x±y=(Mx​⋅2(Ex​−Ey​)±My​)⋅2Ey​,且 E x ≤ E y E_x \leq E_y Ex​≤Ey​。 计算机完成浮点加减运算的操作过程大体为: (1) 0 操作数的检查。 (2) 比较阶码大小并完成对阶。使二数阶码相同(即小数点位置对齐),这个过程叫作对阶。对阶的过程为,首先求两数阶码 E x E_x Ex​和 E y E_y Ey​之差,即 △ E = E x − E y \bigtriangleup E = E_x - E_y △E=Ex​−Ey​,若 △ E = 0 \bigtriangleup E = 0 △E=0,表示 E x = E y E_x = E_y Ex​=Ey​;若 △ E > 0 \bigtriangleup E > 0 △E>0,表示 E x > E y E_x > E_y Ex​>Ey​;若 △ E < 0 \bigtriangleup E < 0 △E<0,表示 E x < E y E_x < E_y Ex​<Ey​。然后通过尾数的移动来改变 E x E_x Ex​或 E y E_y Ey​,使其相等。 对阶的原则是阶码小的数向阶码大的数对齐,即小阶的尾数右移,每右移一位,其阶码加1(右规)。 (3) 尾数进行加或减运算。尾数求和方法与定点加减法运算完全一样。 (4) 结果规格化。求和之后得到的数可能不是规格化了的数,为了增加有效数字的位数, 提高运算精度,必须将求和的结果规格化。规格化的定义为使得规格化的浮点数S满足 0.5 ≤ ∣ S ∣ < 1 0.5 \leq |S| < 1 0.5≤∣S∣<1。 采用原码时,规格化后的正数形如 S = 0.1 x x x … x S=0.1xxx\ldots x S=0.1xxx…x,负数形如 S = 1.1 x x x … x S=1.1xxx\ldots x S=1.1xxx…x。采用双符号位的补码,规格化后的正数形如: S = 00.1 x x x … x S=00.1xxx\ldots x S=00.1xxx…x,对负数形如 S = 11.0 x x x … x S=11.0xxx\ldots x S=11.0xxx…x。 规格化分为向左规格化和向右规格化。 若不是规格化的数,需要尾数向左移位,以实现规格化的过程,我们称其为向左规格化。向左规格化即左移一位,阶码减1,当进行浮点加减运算时,尾数求和的结果也可能得到: S = 01 x x x … x S=01.xxx\ldots x S=01.xxx…x或 S = 10 x x x … x S=10.xxx\ldots x S=10.xxx…x,即两符号位不等,即结果的绝对值大于1。向左破坏了规格化。此时,将尾数运算的结果右移一位,阶码加1,称为向右规格化。 (5) 舍入处理。在对阶或向右规格化时,尾数要向右移位,这样,被右移的尾数的低位部分会被丢掉,从而造成一定误差,因此要进行舍入处理。简单的舍入方法有两种:第一种,“0舍1入”法。即如果右移时被丢掉数位的最高位为0则舍去,反之则将尾数的末位加“1”。第二种,“恒置1”法。即只要数位被移掉,就在尾数的末位恒置“1”。从概率上来说,丢掉的0和1各为1/2。 (6)溢出处理。与定点加减法一样,浮点加减运算最后一步也需判溢出。在浮点规格化中已指出,当尾数之和(差)出现 S = 01 x x x … x S=01.xxx\ldots x S=01.xxx…x或 S = 10 x x x … x S=10.xxx\ldots x S=10.xxx…x时,并不表示溢出,只有将此数右规后,再根据阶码来判断浮点运算结果是否溢出。 浮点数的溢出是以其阶码溢出表现出来的,若阶码正常,加减运算正常结束;若阶码溢出,则要进行相应的处理。 阶码存在阶码上溢和下溢两种情况,阶码上溢是指超过了阶码可能表示的最大值的正指数值,一般将其认为是 + ∞ +\infty +∞和 − ∞ -\infty −∞。 阶码下溢是指超过了阶码可能表示的最小值的负指数值,一般将其认为是0。 当然,我们还需要对尾数的溢出进行处理,上溢则右归,下溢则舍入。 https://i-blog.csdnimg.cn/direct/70dc5220e0ca4ec097c1f120ddea7560.png#pic_center

浮点乘法、除法

浮点乘法、除法运算规则为,设有两个浮点数x和y, x = ( − 1 ) S x ⋅ 2 E x ⋅ M x x = (-1)^{S_x} · 2^{E_x} · M_x x=(−1)Sx​⋅2Ex​⋅Mx​, y = ( − 1 ) S y ⋅ 2 E y ⋅ M y y = (-1)^{S_y} · 2^{E_y} · M_y y=(−1)Sy​⋅2Ey​⋅My​,浮点乘法运算的规则是: x ⋅ y = 2 ( E x + E y ) ⋅ ( M x ⋅ M y ) x · y = 2^(E_x + E_y) · (M_x · M_y) x⋅y=2(Ex​+Ey​)⋅(Mx​⋅My​)。即乘积的尾数是相乘两数的尾数之积;乘积的阶码是相乘两数的阶码之和。 浮点除法运算的规则是 x / y = 2 ( E x − E y ) ⋅ ( M x / M y ) x / y =2^(E_x - E_y) · (M_x / M_y) x/y=2(Ex​−Ey​)⋅(Mx​/My​)。即商的尾数是相除两数的尾数之商;商的阶码是相除两数的阶码之差。 浮点数的乘除运算大体分为四步: (1) 0 操作数检查。 (2) 阶码加/减操作。对阶码的运算有+1、-1、两阶码求和、两阶码求差四种。在运算时还必须检查结果是否溢出。 在计算机中, 阶码通常用补码或移码形式表示,并且移码的运算规则 [ x + y ]移码 = − 2 n -2^n −2n + [x]移码 + [y]移码。考虑到移码和补码的关系,对同一个数值, 其数值位完全相同, 而符号位正好完全相反。[y]补码的定义为[y]补码 = 2 n + 1 ) + y 2^{n+1)} +y 2n+1)+y,则求阶码和用如下方式完成: [ x + y ]移码 = [x]移码 + [y]补码, ( m o d ( 2 n + 1 ) ) (mod(2^{n+1})) (mod(2n+1)) [ x - y ]移码 = [x]移码 + [-y]补码, ( m o d ( 2 n + 1 ) ) (mod(2^{n+1})) (mod(2n+1)) 阶码运算通常使用双符号位的阶码加法器,并规定移码的第二个符号位,即最高符号位恒用0参加加减运算,因此,溢出条件是结果的最高符号位为1,并且当低位符号位为0时(10),表明结果上溢,当低位符号位为1时(11),表明结果下溢。当最高符号位为0时,表明没有溢出,低位符号位为1(01),表明结果为正;低位符号位为0,(00),表明结果为负。 (3) 尾数乘/除操作。 (4) 结果规格化及舍入处理。 浮点加减法对结果的规格化及舍入处理也适用于浮点乘除法。 第一种方法是无条件地丢掉正常尾数最低位之后的全部数值。这种办法被称为截断处理,好处是处理简单,缺点是影响结果的精度。 第二种办法是运算过程中保留右移中移出的若干高位的值,最后再按某种规则用这些位上的值修正尾数。这种处理方法被称为舍入处理。 舍入处理。当尾数用原码表示时,最简便的方法是,只要尾数的最低位为1, 或移出的几位中有为1的数值位,就使最低位的值为1。另一种是0舍1入法,即当丢失的最高位的值为1时,把这个1加到最低数值位上进行修正,否则舍去丢失的各位的值。这样处理时,舍入效果对正数负数相同,入将使数的绝对值变大,舍则使数的绝对值变小。当尾数是用补码表示时,采用0舍1入法时,若丢失的位不全为0时,对正数来说,舍入的结果与原码分析相同;对负数来说,舍入的结果与原码分析相反,即“舍”使绝对值变大,“入”使绝对值变小。为使原、补码舍入处理后的结果相同,对负数可采用如下规则进行舍入处理:当丢失的各位均为0时,不必舍入;当丢失的最高位为0,以下各位不全为0时,或者丢失的最高位为1,以下各位均为0时,则舍去丢失位上的值;当丢失的最高位为1,以下各位不全为0时,则执行在尾数最低位入1的修正操作。