计算机中补码能算减法的原因和补码的由来,最强逻辑解析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/ZhangaZhaoLong/article/details/102741302

**

原码、反码、补码:

**

  • 这里的码都是二进制码,正数的原码、反码和补码都一样,负数的反码是符号位不变,其它位都取反,补码是反码+1

  • 正数的符号位为0,负数的符号位为1,比如你有一个字节,也就是8位,每8位就是符号位,符号位总是占用最后一个位的,为什么要用最后一位当符号位,因为一但没有符号位就不能同时表示正数和负数了,因为二进制只有1和0,所以选最后一位当符号位来区分正负正合适

  • 然后先说为什么补码是反码+1,因为我们的计算机为了简洁、高效,所以只提供了加法操作,所以为了能够算减法,所以使用补码完成任务(为什么补码能算减法后面再说),刚开始是想用反码的,但是很快反码就发现了问题,我们符号位在进行计算时也是参与的,虽然表达的意思不同,但我们为了简便,不用单独保存符号位,所以让符号位也参与计算,我们在使用反码计算的时候会有一个问题,就是在减数大于被减数时(5 - 1,5就是减数,1是被减数),会有问题因为我们在进行减法的时候,实际上计算机进行的是加法,用反码的形式来实现这种加法的话,如果一但符号位发生了进位变成0(现在我们关注的是为什么符号位一定会进位成0,至为什么这样加法能算减法一会再说),那就会认为它是一个正数,正数的原码,反码和补码都是相同的,所以就不会再进行变化,这本身也不是什么问题,但是一但进位,就会丢失精度,因为你只有8位,进一位后就没有了,所以会少1,就比如:二进制10 - 01 = 10 + 10 = 00,少了一个一,那为什么一但减数大于被减数符号位就一定会进位,因为减数比被减数大,也就是说减数最高位1(因为二进制只有1和0,100中1就是高位)之后的被减数肯定全为1(因为被减数是以反码存储的,又因为它比减数小,所以减数最高位1之后的被减数的原码位数肯定是0,如果有1就比被减数大了,因为是反码存储所以一定为1),因为被减数不能比减数大,所以最大的被减数是和减数一样大,也就减数为0的地方它为1,减数为1的地方它为0(这是两数相等的情况,一阵再说),因为被减数比减数小,所以肯定有一个减数为1的地方,被减数也为1(因为它是反码存储,1就是0,总之至少要比减数少1),这样就会发生进位,又因为比这位高一位的位数,减数和被减数如果都为1,那说明还要进位,如果只有其中一个为1(当减数为1时,还是要进位,当被减数为1时,也要进位),如果都不是1(那就是都是0了,但想一想如果都是0,被减数是以反码的形式存的,所以被减数这位的原码是1,因为现在这位是高位,所以代表到现在被减数比减数大,但因为减数比被减数大,所以再往上的高位,肯定有一位减数和被减数都是1,这样才能比被减数大,所以就会发生进位),所以依此推类,在最高位时一定会发生进位,又因为被减数的后面全是1,所以直接导致符号位会进1变成0,这样就会少1了,这是使用反码的问题之1,还有一个问题就是符号位的问题,想一想0的表示方法是有两种的,一种是0000 0000还有一种是负1000 0000,这样就会造成二义性,所以使用把码不能完成减法的任务,这种情况就是在两数都相等进行减法时的情况会出现的问题,然后如果减数比被减数小的话没有什么问题,一定不会进位,根据第一个情况可以推出来

  • 所以我们使用补码来解决这些问题,首先像第一个问题,少了一个1,那我就给被减数的反码加上一个1就行了,为什么给是给被减数的反码加1,好像给那个减数加1,也可以,但想想,那个减数是一个正数,如果我再用它加一个正数,就不需要加1,这样做就错了,因为只有在加负数时(5 - 1,也可以是 5 + (-1))才会出现符号位进位为0的情况(正数人家直接加就行了,没这么麻烦),所以负数才有反码和补码(它们两个的出现就是为了完成减法,所以就可以理解为什么正数没有反码和补码了,补码的出现正是反码推演出来的),因为负数是以补码的形式来算的,这时候符号位变化了,就不能按原位返回了,因为它符号位变了之后就成正数了,就没有反码和补码,就不能往回推了,而正数都是以原码形式算的,就算进位,符号位改变也是正常的,然后就是你会说如果是减数小于被减数时,加1不就有问题了吗(因为原本这样算是可以的),但是我们知道我们是按补码的形式存的,编译器一看,符号位为1(因为这种情况符号位是不变的),就会按补码的形式,恢复成原码会在恢复原码后自动加1来补掉这个多1的问题,加1只是解决符号位改变后成正数不会自动居处的问题,然后是第二个问题,0的二义性,因为我们采取补码的形式来消除这种二义,只保留正0,原因很简单,就是当要变成负0时,我提前加了一个1,让它直接成为了正0,之后它就是正数的不会在发生变化,而比它小一位的数因为也加了1,但没有导致符号位发生变化,所以它还是补码会按补码还原的方式来还原原码,到时候会自动加1越过那0

  • 然后说为什么补码形式的加法做出来的是减法,因为你想,我们用反码举例,反码是什么是原码取反后的值,也可以理解为还差多少就到0了,因为负数最大是0,到底还差多少,就是差反码的位数为0的那些位,也就是它的原码的大小,这时我们进行加法运算,如果减数比被减数大的话,那肯定减数的原码比被减数的原码大,所以肯定会超过0,超过0之后就变成正数了,但它为了加到正数刚好消耗了被减数的大小,这时就是做完减法之后的效果,如果减数比被减数小话,这时肯定不会变成正数,但是它会让那个反码变大(这只是表象,因为这时候是不看符号位的,如果是负数值变大,那它真正的值就会变小),会变小多少,会变小减数减数那么大,将反码转成原码后,它的数字是变小了(比如从-5变成-1了数字变小,值变大),但它的值变大了变大了多少变大了减数的大小,因为正数减负数也是增大负数(负数就是越靠近0越大),现在我们换成补码,它只是多了一个加1的操作,来保证正确性,原理是一样的(如果是负数+负数,其实都是一样的,就是绕了一个来回,也就是负数和正数在满足条件后是可以转换的,也就是循环过去),这就是补码能做减法的原因

猜你喜欢

转载自blog.csdn.net/ZhangaZhaoLong/article/details/102741302