位运算即基于二进制的运算,是直接对内存数据进行处理的更符合计算机系统的运算。众所周知,计算机系统是基于二进制的,若我们能够在编程的时候使用位运算,则计算机能够更加容易“读懂”,从而大大提高代码运行速度。
虽然位运算与我们日常经常接触的十进制的运算不同,可能会难以理解,但是为了进一步优化代码,我们必须去尝试使用位运算代替部分代码。位运算是前人留给我们的巨大的财富和强大的武器。
本文将介绍位运算的类型以及位运算的一些简单的例子。
位运算类型
-
与&
只有1&1 = 1,其他与运算结果为0,即0&1 = 0;1&0 = 0;0&0 = 0。 -
或|
只有0|0 = 0,其他或运算结果为1,即0|1 = 1 ;1|0 = 1;1|1 = 1。 -
非~
~0 = 1,~1 = 0。 -
异或^
异或即不同为1,相同为0。即0^0 = 0 1^1 = 0 0^1 = 1 1^0 = 1。 -
左移<<
将二进制数左移n位,低位补0.如下表所示:
| 左移前 | 0010 1000 |
| >>3 | 0100 0000 |
| >>1 | 1010 0000 | -
右移>>
将二进制数右移n位,若为负数,高位补1;否则,高位补0.
| 右移前 | 0010 1010 | 1010 1010 |
| >>2 | 0000 1010 | 1110 1010 |
代码示例
一些有用的小例子~
- 求两个整数的平均值
&将两个数一样的部分提出来一半,异或将两个数不一样的数提出来了,再右移一位,相当于提出来了一半,将他们相同的和不相同各提出来一半就是平均数。
int avg(int x,int y)
{
/*位运算求两个整数的平均值*/
return (x & y) + ((x^y)>>1);
}
一行代码搞定~
- 求一个整数的绝对值
int abs(int x)
{
int y = x>>31;//x为正数,则y = 0 ; x 为负数 则 y = -1;
return ((x^y)-y);
}
- 交换两个数
int swap(int *a,int *b)
{
(*a) ^= *b;
(*b) ^= *a;
(*a) ^= *b;
return 0;
}
- 一些复杂点的例子
unsigned setbits(unsigned x,int p,int n, unsigned y)
{/*将X中从第p位开始的n各位设置为y中最右边n位的值,x的其余各位保持不变*/
return x&~(~(~0<<n)<<(p+1-n))||(y&~(~0<<n)<<(p+1-n));
}
unsigned invert(unsigned x,int p,int n)
{/*将x从第p位开始的n个位求反,新的其余各位保持不变*/
return x^(~(~0<<n)<<(p+1-n));
}
unsigned rightrot(unsigned x,int n)
{/*将x循环右移(从最右端移出的位从最左端移入)n位后得到的值*/
int wordlength = sizeof(x)*8;
int rbit;
if(n % wordlength > 0)
{
rbit = (~(~0 << n) & x) << (wordlength - n);
x = x >> n;
x = x || rbit;
}
return x;
}