位运算总结
1.只能对整型数操作,例如char , short , int , and long(无论是有符号还是无符号)
2.>> , <<优先级是小于算术运算符的,因此a = b + (c >> 1)表达式中的括号不能少。特别要注意的是右移>>运算符,对于无符号数而言,左边用0填补,而对于有符号数它可能用0填补,也可能用“符号位”填补,因此当我们总是希望用0填补时,必须用unsigned声明(左移<< 总是用0填补,无论是有符号数还是无符号数)
3.《The C Programming language》中有几个例子还是比较经典的:
/*获取从位置P开始的n bits*/
unsigned int getbits(unsigned x , int p , int n)
{
return (x >> (p + 1 - n)) & (~(~0 << n));
}
/*把从位置p开始的n bits反置,其余位保持不变*/
unsigned int invert(unsigned x , int p , int n)
{
return (x ^ (~(~0 << n) << (p + 1 - n)));
}
11011001
^ 00111100(看懂这个就行了)
4.在《编程之美》中的中国象棋将帅问题解法1的位运算操作也是相当简洁漂亮的,在此做以记录
#define HALF_BITS_LENGTH 4
#define FULLMASK 255
#define LMASK (FULLMASK << HALF_BITS_LENGTH) //11110000
#define RMASK (FULLMASK >> HALF_BITS_LENGTH) //00001111
#define RSET(b,n) (b = ((b & LMASK) | n)) //重置右边为n
#define LSET(b,n) (b = ((b & RMASK) | (n << HALF_BITS_LENGTH))) //重置左边为n
#define RGET(b) (b & RMASK) //获取右边值
#define LGET(b) ((b & LMASK) >> HALF_BITS_LENGTH) //获取左边值
很容易把以上稍加修改来适宜任意位。
5.下面内容转载自:http://blog.sina.com.cn/s/blog_66ad7bba0100hf9k.html
问题:要去掉一个二进制数最低位上第一个出现的1,比如6->4, 14->12, 5->4,怎么办?
解答:最快的算法:n&(n-1)
问题,要得到一个二进制数最低位上第一个出现的1,比如6->2, 7->1, 12->4,怎么办?
解答:同理可得:n-(n&(n-1))
问题:判断一个数是不是2的幂
解答:(n&(n-1))==0 && n>0
问题:编写sign函数,参数为int n,返回值当n为负数返回-1,正数返回1,0返回0
解答1:return !!n - (((unsigned)n>>31)<<1)
解答2:return !!n + (n>>31)*2 (这个不一定所有编译器上都正确)
问题:求两个整数的平均值,要考虑溢出的问题
解答:这个计算办法可以保证不会受到溢出问题的影响:(x&y)+((x^y)>>1)
问题:求一个比n大的,并且是最小的2的幂,比如3->4, 6->8, 100->128, 256->512
解答:
int calc(int n)
{
n |= n>>1;
n |= n>>2;
n |= n>>4;
n |= n>>8;
n |= n>>16;
return n+1;
}