文章目录
参考文章:
1. 基础运算
1.1 左移 << :二进制x左移i位,后面补0
x << i
5 << 2 ⇒ 0000 0101 << 2 ⇒ 0001 0100 ⇒ 20
正数或者负数左移,低位都是用0补。
1.2 右移 >> :二进制x右移i位,正数前面补0,负数前面补1
x >> i
5 >> 2 ⇒ 0000 0101 >> 2 ⇒ 0000 0001 ⇒ 1
1.3 无符号右移 >>> : 无论正负,前面补0
x >>> i
-5 >> 3 ⇒ 1111 1111 1111 1111 1111 1111 1111 1011 >> 3 ⇒ 1111 1111 1111 1111 1111 1111 1111 1111 ⇒ -1
-5 >>> 3 ⇒ 1111 1111 1111 1111 1111 1111 1111 1011 >>> 3 ⇒ 0001 1111 1111 1111 1111 1111 1111 1111 ⇒ 536870911
1.4 按位与(&)
每一位做比较,都为1则为1,其中一个为0就为0。
(第一个操作数的的第n位于第二个操作数的第n位如果都是1,那么结果的第n为也为1,否则为0。)
5 & 3
0101
& 0011
————————————
0001 ⇒ 1
1.5 按位或(|)
每一位做比较,两个中有一个为1则为1,否则为0。
(第一个操作数的的第n位于第二个操作数的第n位 只要有一个是1,那么结果的第n为也为1,否则为0)
5 | 3
0101
| 0011
————————————
0111 ⇒ 7
1.6 按位异或(^)
相反为1, 相同为0
(第一个操作数的的第n位于第二个操作数的第n位 相反,那么结果的第n位也为1,否则为0)
5 ^ 3
0101
^ 0011
————————————
0110 ⇒ 6
1.7 按位非(~)
~
为一元操作符
1和0倒过来。
(操作数的第n位为1,那么结果的第n位为0,反之。)
~5
0000 0000 0000 0000 0000 0000 0000 0101
~
————————————————————————————————————————————————
1111 1111 1111 1111 1111 1111 1111 1010 ⇒ -6
1.8 赋值操作
类似于 +=
:
&=
按位与赋值
|=
按位或赋值
^=
按位异或赋值
>>=
右移赋值
>>>=
无符号右移赋值
<<=
赋值左移
2. 常见位运算问题
2.1 位操作实现乘除法
- 数 a 向右移一位,相当于将 a 除以 2;
- 数 a 向左移一位,相当于将 a 乘以 2
int a = 2;
a >> 1; ⇒ 1
a << 1; ⇒ 4
2.2 位操作交换两数
三次异或
void swap(int a, int b){
a ^= b; // a = a^b
b ^= a; // b = b^(a^b) ⇒ b^b^a = a
a ^= b; // a = (a^b)^b ⇒ a^a^b = b
}
2.3 位操作判断奇偶数
- 最后一位是0 ⇒ 偶数
- 最后一位是1 ⇒ 奇数
整数和1与运算
,判断最后一位。
if(0 == (a & 1)) ⇒ 偶数
1: 只有最后一位是1,其他位都是0,所以进行与运算可以使a的其他位为0,判断最后一位是否为1/0
2.4 位操作交换符号
- 将正数变负数、负数变正数。
整数取反加1
,正好变成其对应的负数(补码表示);负数取反加一,则变为其原码,即正数
int reversal(int a){
return ~a + 1;
}
2.5 位操作求绝对值
正数的绝对值是其本身,负数的绝对值正好可以对其进行取反加一求得,即我们首先判断其符号位(整数右移31位得到0,负数右移31位得到-1),然后根据符号进行相应的操作。
int abs(int a) {
int i = a >> 31;
return i == 0 ? a : (~a + 1);
}
上面的操作可以进行优化,将i == 0的条件判断语句去掉。
- 如果符号位i为0,正数,
(a^i) - i= a
- 如果符号位i为-1,负数,(a^i)- i = a ^ (-1) + 1 = a取反+1
int abs(int a) {
int i = a >> 31;
return ((a^i) - i);
}
2.6 位操作进行高低位交换
给定一个16位的无符号整数,将其高8位与低8位交换,求出交换后的值
a = 34520 ⇒ 10000110 11011000
a = (a >> 8) | (a << 8)
55430 ⇒ 11011000 10000110
2.7 位操作进行二进制逆序
将无符号数的二进制表示进行逆序,求取逆序后的结果。
在字符串逆序过程中,可以从字符串的首尾开始,依次交换两端的数据。在二进制中使用位的高低位交换会更方便进行处理,这里我们分组进行多步处理。
-
- 第一步:以每 2 位为一组,组内进行高低位交换
-
- 第二步:在上面的基础上,以每 4 位为 1 组,组内高低位进行交换
-
- 第三步:以每 8 位为一组,组内高低位进行交换
-
- 第四步:以每16位为一组,组内高低位进行交换