• 位运算


      程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算。举个例子,6的二进制是110,11的二进制是1011,那么6 and 11的结果就是2,它是二进制对应位进行逻辑运算的结果(0表示False,1表示True,空位都当0处理)。

    含义  Pascal c     java  
    按位与 and & &
    按位或 or | |
    按位异或 xor ^ ^
    按位取反 not ~ ~
    按位左移 shl << <<
    带符号右移 shr >> >>
    无符号右移     >>>

    运算符说明:

       1.按位与:   

         and运算通常用于二进制取位操作,例如一个数 and 1的结果就是取二进制的最末位。这可以用来判断一个整数的奇偶,二进制的最末位为0表示该数为偶数,最末位为1表示该数为奇数。

       2.按位或:

         or运算通常用于二进制特定位上的无条件赋值,例如一个数or 1的结果就是把二进制最末位强行变成1。如果需要把二进制最末位变成0,对这个数or 1之后再减一就可以了,其实际意义就是把这个数强行变成最接近的偶数。

       3.按位异或:

         异或的符号是^。按位异或运算, 对等长二进制模式按位或二进制数的每一位执行逻辑按位异或操作. 操作的结果是如果某位不同则该位为1, 否则该位为0.下面是一个交换例子:

           a=a ^ b;

           b=a ^ b;

           a=a ^ b;

       4.按位取反:

         ~运算的定义是把内存中的0和1全部取反。使用~运算时要格外小心,你需要注意整数类型有没有符号。如果~的对象是无符号整数(不能表示负数),那么得到的值就是它与该类型上界的差,因为无符号类型的数是用00到$FFFF依次表示的。如果~的对象是有符号的整数,写在后面.

       5.按位左移:

         a << b就表示把a转为二进制后左移b位(在后面添b个0)。例如100的二进制为1100100,而110010000转成十进制是400,那么100 << 2 = 400。可以看出,a << b的值实际上就是a乘以2的b次方,因为在二进制数后添一个0就相当于该数乘以2。

         可以用<<来定义Max_N等常量,例如 1<<16 -1表示65535  

        6.按位右移:

         和<<相似,a >>b表示二进制右移b位(去掉末b位),相当于a除以2的b次方(取整)。我们也经常用>> 1来代替div 2,比如二分查找、堆的插入操作等等。想办法用shr代替除法运算可以使程序效率大大提高。

        注意:左移:

          高位删除,低位补0,但是注意有时会溢出

           int i = 0x40000000; //16进制的40000000,为2进制的01000000...0000
           i = i << 1;
    那么,i在左移1位之后就会变成0x80000000,也就是2进制的          100000...0000,符号位被置1,其他位全是0,变成了int类型所能表示的最小值,32位的               int这个值是-2147483648,溢出,若再左移一位则为0.

         右移:

         符号整数不影响,对于有符号整数符号位不变,低位删除

                int i = 0x80000000;
            i = i >> 1;  //i的值不会变成0x40000000,而会变成0xc0000000

          如何消除右移对符号的影响,如java的<<<

         1.用unsigned int强制转换

           2.与0x7fffffff与操作

    #include<iostream>
    using namespace std;
    int main()
    {
        short int a=0x8000;
        cout<<(a>>1)<<endl;
        cout<<((unsigned short int)a>>1)<<endl;
        cout<<((0x7fff)&(a>>1));
        return 0;
    }

         

    优先级

    1      ~
    2 <<,>>
    3 &
    4 ^
    5 |
    6 &=、^=、|=、<<=、>>=

    简单事例

        去掉最后一位 | (101101->10110) |                 x >> 1
        在最后加一个0 | (101101->1011010) |             x << 1
        在最后加一个1 | (101101->1011011) |             x << 1+1
        把最后一位变成1 | (101100->101101) |              x | 1
        把最后一位变成0 | (101101->101100) |            x | 1-1
        最后一位取反 | (101101->101100) |               x ^ 1
        把右数第k位变成1 | (101001->101101,k=3) |           x | (1 << (k-1))
        把右数第k位变成0 | (101101->101001,k=3) |           x & ~ (1 << (k-1))
        右数第k位取反 | (101001->101101,k=3) |            x ^ (1 << (k-1))
        取末三位 | (1101101->101) |                  x & 7
        取末k位 | (1101101->1101,k=5) |                x & (1 << k-1)
        取右数第k位 | (1101101->1,k=4) |                x >> (k-1) & 1
        把末k位变成1 | (101001->101111,k=4) |            x | (1 << k-1)
        末k位取反 | (101001->100110,k=4) |               x ^ (1 << k-1)
        把右边连续的1变成0 | (100101111->100100000) |        x & (x+1)
        把右起第一个0变成1 | (100101111->100111111) |        x | (x+1)
        把右边连续的0变成1 | (11011000->11011111) |          x | (x-1)
        取右边连续的1 | (100101111->1111) |                                   x ^ (x+1)) >> 1
        去掉右起第一个1的左边 | (100101000->1000) |         x & (x ^ (x-1))(或 x & (-x))

     负数的位运算
        
     1 #include<stdio.h>
     2 int main()
     3 {
     4     short int a,b;
     5     a=0x0000;
     6     b=0x0001;
     7     printf("%d  %d
    ",a,b);
     8     a=0xFFFE;
     9     b=0xFFFF;
    10     printf("%d  %d
    ",a,b);
    11     a=0x7FFF;
    12     b=0x8000;
    13     printf("%d  %d
    ",a,b);
    14     return 0;
    15 }

     

      其中前两个数是内存值最小的数,中间两个数则是内存值最大的数,最后输出的两个数是正数与负数的分界处。二进制的第一位是用来表示正负号的,0表示正,1表示负。正数的原码,补码,反码都相同,都等于它本身.负数的补码是:符号位为1,其余各位求反,末位加1,反码是:符号位为1,其余各位求反,但末位不加1

     

     

  • 相关阅读:
    Android 架构:Android Jetpack 架构组件的学习和分析
    Android 看源码学 Binder
    Android Okhttp 源码分析(待完成)
    Android Glide 源码分析系列(待完成)
    界面2
    使用spring 4.0 + maven 构建超简单的web项目
    maven中跳过单元测试
    Hibernate+maven+eclipse 实现自动建表
    android开发学习---开发一个简易的短信发送器
    java面试题--实现一个百亿的计算器
  • 原文地址:https://www.cnblogs.com/whzlw/p/4486618.html
Copyright © 2020-2023  润新知