众所周知,算术的基本运算共有4种:
加、减、乘和除。在微型计算机中常常只有加法电路,这是为了使硬件结构简单而成本较低。不过,只要有了加法电路,也能完成算术的4种基本运算。
一、二进制数的相加
两个二进制数相加的几个例子:
例1.4.1
(1)
(2)
(3)
(4)
例1.4.1(1)中, 加数A和被加数B都是1位数,其和S变成2位数,这是因为相加结果产生进位之故。
例1.4.1(2)中, A和B都是2位数,相咏峁鸖也是2位数,因为相加结果不产生进位。
例1.4.1(3)中, A和B都是2位数,相加结果S是3位数,这也是产生了进位之故。
例1.4.1(4)中,是例1.4.1(3)的另一种写法,以便看出“进位”究竞是什么意义。第1位(或称0权位)是不可能有进位的,要求参与运算的就只有两个数A0和B0,其结果为S0。第2位(或称l权位)就是
3个数A1,B1及C1参与运算了。其中C1是由于第1位相加的结果产生的进位。此3个数相加的结果其总和为S1=1,同时又产生进位C2,送入下一位(第3位)。第3位(或称2权位)也是3个数A2,B2及C2相加参加运算。由于A2及B2都是0,所以C2即等于第3位的相加结果S2。
从以上几例的分析可得出下列结论:
(1) 两个二进制数相加时, 可以逐位相加。 如二进制数可以写成:
A=A3A2A1A0
B=B3B2B1B0
则从最右边第1位(即0权位)开始,逐位相加,其结果可以写成:
S=S3S2S1S0
其中各位是分别求出的:
S0=A0+B0 进位C1
S1=A1+B1+C1 进位C2
S2=A2+B2+C2 进位C3
S3=A3+B3+C3 进位C4
最后所得的和是:C4S3S2S1S0=A+B
(2) 右边第1位相加的电路要求:
输入量为两个,即A0及B0;
输出量为两个,即S0及C1。
这样的一个二进制位相加的电路称为半加器(half adder)。
(3) 从右边第2位开始, 各位可以对应相加。各位对应相加时的电路要求:
输入量为3个,即Ai,Bi,Ci
输出量为两个,即Si,Ci+1。
其中i=1,2,3,…,n。 这样的一个二进制位相加的电路称为全加器(full adder)。
二、半加器电路
要求有两个输入端,用以两个代表数字(A0,B0)的电位输入;有两个输出端,用以输出总和S0及进位C1。
这样的电路可能出现的状态可以用图1.4.1中的表来表示。
此表在布尔代数中称为真值表。考察一下C1与A0及B0之关系,即可看出这是“与”的关系,即:C1=A0×B0
再看一下S0与A0及B0之关系,也可看出这是“异或”的关系,即:S0=A0⊕B0=A0#B0+A0B0#
即只有当A0及B0二者相异时,才起到或的作用;二者相同时,则其结果为0。
因此,可以用“与门”及“异或门”(或称“异门”)来实现真值表的要求。图1.4.1就是这个真值表及半加器的电路图。
三、全加器电路
全加器电路的要求是:有3个输入端,以输入Ai,Bi和Ci,有两个输出端,即Si及Ci+1。其真值表可以写成如图1.4.2所示。由此表分析可见,
其总和Si可用“异或门”来实现, 而其进位Ci+1则可以用3个“与门”及一个“或门”来实现,其电路图也画在图1.4.2中。
这里遇到了3个输入的“异或门”的问题。如何判断多输入的“异或门”的输入与输出的关系呢?判断方法是:
多输入A,B,C,D,…中为“1”的输入量的个数为零及偶数时, 输出为0;为奇数时,输出为1。
四、二进制数的相减
有符号数的表示:X-Y=X+(-Y)
机器数与真值(以8位字长为例)
计算机中的数和数的符号都是用二进制表示的,这样的数称为机器数。一般用最高有效位来表示数的符号,正数用0表示,负数用1表示。
机器数可用不同的码制来表示,常用的有原码、补码和反码表示法。
机器字长n是指参与运算的数的基本位数, 标志着计算精度,一般是字节的整数倍,有8位、16位、32位等。
数在机器中的具体表示形式——机器数,有多种表示形式,字长固定;真值:机器数所对应的实际数的大小和符号,一般写成有符号十进制数的形式——真值。
无符号数:用机器的所有位按二进制数的位权关系表示的数。8位长:
二进制数可以表示28=256个数,
00~FFH(0~255);16位长:二进制数可以表示216=65536个数,0000~FFFFH(0~65535)。
有符号数的表示(以8位字长为例): 有三种机器数,可以区分正、负的有符号数;
原码表示:机器数的最高位作为符号位:
D7=0表示正号,1表示负号,其余位D6~D0表示数值的大小,
表示范围-127~+127。引入正号0对D6~D0的数值没有影响,因此正数用原码即能表示也能运算,对于正数只要原码的一种机器数就够了;引入负号1对D6~D0的数值有影响,因此负数可用原码表示但不能直接运算。
优点:简单。
缺点:不便于运算,不能直接进行原码加减。
反码表示(负数): 对应正数原码按位取反,表示数值的大小(-127~+127)。
例:[+72]原=0 1001000, [-72]反=1 0110111
关于补码:
以钟表的数字系统为例,要从5点钟拔到3点,两种拔法:①逆时针拔2小时5-2=3。②顺时针拔10小时5+10=15=3,由于12为0点,因此存在12的自然丢失。于是就有:
5-2=5+(-2)=5+10=3
本数字系统中10为-2的补码:[-2]补=12+(-2)=10。
负数补码一般式:
[负数]补=模+(负数) ;求补码方法之一
模:指定长数字系统在运算时发生自然丢失的数值大小。
二进制8位字长(定长)的数字系统,运算时发生自然丢失的是:
模8=100000000B=100H=28;而16位字长时的模16=10000H=216
例:[-100]补=100H+(-64H)=9CH=10011100B
例:[-100]补=10000H+(-64H)=FF9CH=1111111110011100B
例:[+100]补=100H+(+64H)=164H=64H=0110 0100B
例:[+100]补=10000H+(+64H)=10064H=0064H=0000 0000 0110
0100B
8位字长的补码范围:
-128~+127当它们是补码表示的带符号数时,16位二进制的表数范围是-32768≤N≤+32767,如表1.4.1所示。
n位补码的表数范围是:-2n-1≤N≤2n-1-1。
符号扩展:是指一个数从位数较少扩展到位数较多,如从8位扩展到16位,或从16位扩展到32位。8位到16位的正数扩展:扩展的高8位为0,负数扩展的高8位为全1(见上例)。
[证明] n位字长二进制数制系统的模2n;
有:X=2n+X
对正数:X=xn-2 xn-3 …
x1 x0
以8位字长为例,n=8
由于2n=100000000,所以2n+X=X,
即X=0 x6 x5…. x1
x0
28+X=10 x6 x5…. x1
x0=0x6 x5…. x1
x0(只留8位)
也就是正数的补码和原码相同
对负数:
所以负数的补码等于其正数原码“求反加1”,即按位求反,末位加1。
求补码方法之二,该方法很适合硬件电路求补运算。
例:假设机器字长为8位,求-46的补码。
+46的原码表示为: 0010 1110
按位求反: 1101 0001
末位加1 1101 0010
所以,[-46]补码=D2H
求补码方法之三:对负数求补码时,可将求反在最后一个“1”之前进行。
如:原码11001000的补码10111000, 从右往左的第一个1及后面的0不变,
左边的位取反(由负数原码去求负数的补码,符号不要求反;由正数原码去求对应负数的补码,符号也要求反)。
补码的运算:
可以证明 [A+B]补=[A]补+[B]补
[A+B]补=模+(A+B)=模+(A+B)+模=(模+A)+(模+B)
=[A]补+[B]补
即两数和的补码等于两数补码的和。
也就是说,在进行补码加法时,不用考虑加数的正负,直接进行补码加法就可以。从而简化了计算机内部的操作,在微机领域中得到广泛运用。
例:两个负数的相加:-70+(-55)
-70→(11000110)原→(10111010)补
-55→(10110111)原→(11001001)补
相加后:1(10000011)补
由补码再一次“求反加1”可得到其真值:
(10000011)补→(11111101)原→-125
例:一个负数和一个正数相加:-70+55
-70→(11000110)原→(10111010)补
55→(00110111)原→(00110111)补
相加后:(11110001)补
由补码再一次“求反加1”可得到其真值:
(11110001)补→(10001111)原→-15
补码加法的步骤是:
将被加数和加数都变成补码;
直接进行加法,得到两数和的补码;
判断是否溢出;
若没有溢出,则可进一步求和的真值:和为正数可直接求出,和为负数,则再次“求反加1”(即再次求补),得到原码再求真值。
溢出的判断:
溢出:有符号数运算的结果超出了计算机可以表示的范围,就是溢出。
溢出标志:OF=CF⊕CM(异或)。
其中,CF=1表示运算时字长的最高位发生进位或借位;CM=1表示运算时字长的次高位发生进位或借位;OF=1⊕0=0⊕1=1表示结果发生了溢出。
两个同符号数的相加或两个异号数相减有可能出现溢出;发生溢出时结果是错误的且符号与正确结果的符号相反。不要混淆进位CF与溢出OF,进/借位是无符号数运算时的“溢出”表示,而有进位不一定就溢出。
如:两个负数补码相加后得到正数的补码,或两个正数的补码相加后到负数的补码,都不正常,都是出现了溢出。
例:两个负数的相加:-70+(-60)
-70→(11000110)原→(10111010)补
-60→(10111100)原→(11000100)补
相加后:1(01111110)补
此时,因为两个负数相加后得到了正数的补码,结果肯定不对,出现了溢出:OF=1⊕0=1
溢出的解决:先扩展操作数的位数,
再进行运算。数的扩展不能改变数的大小,只能改变数的位数。
正数的扩展:高位全部加0;
负数的扩展:高位全部加1。
如:-70→(10111010)补→(1111111110111010)补
-60→(11000100)补→(1111111111000100)补
相加后为:1(1111111101111110)补
真值为-130 ;溢出标志:OF=1⊕1=0