zoukankan      html  css  js  c++  java
  • Java的位运算符与二进制转换

    转换:

    Java整型数据类型有:byte、char、short、int、long。要把它们转换成二进制的原码形式,必须明白他们各占几个字节。,一个字节==8位数

     数据类型                           所占位数
          byte                                       8 
          boolean                                8
          short                                    16
          int                                         32 
          long                                      64 
          float                                      32 
          double                                  64 
          char                                     16

    byte
    正数最大位0111 1111,也就是数字127 
    负数最大为1111 1111,也就是数字-128
    反码与补码
    1、反码:
            一个数如果是正,则它的反码与原码相同;
            一个数如果是负,则符号位为1,其余各位是对原码取反;

    2、补码:利用溢出,我们可以将减法变成加法
           对于十进制数,从9得到5可用减法:
           9-4=5    因为4+6=10,我们可以将6作为4的补数
           改写为加法:
           9+6=15(去掉高位1,也就是减10)得到5.

           对于十六进制数,从c到5可用减法:
           c-7=5    因为7+9=16 将9作为7的补数
           改写为加法:
           c+9=15(去掉高位1,也就是减16)得到5.

        在计算机中,如果我们用1个字节表示一个数,一个字节有8位,超过8位就进1,在内存中情况为(100000000),进位1被丢弃。

        ⑴一个数为正,则它的原码、反码、补码相同
        ⑵一个数为负,刚符号位为1,其余各位是对原码取反,然后整个数加1
         详细请参考http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html
    Integer.toHexString的参数是int,如果不进行&0xff,那么当一个byte会转换成int时,由于int是32位,而byte只有8位这时会进行补位,
    例如补码11111111的十进制数为-1转换为int时变为11111111111111111111111111111111好多1啊,即0xffffffff但是这个数是不对的,这种补位就会造成误差。
    和0xff相与后,高24比特就会被清0了,结果就对了。

    还需要明白一点的是:计算机表示数字正负不是用+ -加减号来表示,而是用最高位数字来表示,0表示正,1表示负

    在计算机系统中,数值一律用补码来表示(存储)。
    主要原因:使用补码,可以将符号位和其它位统一处理;同时,减法也可按加法来处理。另外,两个用补
    码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。
    补码与原码的转换过程几乎是相同的。
    数值的补码表示也分两种情况:
    (1)正数的补码:与原码相同。
          例如,+9的补码是00001001。
    (2)负数的补码:符号位(最高位)为1,其余位为该数绝对值的原码按位取反;然后整个数加1。
          例如,-7的补码:因为是负数,则符号位为“1”,整个为10000111;其余7位为-7的绝对值+7的原码
         0000111按位取反为1111000;再加1,所以-7的补码是11111001。
    已知一个数的补码,求原码的操作分两种情况:
    (1)如果补码的符号位为“0”,表示是一个正数,所以补码就是该数的原码。
    (2)如果补码的符号位为“1”,表示是一个负数,求原码的操作可以是:符号位为1,其余各位取反,然后再整个数加1。
         例如,已知一个补码为11111001,则原码是10000111(-7):因为符号位为“1”,表示是一个负数,所以该位不变,仍为“1”;其余7位1111001取反后为0000110;再加1,所以是10000111。

    源码:是什么就是什么。负数就是最前面符号位为1。
    反码:正的就是补码,负的就是各位取反,0换1,1换0,注意,最高位符号为不变。
    补码:正的就是源码,负的就是反码+1
    比如: -1 -2
    以8位二进制为例
    源码:10000001 10000010
    反码:11111110 11111101
    补码:11111111 11111110
    补码这样做的好处是什么呢?
    请看-1+(-2)电脑怎么做:
    用源码:10000001 + (10000010)=00000011 这是什么?是-3吗?不是,是3。所以不能直接用源码做加法。
    用反码:11111110 + (11111101)=11111011 这是什么?是反码的"-4"
    用补码:11111111 + (11111110)=11111101 末尾减一再取反得10000011,所以结果是补码的-3。
    反码为什么出错?以4位数为例,高位为符号位(括号内为绝对值):
    1010 (2)取反 1101 (5)
    1011 (3)取反 1100 (4)
    然后 -2 + (-3) 变成了 -(5 + 4)超出8的部分舍去,得 1001,再取反得 1110,成了-6
    究其原因:各位取反的两数相加:1010+0101=1111必是全1即绝对值为7,2->5,3->4,相对于8共偏差了2,然后9=1mod8,1->6,只修正了1点偏差,
    结果就出现了1的偏差。补码中末尾加一就是修正了该偏差,得到正确的结果。即2->6,3->5.相对于8无偏差11=3mod8,3->5。

    位运算符:

    位移进制运算

    带符号右移 题:-15 >> 2 = -4

    15原码:   00000000 00000000 00000000 00001111 //32位,二进制
    反码:    11111111 11111111 11111111 11110000 //0变1,1变0
    补码:    11111111 11111111 11111111 11110001 //最后位加1,-15二进制
    右移2位:  11111111 11111111 11111111 11111100 //右边丢弃2位,前面30位保留,左边补1
    取反:      00000000 00000000 00000000 00000011 //0变1,1变0
    +1:                                       3+1
    结果:                                     =-4 //负号保留,十进制

    带符号左移 题: 10 << 2 = 40
    10 补码:    00000000 00000000 00000000 00001010 //32位,二进制
    左移2位:    00000000 00000000 00000000 00101000 //左边丢弃2位,右边补0
    结果:                                        40 //十进制
     

    无符号右移 题:-4321 >>> 30 = 3
    4321原码:         00000000 00000000 00010000 11100011 //32位,二进制
    反码:           11111111 11111111 11101111 00011100 //0变1,1变0
    补码:           11111111 11111111 11101111 00011101 //最后位加1,-4321二进制
    无符号右移30位:  00000000 00000000 00000000 00000011 //右边丢弃30位,前面二位保留,左边补0
    结果:                                                3 //十进制


    & 位逻辑与 题:44 & 21 = 4
    44 补码:    00000000 00000000 00000000 00101100 //32位,二进制
    21 补码:    00000000 00000000 00000000 00010101 //32位,二进制
    & 运算:     00000000 00000000 00000000 00000100 //对应的两个二进制位均为1时 结果位才为1 否则为0
    结果:                                         4 //十进制   
                                   
    | 位逻辑与 题:9 | 5 = 13
    9 补码:    00000000 00000000 00000000 00001001 //32位,二进制
    5 补码:    00000000 00000000 00000000 00000101 //32位,二进制
    | 运算:    00000000 00000000 00000000 00001101 //对应的二个二进制位有一个为1时,结果位就为1
    结果:                                       13 //十进制

    ^ 位逻辑异或 题: 9 ^ 5 = 12
    9 补码:    00000000 00000000 00000000 00001001 //32位,二进制
    5 补码:    00000000 00000000 00000000 00000101 //32位,二进制
    | 运算:    00000000 00000000 00000000 00001100 //对应的二进制位相异时,结果为1
    结果:                                       12 //十进制

    ~ 位逻辑反 题: ~9 = -10
    9 补码:    00000000 00000000 00000000 00001001 //32位,二进制
    ~ 运算:    11111111 11111111 11111111 11110110 //最高位为1表示为一个负数,则进行取反加1
    取反:      00000000 00000000 00000000 00001001 //32位,二进制
    +1:                                      9+1 //32位,二进制
    结果:                                      -10 //十进制

    由于数据类型所占字节是有限的,而位移的大小却可以任意大小,所以可能存在位移后超过了该数据类型的表示范围,于是有了这样的规定: 如果为int数据类型,且位移位数大于32位,则首先把位移位数对32取模,不然位移超过总位数没意义的。所以4>>32与4>>0是等价的。

    如果为long类型,且位移位数大于64位,则首先把位移位数对64取模,若没超过64位则不用对位数取模。

    如果为byte、char、short,则会首先将他们扩充到32位,然后的规则就按照int类型来处理。

     

    实际应用:


    1.  判断int型变量a是奇数还是偶数    
         a&1  = 0 偶数 
         a&1 =  1 奇数 
    2.  求平均值,比如有两个int类型变量x、y,首先要求x+y的和,再除以2,但是有可能x+y的结果会超过int的最大表示范围,所以位运算就派上用场啦。
          (x&y)+((x^y)>>1); 
    3.  对于一个大于0的整数,判断它是不是2的几次方
        ((x&(x-1))==0)&&(x!=0); 
    4.  比如有两个int类型变量x、y,要求两者数字交换,位运算的实现方法:性能绝对高效
        x ^= y; 
        y ^= x; 
        x ^= y; 
    5. 求绝对值
        int abs( int x ) 
       { 
         int y ; 
         y = x >> 31 ; 
        return (x^y)-y ;        //or: (x+y)^y 
       }
    6.  取模运算,采用位运算实现:
         a % (2^n) 等价于 a & (2^n - 1) 
    7.  乘法运算   采用位运算实现
         a * (2^n) 等价于 a << n
    8.   除法运算转化成位运算
          a / (2^n) 等价于 a>> n 
    9.   求相反数
          (~x+1) 
    10  a % 2 等价于 a & 1 

     

     

  • 相关阅读:
    C# 综合练习题目 及 答案解析
    SQL数据库子查询练习题及解析
    SQL数据库 连接查询、变量、选择、循环、延时语句等
    SQL数据库中模糊查询、排序、聚合函数、数学函数、字符串函数、时间日期函数、转换、函数转换等
    SQL数据库的创建及简单增删改查语句运用
    SQL数据库简介
    ado.net操作数据库
    轻松美化窗体
    面向对象(委托)
    面向对象(五大原则)
  • 原文地址:https://www.cnblogs.com/lulu638/p/4692089.html
Copyright © 2011-2022 走看看