• 补码原理


    补码

    所有的计算机资料都规定:补码是将各位按位取反,再加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,这显然是不对得。

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

  • 相关阅读:
    Linux命令-压缩解压命令:gzip、gunzip
    Linux命令-用户管理命令:useradd,passwd,who,w
    Linux命令-帮助命令:help
    Linux命令-帮助命令:whatis,apropos
    Linux命令-帮助命令:man
    Linux命令-文件搜索命令:grep
    Linux命令-文件搜索命令:whereis
    Linux命令-文件搜索命令:which
    Linux命令-文件搜索命令:locate
    Linux命令-文件搜索命令:find
  • 原文地址:https://www.cnblogs.com/xiaojidanbai/p/14216550.html
Copyright © 2020-2023  润新知