1-关于补码的理解
原文参考:https://blog.csdn.net/weixin_38958597/article/details/86631639
参考:十进制负数的二进制转换
补码是啥,它跟原码反码有啥关系?
相信大家都听过原码、反码、补码,需要知道的是,这三种都是有符号位的表示方法,第一位是符号位,1为负,0为正。如果是无符号,就不用分那么多了,直接转成二进制就是了,毕竟不用考虑负数。
原码:就是一个数的二进制表示,是我们最熟悉的二进制有符号数的表示方式,正数的话符号位为0,负数为1。
例:15的原码就是0000 1111;-15的原码就是1000 1111。
反码:反码是基于原码的变动,有两种情况,如果是正数的反码,就跟原码相同。如果是负数的反码,则除了符号位,其他全部取反
例:15的反码就是0000 1111;-15的反码就是1111 0000。
补码:补码是基于反码的变动,有两种情况,如果是正数的补码,就跟原码反码都相同。如果是负数的补码,则在其反码的基础上,再加1
例:15的补码就是0000 1111;-15的补码就是1111 0001。
总结:正数几乎只有一种码,不论用什么码去表示,它都是一样的。而反码补码更像是为负数“服务”的,他们的表示方式都有所不同。
到这里为止,这是大部分人都知道的,我在课本上学的也是如此,它教了我怎么计算一个有符号数的原码反码补码,我却没有去弄清楚它们存在的意义。在这篇笔记,我会把我理解的写出来,为什么计算机中,有符号数都是用补码表示的。
为什么计算机用补码表示负数?
在计算机里,通常用补码表示负数,或者说计算机里只有一种码,那就是补码。
我们偶尔会在有些地方看到这样的说法:计算机有符号数中,正数用原码表示,负数用补码表示。另一种说法是计算机有符号数只有补码一种表示方式。
我个人的理解是都没错,其实也没必要分哪边是正确的叫法,毕竟正数的补码跟原码是完全相同的,如果内容完全一样,那叫法稍有不同也没关系。
我的话更偏向计算机只有补码一种表现方式,因为它的存在意义就是为了弥补使用原码时产生的缺陷。
我们先假设,计算机的有符号数都是用原码表示的,那么-15就是1000 1111
现在来作个简单的运算,5+(-15)=?
00000101
+10001111
---------
10010100
我们应该要求得的应该是-10,显然1001 0100的值是-20,它只是把两个数相加,然后再根据符号位判断是正负而已。
如果我们要用原码表示计算机内部有符号数,那就意味着我们不得不再作出另一种运算规则,让正数的相加用一种,跟负数的相加用另外一种。
这是十分复杂的,而现在有更简单的方法,就是引入补码。
补码的本质
在回答2的补码为什么能正确实现加法运算之前,我们先看看它的本质,也就是那两个步骤的转换方法是怎么来的。
要将正数转成对应的负数,其实只要用0减去这个数就可以了。比如,-8其实就是0-8。
已知8的二进制是0000 1000,-8就可以用0-8:0000 0000减去0000 1000得出
00000000
-00001000
---------
这时我们会发现不够减,我们都知道当位不够减的时候,会“借位”,这时就相当于是1 0000 0000减0000 1000了
100000000
-00001000
---------
11111000
而1 0000 0000等价于1111 1111+1,现在可以拆分成两个式子
11111111
-00001000
---------
11110111
+00000001
---------
11111000
这就是补码的转换步骤
由0减去8得出了-8,也就是补码(-8)和原码(+8)相加的和为0
这里有个前置条件,就是我们限定了只有8位,所以借位了就不用考虑“还”的问题了,如果是16位,则是继续往前借,直到最高位以后,也同样不必考虑还的问题,多少位的区别只是前面会多几个“1”。
为什么正数加法适用于2的补码?
现在测试一下,用补码是否能解决上面的问题,只用加法就计算出正确答案。
实际上,我们要证明的是,X-Y或X+(-Y)可以用X加上Y的2的补码完成。
Y的2的补码等于(11111111-Y)+1。所以,X加上Y的2的补码,就等于:
X + (11111111-Y) + 1
我们假定这个算式的结果等于Z,即 Z = X + (11111111-Y) + 1
接下来,分成两种情况讨论。
第一种情况,如果X小于Y,那么Z是一个负数。这时,我们就对Z采用2的补码的逆运算,求出它对应的正数绝对值,再在前面加上负号就行了。所以,
Z = -[11111111-(Z-1)] = -[11111111-(X + (11111111-Y) + 1-1)] = X - Y
第二种情况,如果X大于Y,这意味着Z肯定大于11111111,但是我们规定了这是8位机,最高的第9位是溢出位,必须被舍去,这相当于减去100000000。所以,
Z = Z - 100000000 = X + (11111111-Y) + 1 - 100000000 = X - Y
这就证明了,在正常的加法规则下,可以利用2的补码得到正数与负数相加的正确结果。换言之,计算机只要部署加法电路和补码电路,就可以完成所有整数的加法。
*深入解析
在看完几篇博客后,我产生了一些疑问,感觉脑袋有点乱,有些地方绕不过来,这里作为笔记,记录我对补码的深入理解并解答一些自己的疑问。
由于我经验不足,水平欠缺,感觉自己会说的不好或可能理解错误把你们带偏,所以不是很建议大家继续阅读,但如果有发现什么不对的,欢迎指正
首先,为什么补码可以用加法得到相减的结果?
之所以可以这样做,是因为计算机的有符号数是有位数“上限”的,8位计算机就是8位的上限,16位的就是16位的上限,一旦超出这个上限,多余的位就会被丢失,相当于不存在了
举例来说,假设现在我们是4位的计算机,它的表示范围是-8~7
我们现在尝试输出结果超出4位的运算:
1111+0001
先不去想他们值是什么,我们现在知道它的结果应该是1 0000,但由于我们现在是4位的机器,所以超出的一位自然就被“丢弃”了,所以结果应该是0000
现在再去看它们的值,是 -1+1=0,结果是准确的,我们用加法成功的做出了减法的效果,而这都是因为我们把超出最高位的位数“丢弃”了,这就是为什么补码可以用加法得到减法的效果。
那十进制呢,十进制可以这样吗?
我们在十进制运算的时候,几乎没有位数限制,毕竟人不是机器。当没有位数限制的时候,你无论怎么加,都无法作出丢弃超出最高位的位数的行为,因为根本没有最高位,所以是无法用加法作出减法的效果的。
如果一定想用十进制作出如上的效果需要两个条件,限制位数和重定义数字的值。
由于限制的位数,同时产生了一个衍生的条件,就是在有效位里,我们可以表示的数字是有限的,不像我们现实中的运算,正负无限延伸。既然产生了这个条件,我们就必须考虑在这个范围内,每个符号的顺序。
由于我们现在是十进制,只有10个符号,假设我们只限了一位,超出一位的都会被“丢弃”。
我们给这些符号赋上意义,上面这行我们只当它是符号,在下面的括号里则是它们的意义,范围是-5~4。
0 1 2 3 4 5 6 7 8 9
( 0 1 2 3 4 -5 -4 -3 -2 -1 )
- 1
- 2
之所以这样赋值,原因和补码一样,我们利用10减去1,得到了9,那么9就是1的负数也就是-1。
首先我们不用数字的方式计算结果,而是用移位的方式,符号如果是4+5的话就把4往后移5位。
我们将这串符号看成如下图一样的一个环,超出9的时候下一个又是0开始,现在我们不用“丢弃”最高位后的一位来看待,而是超出最高位时,下一个还是第一位。
现在我们用补码的方式来进行减的操作,3+(-2),在上面的符号就是3+8,我们把3后移8个位,得到符号1,它的意义是1,答案是正确的。
但如果是符号6加符号7,我们得到了符号3就会变成:(-3)+(-4)=3
这是因为我们计算的结果超出了有效范围-5~4,当超出这个范围时,它的计算结果就会变得不准确,就像int类型的范围是-2147483648——2147483647,如果你在超出了他们的范围计算,那得到的结果同样也是不准确的。