0x00 -- 位运算概览
符号 | 描述 | 运算规则 |
---|---|---|
& | 按位与 | 2个位都为1,结果为1 |
| | 按位或 | 一个位为1,结果为1 |
^ | 按位异或 | 相同为0,相异为1 |
~ | 按位取反 | 1变0,0变1 |
<<n | 左移 | 各二进位全部左移n位,高位丢弃,低位补0 |
>>n | 右移 | 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移) |
0x01 -- 按位与 &
运算规则:0&0=0 0&1=0 1&1=1
两位相同为1,否则为0
3 & 5 = 1
3 0000 0011
5 0000 0101
& 0000 0001
用途
- 清零
如果想将一个单元清0,即让这个数的各个位都为0,就让这个数去与一个各位都为0的数值按位与。结果为0
- 取一个数的指定位
举个例子:
a = 1010 1110. 取 a 的低四位。只需要找一个 b,把 b 的低四位设置为 1,其余为 0,即
b = 0000 1111.
& = 0000 1110. 就可以得到 a 的指定部分, 这个过程中
b
也就是a
的(mask)所谓的掩码。
- 判断奇偶
只要根据末尾是
0
还是1
来判断是否是奇偶数。是 0 就是偶数,是 1 就是奇数。因此可以代替
if (a % 2) == 0
替换为
if(a & 1 == 0)
来判断a
是否为偶数。
0x02 -- 按位与 |
运算规则:0|0 = 0, 0|1 = 1, 1|1 = 1
只要其中一位是 1, 结果就位 1.
3 | 5 = 7
3 0000 0011
5 0000 0101
| 0000 0111
用途
- 用来对一个数据的某些位设置位 1
举个例子:
a = 1010 1110. 设置 a 的低四位为 1。只需要找一个 b,把 b 的低四位设置为 1,其余为 0,即
b = 0000 1111.
| = 1010 1111. 就可以得到按位与后的结果,
0x03 -- 按位异或 ^
运算规则:0 ^ 0 = 0, 0 ^1 = 1, 1 ^ 0 = 1, 1 ^ 1 = 0
参加元算的俩个数,相同的位为 0,不同的位为 1 ;
异或的几条性质:
-
交换律
-
结合律 ( a ^ b ) ^ c == a ^ ( b ^ c )
-
对于任何数 x,都有 x ^ x = 0,x ^ 0 = x
-
自反性: a ^ b ^ b = a ^ 0 = a;
用途
-
翻转指定位
举个例子:
a = 1010 1110, 翻转 a 的低四位。只需要找一个 b,把 b 的低四位设置为 1,其余为 0,即
b = 0000 1111.
^ = 1010 0001. 就可以得到按位异或后的结果。 就把 a 的低四位按位翻转了。
-
与0相异或值不变
1010 1110 0000 0000 ^ 1010 1110 a 3 0000 0011 b 4 0000 0100 a ^ b 0000 0111 a b 4 0000 0100 b ^ a 0000 0111 a 0000 0011 b
-
交换俩个数
void swap(int a, int b) { if(a != b) { a ^= b; b ^= a; a ^= b; } }
0x05 -- 按位取反 ~
运算规则: ~1 = 0, ~0 = 1
使 a 的最低位为 0,可以表示为:
a & ~1
。~1 的值为 1111 1111 1111 1110,再按"与"运算,最低位一定为0。因为“ ~”运算符的优先级比算术运算符、关系运算符、逻辑运算符和其他运算符都高。
0x06 -- 左移运算符 <<
使 a 的最低位为 0,可以表示为:
a & ~1
。~1 的值为 1111 1111 1111 1110,再按"与"运算,最低位一定为 0。因为 “ ~” 运算符的优先级比算术运算符、关系运算符、逻辑运算符和其他运算符都高。
0x07 -- 右移运算符 >>
定义:将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。
例如:a = a >> 2 将 a 的二进制位右移 2 位,左补 0 或者 左补 1 得看被移数是正还是负。
操作数每右移一位,相当于该数除以 2。
综合应用
比如有两个 int 类型变量 x、y,首先要求 x+y 的和,再除以 2,但是有可能 x+y 的结果会超过 int 的最大表示范围,所以位运算就派上用场啦。
(x & y)+((x ^ y) >> 1);
对于一个大于0的整数,判断它是不是2的几次方
`((x & (x - 1)) == 0) && (x != 0);
求绝对值
int abs( int x ) {
int y ;
y = x >> 31 ;
return ( x ^ y) - y ; //or: (x + y) ^ y
}
取模运算,采用位运算实现:
a % (2 ^ n) 等价于 a & (2 ^ n - 1)
乘法运算 采用位运算实现
a * (2 ^ n) 等价于 a << n
除法运算转化成位运算
a / (2 ^ n) 等价于 a >> n
求相反数
(~x + 1)
a % 2 等价于 a & 1