位运算
位运算
概述
现代计算机中所有的数据均以二进制的形式存储在设备中,即 $0$、$1$ 两种状态计。计算机对二进制数据进行的运算( $+$、$-$、$*$、$/$ )都是位运算,即将符号位共同参与运算的运算。由于计算机内部就是以二进制来存储数据,位运算是相当快的。
基本的位运算共 $6$ 种,分别为按位与、按位或、按位异或、按位取反、左移和右移。通俗叫法会去掉“按位”,即与、或、异或、取反、左移和右移。
其中,按位与、按位或、按位异或是将两个整数作为二进制数,对二进制表示中的每一位逐一运算;按位取反、左移和右移是对于某一个整数作为二进制数,对二进制表示中的每一位逐一运算。
在位运算时,若两个整数的二进制位数不同,则在位数较少的前面补 $0$ 即可。
整数二进制表
这是一张 $0\sim31$ 的 $十进制\longleftrightarrow二进制$ 对照表。
二进制这个东西可以手推,但是比较麻烦,这张表在位运算的学习和实际应用中很方便比较并找到规律。
| 十进制 | 二进制 |
|---|---|
| 0 | 00000 |
| 1 | 00001 |
| 2 | 00010 |
| 3 | 00011 |
| 4 | 00100 |
| 5 | 00101 |
| 6 | 00110 |
| 7 | 00111 |
| 8 | 01000 |
| 9 | 01001 |
| 10 | 01010 |
| 11 | 01011 |
| 12 | 01100 |
| 13 | 01101 |
| 14 | 01110 |
| 15 | 01111 |
| 16 | 10000 |
| 17 | 10001 |
| 18 | 10010 |
| 19 | 10011 |
| 20 | 10100 |
| 21 | 10101 |
| 22 | 10110 |
| 23 | 10111 |
| 24 | 11000 |
| 25 | 11001 |
| 26 | 11010 |
| 27 | 11011 |
| 28 | 11100 |
| 29 | 11101 |
| 30 | 11110 |
| 31 | 11111 |
与
“与”,就是和的意思。定义如下:
| C++运算符 | 数学符号 | 意义(咋算的) |
|---|---|---|
| & | $&\space、\operatorname{and}$ | 均为 $1$,则结果为 $1$;任意一个是 $0$,结果为 $0$。 |
其对应的结果如下表:
| 数A第 $i$ 位 | 数B第 $i$ 位 | 结果 |
|---|---|---|
| $1$ | $1$ | $1$ |
| $1$ | $0$ | $0$ |
| $0$ | $1$ | $0$ |
| $0$ | $0$ | $0$ |
lowbit
正确的使用与运算(再加上一点技巧),可以求出某一个数二进制下最低位的 $1$ 的位置。详情请参见树状数组。
或
“或”,即或者。定义:
| C++运算符 | 数学符号 | 意义(咋算的) |
|---|---|---|
| | | $\mid\space、\operatorname{or}$ | 均为 $0$,则结果为 $0$;任意一个是 $1$,结果为 $1$。 |
其对应的结果如下表:
| 数A第 $i$ 位 | 数B第 $i$ 位 | 结果 |
|---|---|---|
| $1$ | $1$ | $1$ |
| $1$ | $0$ | $1$ |
| $0$ | $1$ | $1$ |
| $0$ | $0$ | $0$ |
异或
“异或”,大概就是变异的“或”吧。
| C++运算符 | 数学符号 | 意义(咋算的) |
|---|---|---|
| ^ | $\oplus\space、\operatorname{xor}$ | 均为 $0$ 或均为 $1$,结果为 $0$;两个不同(任意一个是 $1$,另一个是 $0$),结果为 $1$。 |
其对应的结果如下表:
| 数A第 $i$ 位 | 数B第 $i$ 位 | 结果 |
|---|---|---|
| $1$ | $1$ | $0$ |
| $1$ | $0$ | $1$ |
| $0$ | $1$ | $1$ |
| $0$ | $0$ | $0$ |
异或与加法
一个定理:$a\oplus{b}\le{a+b}$
证明:
我们发现,位运算不进位;而加法运算当两个位都是 $1$ 时会进位。因此,观察上表,异或运算的得数是加法运算进位后剩余的数字。
因此,在加法不进位时,$a\oplus{b}={a+b}$;加法进位时,$a\oplus{b}<{a+b}$。
取反
“取反”,顾名思义,就是 $0$ 变 $1$;