原码、反码、补码、移位运算符

in TCEH with 0 comment

前言

好记性不如烂笔头。原先上学学过的知识,如今变得模模糊糊,导致查阅源码时,总是磕磕绊绊。这里做个记录,时常温故而知新。

原码

原码(true form)是一种计算机中对数字的二进制定点表示方法。原码表示法在数值前面增加了一位符号位;(即最高位为符号位):正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小。

缺点:原码不能直接参加运算,可能会出错。

例如数学上,1+(-1)=0,而在二进制中原码00000001+10000001=10000010,换算成十进制为-2。显然出错了。

示例

        // 十进制数 正数
        int num = 53;
        // 53的8位二进制原码 00110101

        // 十进制数 负数
        int num = -53;
        // -53的8位二进制原码 10110101

反码

反码通常是用来由原码求补码或者由补码求原码的过渡码。根据定义,可以得到机器数的反码的整数和小数中“0”的表示形式各有2种,“+0”和“-0”不一样,以8位机器数为例,整数的“+0”原码为0,0000000,反码为0,0000000;整数的“-0”原码为1,0000000,反码为1,1111111;小数的“+0”原码为0.0000000,反码为0.0000000;小数的“-0”原码为1.0000000,小数的“-0”反码为1.1111111。反码跟原码是正数时,一样;负数时,反码就是原码符号位除外,其他位按位取反。

示例

        // 十进制数 正数
        int num = 53;
        // 53的8位二进制原码 00110101
        // 53的8位二进制反码 00110101 

        // 十进制数 负数
        int num = -53;
        // -53的8位二进制原码 10110101
        // -53的8位二进制反码 11001010 

补码

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。正整数的补码是其二进制表示,与原码相同;负整数的补码,将其原码除符号位外的所有位取反(0变1,1变0,符号位为1不变)后加1(其实就是原码转化为反码,再加1,即为补码)。更多细节,请点击如何理解补码百度百科

示例

        // 十进制数 正数
        int num = 53;
        // 53的8位二进制原码 00110101
        // 53的8位二进制反码 00110101 
        // 53的8位二进制补码 00110101 

        // 十进制数 负数
        int num = -53;
        // -53的8位二进制原码 10110101
        // -53的8位二进制反码 11001010 
        // -53的8位二进制补码 11001011

总结:正数时,原码、反码、补码均是其二进制表示的相同数值。负数时,反码就是原码符号位除外,其他位按位取反,补码则是反码加1。

移位运算符

移位运算符在程序设计中,是位操作运算符的一种。移位运算符可以在二进制的基础上对数字进行平移。按照平移的方向和填充数字的规则分为三种:<<(左移)、>>(带符号右移)和>>>(无符号右移)。

左移运算符(<<)规则

按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。

语法格式:
需要移位的数字 << 移位的次数
  例如: 11 << 2,则是将数字11左移2位
计算过程:
  首先把11转换为二进制数字0000 0000 0000 0000 0000 0000 0000 1011,然后把该数字高位(左侧)的两个0移出,其他的数字都朝左平移2位,最后在低位(右侧)的两个空位补零。则得到的最终结果是0000 0000 0000 0000 0000 0000 0010 1100,则转换为十进制是44。

例如: -11 << 2,则是将数字-11左移2位
计算过程:
  首先把-11转换为二进制数字1111 1111 1111 1111 1111 1111 1111 0101(11的补码),然后把该数字高位(左侧)的两个1移出,其他的数字都朝左平移2位,最后在低位(右侧)的两个空位补零。则得到的最终结果是1111 1111 1111 1111 1111 1111 1101 0100(符号位为1,则为补码),转化成反码为1111 1111 1111 1111 1111 1111 1101 0011,再转化成原码1000 0000 0000 0000 0000 0000 0010 1100为则转换为十进制是-44。

备注:二进制100 - 1 = 011。可以这么理解,将二进制100比如十进制的100,那么十进制的100 - 1 = 99;在个位减个位,0 - 1不够减,向十位借,十位还是不够减,向百位借。即将百位的1借给十位,则十位变成10,十位借1给个位,个位则为10。最终个位的10-1=9;十位等于9,百位为0;因此100 - 1 = 99;同理,二进制逢二进一,二进制100的最高位借1给中间位,中间位即为2,中间位借1给最低位,即最低位为2.因此二进制100 - 1 = 011;

数学意义:
在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方。

右移运算符(>>)规则

按二进制形式把所有的数字向右移动对应位移位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1。

语法格式:
需要移位的数字 >> 移位的次数
  例如11 >> 2,则是将数字11右移2位
计算过程:
11的二进制形式为:0000 0000 0000 0000 0000 0000 0000 1011,然后把低位的最后两个数字移出,因为该数字是正数,所以在高位补零。则得到的最终结果是0000 0000 0000 0000 0000 0000 0000 0010。转换为十进制是2。

  例如-11 >> 2,则是将数字-11右移2位
计算过程:
-11的二进制形式为:1111 1111 1111 1111 1111 1111 1111 0101(11的补码),然后把低位的最后两个数字移出,因为该数字是负数,所以在高位补1。则得到的结果是1111 1111 1111 1111 1111 1111 1111 1101。转成反码是1111 1111 1111 1111 1111 1111 1111 1100。转成原码1000 0000 0000 0000 0000 0000 0000 0011。转换为十进制是-3。

数学意义:
右移一位相当于除2,右移n位相当于除以2的n次方。

无符号右移运算符(>>>)规则

按二进制形式把所有的数字向右移动对应位数,低位移出(舍弃),高位的空位补零。对于正数来说和带符号右移相同,对于负数来说不同。

  例如-11 >>> 2,则是将数字-11右移2位

计算过程:
-11的二进制形式(负数用补码表示)为:1111 1111 1111 1111 1111 1111 1111 0101,然后把低位的最后两个数字移出,高位的空位补零。则得到的最终结果是0011 1111 1111 1111 1111 1111 1111 1101。由于无符号右移之后为正数,正数的补码和原码是一致的。所有转换为十进制是1073741821

总结

补码是负数在计算机中的二进制表示方法。因此,正数位移操作用原码,负数位移操作用补码

Comments are closed.