zoukankan      html  css  js  c++  java
  • c++ 位操作

    本篇由作者原创(部分参考)

    注意:位操作只适用于整型数据的操作,对于float型和double型数据编译器会报错。

    位操作有与、或、异或、取反、左移、右移六种,符号及运算规则如下:

     符号

     描述

     运算规则                      

    &      

     与

    两个位都为1时,结果才为1

    |  

     或    

    两个位都为0时,结果才为0

    ^    

    异或

    两个位相同为0,相异为1

    ~   

    取反

    0变1,1变0

    << 

    左移

    各二进位全部左移若干位,高位丢弃,低位补0

    >> 

    右移

    各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

    注意:1.位操作的优先级比较低,应该使用括号保证提前运算。

       2.对于移位操作来讲必须要注意是算术移位还是逻辑移位(算术左移、右移主要进行有符号数的倍增、倍减。逻辑左移、   右移主要进行无符号数的倍增、倍减。)

          逻辑移位:不考虑符号位,也就是不考虑正负数的移位(逻辑移位不管是左移还是右移都是空缺处补0)

          算术移位:考虑符号位,也就是正负数的移位(算数移位要保证符号位不改变)

              1)其中算术左移和逻辑逻辑左移的思想一样,缺位补0。

              2)算术右移的移位过程中,缺位由符号位决定(符号位是1,缺位补1。符号位是0,缺位补0)

    注:(数据在计算机以补码存储)补码在计算机算术左移过程中符号位可能发生改变(溢出)。


    位操作可以对某字节中的某段字段赋值、修改、取值(需要借助移位)等操作

    实例:(这里以对字节为单位进行位操作,获取字节中的10)

    #define  TEMP_NUMBER_INITINAL  0x00000000    //十六进制表示 0

    #define  TEMP_NUMBER  0x000000a0   //十六进制表示 160

    1 void main(){
    2       int   number=NULL;
    3       number = TEMP_NUMBER;
    4       cout<<(number>>8)<<endl;//此时输出的是10
    5 }        

    位操作的一般应用:

    1.判断奇偶

    只要根据最未位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用if (a & 1 == 0)代替if (a % 2 == 0)来判断a是不是偶数。

    下面程序将输出0到100之间的所有奇数。

    [cpp] view plaincopy
     
    1. for (i = 0; i < 100; ++i)  
    2.     if (i & 1)  
    3.         printf("%d ", i);  
    4. putchar(' ');  

    2.交换两数

    一般的写法是:

    [cpp] view plaincopy
     
    1. void Swap(int &a, int &b)  
    2. {  
    3.     if (a != b)  
    4.     {  
    5.         int c = a;  
    6.         a = b;  
    7.         b = c;  
    8.     }  
    9. }  

    可以用位操作来实现交换两数而不用第三方变量:

    [cpp] view plaincopy
     
    1. void Swap(int &a, int &b)  
    2. {  
    3.     if (a != b)  
    4.     {  
    5.         a ^= b;  
    6.         b ^= a;  
    7.         a ^= b;  
    8.     }  
    9. }  

    可以这样理解:

    第一步  a^=b 即a=(a^b);

    第二步  b^=a 即b=b^(a^b),由于^运算满足交换律,b^(a^b)=b^b^a。由于一个数和自己异或的结果为0并且任何数与0异或都会不变的,所以此时b被赋上了a的值。

    第三步 a^=b 就是a=a^b,由于前面二步可知a=(a^b),b=a,所以a=a^b即a=(a^b)^a。故a会被赋上b的值。
    再来个实例说明下以加深印象。int a = 13, b = 6;

    a的二进制为 13=8+4+1=1101(二进制)

    b的二进制为 6=4+2=110(二进制)

    第一步 a^=b  a = 1101 ^ 110 = 1011;

    第二步 b^=a  b = 110 ^ 1011 = 1101;即b=13

    第三步 a^=b  a = 1011 ^ 1101 = 110;即a=5

    3.变换符号

    变换符号就是正数变成负数,负数变成正数。

    如对于-11和11,可以通过下面的变换方法将-11变成11

          1111 0101(二进制) –取反-> 0000 1010(二进制) –加1-> 0000 1011(二进制)

    同样可以这样的将11变成-11

          0000 1011(二进制) –取反-> 0000 1010(二进制) –加1-> 1111 0101(二进制)

    因此变换符号只需要取反后加1即可。完整代码如下:

    [cpp] view plaincopy
     
    1. //by MoreWindows( http://blog.csdn.net/MoreWindows )    
    2. #include <stdio.h>  
    3. int SignReversal(int a)  
    4. {  
    5.     return ~a + 1;  
    6. }  
    7. int main()  
    8. {  
    9.     printf("对整数变换符号 --- by MoreWindows( http://blog.csdn.net/MoreWindows )  --- ");  
    10.     int a = 7, b = -12345;  
    11.     printf("%d  %d ", SignReversal(a), SignReversal(b));  
    12.     return 0;  
    13. }  

    4.求绝对值

    位操作也可以用来求绝对值,对于负数可以通过对其取反后加1来得到正数。对-6可以这样:

          1111 1010(二进制) –取反->0000 0101(二进制) -加1-> 0000 0110(二进制)

    来得到6。

    因此先移位来取符号位,int i = a >> 31;要注意如果a为正数,i等于0,为负数,i等于-1。然后对i进行判断——如果i等于0,直接返回。否之,返回~a+1。完整代码如下:

    [cpp] view plaincopy
     
    1. //by MoreWindows( http://blog.csdn.net/MoreWindows )  
    2. int my_abs(int a)  
    3. {  
    4.     int i = a >> 31;  
    5.     return i == 0 ? a : (~a + 1);  
    6. }  

    现在再分析下。对于任何数,与0异或都会保持不变,与-1即0xFFFFFFFF异或就相当于取反。因此,a与i异或后再减i(因为i为0或-1,所以减i即是要么加0要么加1)也可以得到绝对值。所以可以对上面代码优化下:

    [cpp] view plaincopy
     
    1. //by MoreWindows( http://blog.csdn.net/MoreWindows )  
    2. int my_abs(int a)  
    3. {  
    4.     int i = a >> 31;  
    5.     return ((a ^ i) - i);  
    6. }
  • 相关阅读:
    csu 1513 Kick the ball! 搜索
    训练赛bug总结
    csu 1780 简单的图论问题? 搜索
    贪吃蛇
    hdu 1541 Stars 树状数组
    FZU 2092 收集水晶 BFS记忆化搜索
    [ An Ac a Day ^_^ ] UVALive 2035 The Monocycle BFS
    52. N皇后 II
    修改全局变量-global 修改外部嵌套函数中的变量 nonlocal
    安装glove 不报错
  • 原文地址:https://www.cnblogs.com/spring-hailong/p/6071984.html
Copyright © 2011-2022 走看看