补码原理

补码

所有的计算机资料都规定:补码是将各位按位取反,再加1.

学的时候并没有觉得有什么疑问,但是写代码很多年之后,回过头去温习计算机原理,突然冒出来几个问题

为什么要有补码这个东西?为什么补码要按位取反?为什么要有左移右移?

这些都是为了计算机实现加减乘除才出现的。首先讲讲加减,计算机没有减法,所以就是加上负数来替代它。

举个例子吧
2的二进制是0000 0010,那么-2的表示是否是1000 0010呢
验证一下,假如它们成立就必须2+(-2)=0
两者的相加为1000 0100,不管前面符号位是0还是1,这个数都不等于0.

那么我们反过来想,我想要获取一个数的负数是多少,那么只要确保这个数加上它的负数等于0

还是刚刚的例子
2的二进制是0000 0010,那么0的二进制是0000 0000
我们知道二进制加法中,正常情况下2加上任何数都不能等于0,只有一种情况,那就是高位溢出。比如2加上某个数变成了1 0000 0000,这个时候计算机会弃掉高位的1.
这就很简单了,我把2按位取反,变成1111 1101,它加上2就是1111 1111,这个时候我只需要再加1,就能变成1 0000 0000.
所以将2按位取反再加1为 1111 1110,这就是补码。

补码的规则就有了,将各位按位取反,再加1. 补码就是用正数表示的负数形式。

因为符号位的特殊,0000 0000 - 1111 1111 一共能表示256个,所以1个字节表示的无符号范围是0 到28 -1(一共256个),有符号- 27 到 27-1(一共256个)

好,问题来了,无符号的范围不用说,有符号的范围为什么负数是-128,正数只能到127呢

我们可以看到,有符号位的二进制数第一位是符号,所以剩下的7位表示数
正数范围从0到127没有问题。
1到127对应的数都有其补码,对应了-127到-1
唯独剩下个0,0归为正数,它的二进制是0000 0000,那么现在就剩下一个1000 0000没有表示,因为符号位的原因,它相当于是-0.但是-0也是0,所以规定1000 0000表示负数最大值,也就是128

所以0的补码就是-128,所以有符号位的范围是-128到127

左移和右移

补码的出现是为了表示负数,来做加法和减法。那么左移和右移就是来做乘法以及除法。

左移是指把所有的位向左移动n位数,那么这个数就扩大了2n

左移是指把所有的位向又移动n位数,那么这个数就缩小了2n

这样我们就能实现乘法和除法,比如5*3就变成了5*(2+1)就等于5*21+5,也就是将5左移1位,再加上5。

除法假如除数是2的幂次方,比较简单,右移2的幂次位就行,比如5/2,只要把5右移1位得到整数位是2.

那么小数位呢?(小数位比较复杂,这边就不讨论了)假如除数不是2的幂次方呢?

x/y其实就是,x不断减y的过程。小学时候学的长长除法就是这个原理。
用二进制的除法x/y,比十进制容易写,商不是0即是1,而且如果除数大于除数的1倍,商就是标记在另一个位上面了

二进制除法x/y=0.1001/0.1011手工计算如下
           0.11  
     _______
0.1001/0.1001
        10010(后面补0)
        -1011
      ------
        111(余数)
        1110(后面补0)
        -1011
       --------
             1(余数)
           
设ri表示第i次运算后所得的余数,则:
若ri>0,则商1,余数和商左移1位,再减去除数,即ri+1=2ri-y
若ri<0,则商0,余数和商左移1位,再加上除数,即ri+1=2ri+y

用85/6来举例,85/6=1010101/110
a.101(0101)左移1位到第3位都小于110,因此商=000
b.1010(101)左移四位是1010,比110大,商=0001,余数=1010-110=100(101)
c.余数100(101)左移一位是1001,比110大,商=00011,余数=1001-110=11(01)
d.余数11(01)左移一位是110,等于110,商=000111,余数=0(1)
e.余数0(1)左移一位是01,小于110,商=0001110,余数=01

因此85/6=1010101/110=0001110,即14,余数为最后的余数1     

 

无符号数的左移和右移是没有问题的,往左移相当于增加2倍,往右移是减小2倍,

但是假如是有符号数呢,第一位是符号位,那么直接把后面的7位左移或者右移就可以了吗?

先来看左移

以-2为例
2转换成二进制是0000 0010
2的补码是 1111 1110
对1111 1110左移一位得到1111 1100
将补码-1得到1111 1011,再按位取反得到正数是0000 0100,是4
左移1位相当于是乘以2

所以有符号数的左移也是相当于增加2的幂次方倍

下面看右移,这就涉及到2种方式:

 

 

逻辑右移:把所有的位,包括符号位向左或向右移动,高位补0

算术右移:假如是正数,高位补零,假如是负数,高位补1。

看图中的例子,逻辑右移不能得到正确答案,算数右移才是正确的

还是以-4为例子, 我们先看下它的正数的例子
原始数值    0000 0100     
右移两位    0000 0001
最终结果          1

我们还是按结果倒推,-4右移两位我们想要的结果是-1
那么以-1为例,左移两位不就是-4吗
原始数值    1111 1111
左移两位    1111 1100

根据补码的规则,把正数的各位取反加1. 设想一下假如负数右移的过程中把高位取0,那么减去1之后,把各位再取反得到得正数,它得高位将会是1,这显然是不对得。

所以负数得右移应该以算数右移为准。

 

posted @ 2020-12-31 14:32  小鸡蛋白  阅读(1438)  评论(0编辑  收藏  举报