有符号二进制加法溢出判断以及溢出后该如何计算正确答案
打开博客园,一篇关于有符号二进制加法溢出的文章吸引了我的好奇。由于没有基础,对原博主所说内容并未完全理解,开始在网上搜索寻找各种详细的解释,但发现效果都不好。今天花了大半天的时间来研究有符号二进制数加法溢出以及溢出后该如何计算的问题。本文适合没有任何基础的初学者。
我想从五个方面来说说有符号二进制加法溢出以及溢出后该如何计算这些个问题:
·什么是有符号二进制数
·补码的计算以及还原
·有符号数的加法
·什么是溢出、什么是自然丢弃
·溢出后该如何正确计算结果
一.什么是有符号二进制数
二进制数分为有符号和无符号两种形式,在未标明的情况下,二进制数指的是无符号二进制数,即没有负数形式。反之,有符号二进制数,是指有正负号的二进制数。
有符号二进制数即在无符号二进制数的基础上,在最左边添加符号位,‘0’为正,‘1’为负。
举例说明:-2 1(符号位 ‘1’表明是负数)10(2的二进制表达) --> 110
+2 --> 010
二.补码的计算以及还原
在计算机的运算中,是以补码的形式进行加减法运算的(减法其实就是带负数的加法,2-3 其实就是2+(-3))。那补码是怎么计算的呢?
分为两种情况:
1.正数补码。 记住正数的补码就是其本身。如:+2 -->010 补码--> 010
2.负数补码。 符号位不变,将符号位后面的所有数取反,之后进行加一操作。如:-2 --> 110 补码 --> 101 + 1 -->110. 可以发现它的补码和原码相同,这里大家留个心眼,为后面的溢出埋下伏笔。
学会了原码转补码,怎么能不会补码转原码呢。
补码转原码其实就是再将补码进行一次求补码的操作,即补码的补码是原码。
三.有符号数的加法
ps:自己在学习的过程中忽然有一个思考,拿出来分享一下。
思考:为什么不采用符号进行或操作,数值正常的相加减呢?
接下来就是开始进行加法操作了。在补码的加法运算中,符号位就当成是整个二进制数的一部分,进行加法运算。
如:+3 + 4
3 --> 0011
4 --> 0100
相加 --------
结果 0111
然后对所得结果求补码(这点很重要,前面例子发现有些负数的补码就是其本身,为了后面不弄混淆,建议对所得结果求补码)。此处,正数的补码是其本身。计算结果就是0111。
0 表示正数 111的十进制是7,解为+7。完全正确。
提一点如果两个相加数的位宽不同,将小的位宽的数左起填充0,然后再进行补码操作。
如-2+8 110 + 01000 此处将-2做如下处理。10010(五位保持和+8一样位宽) 再将10010做补码处理,-->11101+1-->11110。补码形式加法为:11110+01000
接下来请看什么是溢出,以及溢出的危害是什么。
四.什么是溢出、什么是自然丢弃
对于溢出的理解,稍微解释的不详细很可能会把初学者带入沟里,今天我就被带进沟里了。作为一个过来人我很愿意和大家分享,让初次接触的朋友们能很快的理解,避免和我一样花大量时间从沟里爬出来。言归正传。
说到溢出,还是要先提一下自然丢弃。
前面的例子是很简单的例子,请看下面这个例子:
-2 - 6
-2 --> 1110
-6 --> 1010
相加 --------
结果 11000
结果的位数比原先的多出了一位,此处最左边的1,是会被自然丢弃的(就是不要了)。再看结果,对1000求补码(其实可以看出它就是0)。这和我们想要的-8有天壤之别。为什么会出现这个情况呢?
原因就是这里出现了溢出!
首先来看溢出的定义:
对一个N位二进制补码,其可以表达的范围是 - 2N-1+1 ~ 2N+1 - 1之间。如果超出这个范围就称为溢出了。
拿上面的-2-6来说,我们刚刚在计算时,转换为二进制补码是4位的。它的取值范围是-7~+7之间。而我们想要的结果是-8,比范围的最小值还要小,这个叫做负溢出。同理如果想要的结果比最大值还要大,那么就叫做正溢出,如取值范围是-7~+7之间,想要的结果是+8,那么就是正溢出。
说完了溢出的定义,我们来说说溢出的判定,就是怎么在计算开始时知道自己算的结果是不是溢出了?
还是拿前面-2-6为例,即1110 + 1010,大家可以看到我拿两种不同颜色标注了它们最开头的两个数,我们把红色的(左起第一位)符号位进位值和蓝色(左起第二位)相加的进位值进行比较。如果两者相同(即00或者11),则不溢出,如果两者不同(即01正溢出,10负溢出),则发生溢出,最后的解必定会出错。
拿-2-6为例,它们补码形式为1110+1010,符号位相加发生了进位,进位值为1,数字位左起第一位相加没有发生进位,进位值为0,即10型溢出,为负溢出,就是说所得的值小于四位二进制补码的取值范围,和我们计算的-8<-7结果相匹配,判断成功。
到这里我们已经成功了一大半,与最终正确解的就值就差一步之遥。
五.溢出后该如何正确计算结果
在通过判断之后,我们知道这个结果定是溢出了,该怎么求正确的解呢?
答:将位宽扩大一位,还是按前面的判定方法进行判定。
举例,-2-6 前面说了这是一个负溢出,我们在转换为二进制时进行位宽扩大,以提升取值范围。
此处 -2 二进制写成 10010(5位比开始多一位),-6二进制写成10110(5位比开始多一位)。再进行补码运算,10010--> 11101+1-->11110,10110-->11001+1-->11010.
11110
11010
相加---------
111000 最高位超出位宽,自然舍弃,剩下的11000求补码,10111+1-->11000 即-8,和我们所求的结果一致,bingo答对了。
如果想真的弄懂,一定要自己多给自己做一些练习:
题目:(1)-5-6 (2)+4+8 (3)-4-8
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
不知道大家有思考过我的问题吗?那种算法其实更符合我们在计算过程中的想法。但是为什么不使用这个算法呢?
本人是IC方向的,不妨从IC方向思考。如果采用上述算法,那么就需要一个加法器和一个或门相结合的形式,这和只用加法器就能完成的补码相加计算相比,是不是就多了一步符号位或的操作,这无形中增加了功耗,以及增加了电路的复杂程度。是不是降低或者增加了速度,不好说,那得看或操作延时和位数进位延时哪个时长较长了。我没有模拟过,在这里没法给予答案。
这只是我个人对这个思考的个人解读,如果你有不同的想法,欢迎留言,或者纠正我的错误,谢谢!