位运算操作技巧
使用位运算的注意事项:
- 位操作只能用于整形数据,对float和double类型进行位操作编译器会报错。
- 位操作符的运算优先级比较低,尽量使用括号来确保运算顺序。
注意:一般运算不一定比位运算慢。编译器已经做的很好了,会把一般运算优化为位运算。
某些自作聪明的优化反而会误导编译器,使得编译器不进行更棒的优化。
取第n位的值(从右边)
int r = (v >> n) & 1;
把某一位置1(从右边)
v = v | (1 << n);
把某一位取反(从右边)
v = v ^ (1 << n);
把最后一个1置0
v = v & (v - 1);
把最后一个0置1
v = v | (v + 1);
奇偶判断
(v & 1)
计算绝对值
int bits = sizeof(v) * 8 - 1;
int r = (v ^ (v >> bits)) - (v >> bits);
取模
//v % (2^n)可以转化为去掉n位之前的值
int mod = v & (2^n - 1);
乘2的n次方
int r = v << n;
除2的n次方
int r = v >> n;
除2的余
int r = v & 1;
判断语句 v == a ? b : a;
v = a ^ b ^ v;
否为2的幂
bool power2(int v){
return ((v & (v - 1)) == 0) && (v != 0);
}
求整数的平均值
//第1部分:计算相同位的平均值
//第2部分:计算不同位的平均值
int average(int x, int y){
return (x & y) + ((x ^ y) >> 1);
}
判断两数符号是否相反
bool f = ((a ^ b) < 0);
根据掩码mask合并a和b, mask为1的位为b的值,反之为a的值
unsigned int r = a ^ ((a ^ b) & mask);
计算二进制v中1的个数n
int count_1(int v) {
int n = 0;
while (v) {
n++;
v &= (v - 1);
}
return n;
}
计算二进制v中0的个数n
int count_0(int v) {
int n = 0;
while (v + 1) {
n++;
v |= (v + 1);
}
return n;
}
下一个2的幂次方
unsigned int nextpowerof2(register unsigned int x) {
if (x == 0) {
return 1;
}
x--;
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return(x + 1);
}
上一个2的幂次方
unsigned int lastpowerof2(register unsigned int x) {
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return(x & ~(x >> 1));
}
计算二进制数字前导0的个数
int clz(unsigned int x) {
if (x == 0) return 32;
int e = 31;
//1111 1111 1111 1111 0000 0000 0000 0000
if (x & 0xFFFF0000) { e -= 16; x >>= 16; }
//0000 0000 0000 0000 1111 1111 0000 0000
if (x & 0x0000FF00) { e -= 8; x >>= 8; }
//0000 0000 0000 0000 0000 0000 1111 0000
if (x & 0x000000F0) { e -= 4; x >>= 4; }
//0000 0000 0000 0000 0000 0000 0000 1100
if (x & 0x0000000C) { e -= 2; x >>= 2; }
//0000 0000 0000 0000 0000 0000 0000 0010
if (x & 0x00000002) { e -= 1; }
return e;
}
refer: