zoukankan      html  css  js  c++  java
  • 1的补码及2的补码

    一、计算机的负数表示

    二、1的补码One's complement——反码

    三、2的补码Two's complement——补码

       

    一、计算机的负数表示

    数据在计算机中由一个一个的0,1比特表示,所以在表示负数的时候,不能直接添加符号'-'来表示这是个负数,必须采用一些规范或者约定来区分正数和负数。

    有四种比较有名的表示负数的方法:原码(sign-and-magnitude)1的补码(one's complement)2的补码(two's complement),以及excess-k(即Offset binary)

       

    二、1的补码One's complement——反码

    1、特性

    1的补码比较简单,它在表示负数的时候简单把该负数的绝对值(即相应的正数)的二进制位全部反转。比如1用0000 0001表示,那么-1就用1111 1110表示。

    比较有意思的是由于+0用0000 0000表示,反转后1111 1111就表示-0。所以在1的补码里有两个零。

       

    Binary value

    Ones' complement interpretation

    Unsigned interpretation

    00000000

    +0

    0

    00000001

    1

    1

    01111101

    125

    125

    01111110

    126

    126

    01111111

    127

    127

    10000000

    127

    128

    10000001

    126

    129

    10000010

    125

    130

    11111101

    2

    253

    11111110

    1

    254

    11111111

    0

    255

       

    From <http://en.wikipedia.org/wiki/Signed_number_representations#Ones.27_complement>

       

    以上表举例来看:(-1)+1 = 0,对应的1的补码加法

    0000 0001 ——-1

      +1111 1110 ——1

    =========

    1111 1111——-0

       

    由于负数都是由相应的正数二进制位全反转得到的,所以这里有个特性就是把它们相加的话会得到一个二进制位为全1的数,在1的补码的表示方法中,全1表示-0。这也是为什么这种表示方法叫做"1的补码"。1的补码在IP,TCP,UDP,ICMP等协议头中应用于计算校验和。

    还有一点很有意思的是,在1的补码表示的数中,所有的正数最高比特都是0,而所有的负数最高比特都是1。而且它的正最大值是127,没有向上加过去表示128。在我们平常来看,最高位表示符号位0代表正,1代表负是极为正常的事。但是在1的补码里,没有设置符号位,之所以造成这样的"巧合",存在着一定的必然性。我们假设它能表示到128,即1000 0000,那么-128就表示成0111 1111,可是0111 1111已经用来表示127了,这就造成了冲突。其实问题很简单,我们可以把最高位的0,1看作是前缀码,用这位前缀码保证对正数的反转操作不存在冲突。这也是为什么正数最大只能表示到127。

    更有意思的是,国内将1的补码翻译成反码,其求负数的反码时,"保留符号位,将其余的比特进行反转"。但是这样就不能解释为什么有-0的存在。更不能解释在IP,TCP,UDP,ICMP协议头里求校验和时所谓的"反码求和"是怎么回事。

    想象有一根数轴,两端分别向正无穷和负无穷延伸,从中间0的位置一刀劈下去(0有两个),分成非负和非正的两半。

       

    这根轴看起来很对称。

    如果我们从+0开始数数,即从0000 0000开始不断加1(0000 0001,0000 0002,0000 0003…),我们会发现我们不停在循环('0'-'127','-127'-'0')。原因是当我们数到127(0111 1111)时,再加1变成-127(1000 0000)。这个时候看起来是这样的:

       

       

       

    2、1的补码的加法

    1的补码的加法跟其它的加法是一样的,只是它有个循环进位(end-around carry)概念。它要求把最后结果的进位加回到最后的结果中去。

    比如计算(-1)+2:

    1111 1110

       +0000 0010

    =========

     (1)0000 0000

               + 1 进位

    =========

    0000 0001

       

    为什么要这样呢?

    我们考虑在①+127处,我们加1变成-127,在-127处我们再减1,同样会出错。在应用的时候我们要注意这种超出范围的错误。②处,由于我们有两个零,在做加法时,我们要加回一个0去。比如还是计算(-1)+2,

    我们拿上面的圈来想象计算的过程,绕着圈顺时针走步,圈上的每一个数字对应一个走步,计算(-1)+2,也即在(-1)处走两步,我们走到+0处。由于正常的运算中没有两个0,我们在最后回加一个1。

    由于溢出,得到的结果等于0(0000 0000),就是因为中间-0占用了一个计数,我们把进位1加最后结果上,得到正确结果1:

    1111 1110

      +0000 0010

    =========

    (1)0000 0000

              + 1

    =========

    0000 0001

       

    减法可以用加法来表示。

       

    三、2的补码Two's complement——补码

    1、从1的补码的角度来理解补码加法

    负数的补码经常用反码加一来计算。将补码与1的补码加法联系起来可以理解为什么可以用补码加法代替减法。

    将1的补码中-0的编码空出来给-1用,后续数值依次前移,最后1000 0000会空出来,我们给它分配-128。因此,我们可以取值[-1,-128]U[0,127]。

       

    因此,补码根据反码(即前文1的补码)加一来计算其实就是把-0挤掉,留了个位置给-128。

    Binary value

    Two's complement interpretation

    Unsigned interpretation

    00000000

    0

    0

    00000001

    1

    1

    01111110

    126

    126

    01111111

    127

    127

    10000000

    128

    128

    10000001

    127

    129

    10000010

    126

    130

    11111110

    2

    254

    11111111

    1

    255

       

    From <http://en.wikipedia.org/wiki/Signed_number_representations#Ones.27_complement>

    那为什么可以用补码来计算减法呢?理解了反码的加法,其实就不难理解为什么补码可以直接用来计算减法了。

       

    2、快速写出补码

    正数的补码是它本身。

    负数的补码:

    从右往左看,从第一个1出现的位置的下一位开始,反转比特,符号位不反转。比如(11010110) 的补码为10101010。

       

    参考资料

    【1】http://en.wikipedia.org/wiki/Signed_number_representations#Sign-and-magnitude_method

  • 相关阅读:
    静态方法
    表单的验证
    jquery笔记
    jquery参考
    dom体系 和获取其他页面的Window对象
    jsRegExp对象
    jsDate对象
    js案例
    Sqli-Labs 闯关 less 42-53
    Sqli-Labs 闯关 less 32-41
  • 原文地址:https://www.cnblogs.com/codetravel/p/4361345.html
Copyright © 2011-2022 走看看