你一定看得懂的位运算

位运算是直接对整数在内存中的二进制位进行操作。

阅读本章时,可以打开计算机上的计算器,并将其设置为程序员模式

了解位

在计算机内部,数据以二进制来存储,每一个二进制数称为一个(Bit)。

位运算

位运算通常有如下几个操作:

  • 位与(&, and),当两位同时为 1 时才返回 1。
  • 位或(|, or),只要有一位为 1 就返回 1。
  • 异或(^, xor),当两位相同时返回 0,不相同时返回 1。
  • 位非(~, not),将操作数的每个位(包括符号位)全部取反。
  • 左移(<<, lsh)
  • 右移(>>, rsh)

其中,Java 语言还多一个无符号右移(>>>)。

位与位或异或的运算法则如下:

操作数 10011
操作数 20101
位与0001
位或0111
异或0110

位与

举个例子,5 & 9 = 1,为什么呢?

首先将这两个数转换成二进制

1
2
3
4
5: 0000 0000 0000 0000 0000 0000 0000 0101
9: 0000 0000 0000 0000 0000 0000 0000 1001
------------------------------------------
&: 0000 0000 0000 0000 0000 0000 0000 0001 = 1

位或

5 | 9 = 13

1
2
3
4
5: 0000 0000 0000 0000 0000 0000 0000 0101
9: 0000 0000 0000 0000 0000 0000 0000 1001
------------------------------------------
|: 0000 0000 0000 0000 0000 0000 0000 1101 = 13

异或

5 ^ 9 = 12

1
2
3
4
5: 0000 0000 0000 0000 0000 0000 0000 0101
9: 0000 0000 0000 0000 0000 0000 0000 1001
------------------------------------------
^: 0000 0000 0000 0000 0000 0000 0000 1100 = 12

位非

~-5 = 4

1
2
 -5: 1111 1111 1111 1111 1111 1111 1111 1011 (计算机内部负数以补码形式表示)
~-5: 0000 0000 0000 0000 0000 0000 0000 0100

左移

左移是将操作数二进制码整体向左移动制定的位数,左移后右边空出来的地方用 0 来填充。

5<<2 = 20-5<<2 = -20

1
2
3
4
5
6
7
      5:    0000 0000 0000 0000 0000 0000 0000 0101
5<<2: 00 0000 0000 0000 0000 0000 0000 0001 0100
-> 0000 0000 0000 0000 0000 0000 0001 0100 = 20
--------------------------------------------------------
-5: 1111 1111 1111 1111 1111 1111 1111 1011
-5<<2: 11 1111 1111 1111 1111 1111 1111 1110 1100
-> 1111 1111 1111 1111 1111 1111 1110 1100 = -20

右移

右移是将操作数的二进制码向右移动指定位数,右移后左边空出来的地方以原来的符号为来填充。若原来为正数,则在左边补 0,若为负数,则补 1。

5>>2 = 1-5>>2 = -2

1
2
3
4
5
6
7
     5: 0000 0000 0000 0000 0000 0000 0000 0101
5>>2: 00 0000 0000 0000 0000 0000 0000 0001 01
-> 0000 0000 0000 0000 0000 0000 0000 0001 = 1
------------------------------------------------------
-5: 1111 1111 1111 1111 1111 1111 1111 1011
-5>>2: 11 1111 1111 1111 1111 1111 1111 1110 11
-> 1111 1111 1111 1111 1111 1111 1111 1110 = -2

Java 中的无符号右移

右移不同,无符号右移无论操作数为正数还是负数都将在左侧补 0。

-5>>>2 = 1073741822

1
2
3
     -5: 1111 1111 1111 1111 1111 1111 1111 1011
-5>>>2: 11 1111 1111 1111 1111 1111 1111 1110 11
-> 0011 1111 1111 1111 1111 1111 1111 1110 = 1073741822

参考资料