有趣的二进制—高效位运算

原文地址: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在最后加一个0101101->1011010
x << 1 | 1在最后加一个1101101->1011011
x | 1把最后一位变成1101100->101101
x & -2把最后一位变成0101101->101100
x ^ 1最后一位取反101101->101100
x | (1 << (k-1))把右数第k位变成1101001->101101,k=3
x & ~ (1 << (k-1))把右数第k位变成0101101->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位变成1101001->101111,k=4
x ^ (1 << k-1)末k位取反101001->100110,k=4
x & (x+1)把右边连续的1变成0100101111->100100000
x | (x+1)把右起第一个0变成1100101111->100111111
x | (x-1)把右边连续的0变成111011000->11011111
(x ^ (x+1)) >> 1取右边连续的1100101111->1111
x & -x去掉右起第一个1的左边100101000->1000
x&0x7F取末7位100101000->101000
x& ~0x7F是否小于127001111111 & ~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-------------------------

转载于:https://www.cnblogs.com/wangxiaokun/p/6747769.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值