关于位运算的优越之处,无论用在嵌入式开发或者系统核心代码的调优上,有大把的文章去介绍其迷人的特性;在日常程序里面适当添加一些位运算的逻辑也会让你的代码增色不少;当然如果在普通程序中大量使用,在可读性上就是一种糟糕的体验了。这里就一些常用的位运算技巧进行解析,也方便对这些技巧进行记忆!
『首先』
使用位运算前,切记注意场景,并进行严格测试,我们这里使用一个常用的 ‘交换数值运算’ 进行对比测试:
|
|
中间变量交换(循环运算 10000000 耗时 0m0.029s):
|
|
异或运算交换(循环运算 10000000 耗时 0m0.068s):
|
|
所以:
- 并不是所有位运算逻辑一定是更快或者更高效的。
- 不同平台上的效果可能不太一致。
『但是』
不可否认位运算的优越性,还是很值得我们学一下,我们针对常用的技能进行解释,同时也重温一下位运算的语法
获得int型最大值
|
|
<< 左移操作 A << B
将 A 的二进制表示的整体向左移 B 位,左边超出 32 位的截掉(如果是 int 的话),右边不足的位补 0。[标注1]
获得int型最小值
|
|
|
|
获得long类型的最大值
|
|
|
|
乘以2运算
|
|
|
|
除以2运算(这里仅作示例,针对偶数)
|
|
>> 算术右移 A >> B
将 A 的二进制表示的每一位向右移 B 位,右边超出的位截掉,左边不足的位补符号位的数(比如负数符号位是1则补充1,正数符号位是0则补充0),so 对于算术右移,原负数结果还是负数,原正数的结果还是正数。[标注2]
乘以2的m次方
|
|
return = orginum * 2m
|
|
除以2的m次方
|
|
return = orginum / 2m
|
|
判断一个数的奇偶性
|
|
按位与操作 A & B
将 A 和 B 的二进制表示的每一位进行与操作,只有两个对应的二进制位都为1时,结果位才为1,否则为0
不用临时变量交换两个数(面试常考)
|
|
按位异或操作 A ^ B
将A和B的二进制表示的每一位进行异或操作,如果对应的二进制位不同,结果位为1,否则为0
取绝对值(某些机器上,效率比 numb > 0 ? numb : -numb 高)
|
|
|
|
取两个数的最大值(某些机器上,效率比 numb1 > numb2 ? numb1 : numb2 高)
|
|
|
|
取两个数的最小值(某些机器上,效率比 numb1 < numb2 ? numb1 : numb2 高)
跟上面获取最大值类似
|
|
判断符号是否相同
|
|
|
|
判断一个数是不是2的幂
|
|
|
|
二进制从低位到高位取,取 orginum 的第 numb 位
|
|
|
|
二进制从低位到高位取,将 orginum 的第 numb位 置为1
|
|
按位或操作 A | B
将A和B的二进制表示的每一位进行或操作,只要两个对应的二进制位有一个为1,结果位就为1,否则为0
二进制从低位到高位取,将 orginum 的第 numb位 置为0
|
|
按位非操作 A | B
将A的二进制表示每一位进行取反操作,如果对应的二进制位为0,结果位为1,否则为0,注意
这里是指一个位(bit)取反,对整数1取反结果不是0,因为整数1由32位(bit)组成。
比如十进制1, 表示成2进制是(00000000000000000000000000000001)2, 这里是32位有符号整数
边角余料
下面的一些小技巧,感兴趣的童鞋可以用上面的知识尝试验证一下
- 标注1:那为什么不直接写成
A * 2 ^ B
呢?因为位移运算比乘法和求幂的运算快很多很多- 标注2:区别与 Java 特有的 逻辑右移
A >>> B
:将 A 的二进制表示的每一位向右移 B 位,右边超出的位截掉,左边不足的位补 0,所以对于逻辑右移, 结果将会是一个正数。举个例子对于十进制数-127 = 11111111111111111111111110000001
,因为是负数,所以最高位上是1,逻辑右移的运算过程是:11111111111111111111111110000001 >> 2 = 00111111111111111111111111100000 = 1073741792
本文作者: wettper
本文链接: http://www.web-lovers.com/c-bit-operation.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!