zoukankan      html  css  js  c++  java
  • 有趣的二进制—高效位运算

    原文地址:https://my.oschina.net/u/1859679/blog/868056

     基础

    位操作符

    符号含义规则
    两个位都为1时,结果为1
    | 有一个位为1时,结果为1
    ^ 异或 0和1异或0都不变,异或1则取反
    ~ 取反 0和1全部取反
    << 左移 位全部左移若干位,高位丢弃,低位补0
    >> 算术右移 位全部右移若干位,,高位补k个最高有效位的值
    >> 逻辑右移 位全部右移若干位,高位补0

    注意:

    1、位运算只可运用于整数,对于float和double不行。

    2、另外逻辑右移符号各种语言不太同,比如java是>>>。

    3、位操作符的运算优先级比较低,尽量使用括号来确保运算顺序。比如1&i+1,会先执行i+1再执行&。

    应用实例

    很棒的应用实例,你可以mark一下,方便以后对照使用。

    1、混合体

    位运算实例

    位运算功能示例
    x >> 1 去掉最后一位 101101->10110
    x << 1 在最后加一个0 101101->1011010
    x << 1 | 1 在最后加一个1 101101->1011011
    x | 1 把最后一位变成1 101100->101101
    x & -2 把最后一位变成0 101101->101100
    x ^ 1 最后一位取反 101101->101100
    x | (1 << (k-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 & 7 取末三位 1101101->101
    x & (1 << k-1) 取末k位 1101101->1101,k=5
    x >> (k-1) & 1 取右数第k位 1101101->1,k=4
    x | ((1 << k)-1) 把末k位变成1 101001->101111,k=4
    x ^ (1 << k-1) 末k位取反 101001->100110,k=4
    x & (x+1) 把右边连续的1变成0 100101111->100100000
    x | (x+1) 把右起第一个0变成1 100101111->100111111
    x | (x-1) 把右边连续的0变成1 11011000->11011111
    (x ^ (x+1)) >> 1 取右边连续的1 100101111->1111
    x & -x 去掉右起第一个1的左边 100101000->1000
    x&0x7F 取末7位 100101000->101000
    x& ~0x7F 是否小于127 001111111 & ~0x7F->0
    x & 1 判断奇偶 00000111&1->1

    2、交换两数

    1 int swap(int a, int b)  
    2 {  
    3     if (a != b)  
    4     {  
    5         a ^= b;  
    6         b ^= a;  
    7         a ^= b;  
    8     }  
    9 } 

    3、求绝对值

    1 int abs(int a)  
    2 {  
    3     int i = a >> 31;  
    4     return ((a ^ i) - i);  
    5 } 

    4、二分查找32位整数前导0个数

     1 int nlz(unsigned x)
     2 {
     3    int n;
     4 
     5    if (x == 0) return(32);
     6    n = 1;
     7    if ((x >> 16) == 0) {n = n +16; x = x <<16;}
     8    if ((x >> 24) == 0) {n = n + 8; x = x << 8;}
     9    if ((x >> 28) == 0) {n = n + 4; x = x << 4;}
    10    if ((x >> 30) == 0) {n = n + 2; x = x << 2;}
    11    n = n - (x >> 31);
    12    return n;
    13 }

    5、二进制逆序

     1 int reverse_order(int n){
     2 
     3   n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1);
     4   n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2);
     5   n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4);
     6   n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8);
     7   n = ((n & 0xFFFF0000) >> 16) | ((n & 0x0000FFFF) << 16);
     8 
     9   return n;
    10 }

    6、 二进制中1的个数

     1  unsigned int BitCount_e(unsigned int value) {
     2         unsigned int count = 0;
     3         // 解释下下面这句话代码,这句话求得两两相加的结果,例如 11 01 00 10
     4         // 11 01 00 10 = 01 01 00 00 + 10 00 00 10,即由奇数位和偶数位相加而成
     5         // 记 value = 11 01 00 10,high_v = 01 01 00 00, low_v = 10 00 00 10
     6         // 则 value = high_v + low_v,high_v 右移一位得 high_v_1,
     7         // 即 high_v_1 = high_v >> 1 = high_v / 2
     8         // 此时 value 可以表示为 value = high_v_1 + high_v_1 + low_v,
     9         // 可见 我们需要 high_v + low_v 的和即等于 value - high_v_1
    10         // 写简单点就是 value = value & 0x55555555 + (value >> 1) & 0x55555555;
    11         value = value - ((value >> 1) & 0x55555555);
    12 
    13         // 之后的就好理解了
    14         value = (value & 0x33333333) + ((value >> 2) & 0x33333333);
    15         value = (value & 0x0f0f0f0f) + ((value >> 4) & 0x0f0f0f0f);
    16         value = (value & 0x00ff00ff) + ((value >> 4) & 0x00ff00ff);
    17         value = (value & 0x0000ffff) + ((value >> 8) & 0x0000ffff);
    18         return value;
    19 
    20         // 另一种写法,原理一样,原因在最后一种解法中有提到
    21         //value = (value & 0x55555555) + (value >> 1) & 0x55555555;
    22         //value = (value & 0x33333333) + ((value >> 2) & 0x33333333);
    23         //value = (value & 0x0f0f0f0f) + ((value >> 4) & 0x0f0f0f0f);
    24         //value = value + (value >> 8);
    25         //value = value + (value >> 16);
    26         //return (value & 0x0000003f);
    27     }

    -----------------------end-------------------------

  • 相关阅读:
    SQL的四种连接(内连接,外连接)
    MySQL连表操作之一对多
    [转]Mysql连表之多对多
    Hibernate笔记二
    Hibernate框架报错:org.hibernate.PropertyAccessException: IllegalArgumentException occurred while calling setter of com.mikey.hibernate.domain.Person.pid
    Hibernate框架:org.hibernate.exception.SQLGrammarException: Cannot open connection at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java92)
    [转]网络编程三要素
    Hibernate笔记一
    JavaScript高级特征之面向对象笔记
    Myeclipse创建HTML文件中文显示乱码问题
  • 原文地址:https://www.cnblogs.com/wangxiaokun/p/6747769.html
Copyright © 2011-2022 走看看