什么是位运算符
位运算是直接对整数在内存的二进制位进行操作。
什么是二进制
二进制,是一种广泛应用于现代计算机技术的数制,进位规则是“逢二进一”,借位规则是“借一当二”。
如何把十进制转化成二进制
以2017为例,2017十进制可以分解成
2017 = 2*10³ + 0*10² + 1*10¹ + 7*10⁰
它的二进制是11111100001⁰¹²³⁴⁵⁶⁷⁸⁹
111 1110 0001 = 1*2¹⁰ + 1*2⁹ + 1*2⁸ + 1*2⁷ + 1*2⁶ +1*2⁵ + 0*2⁴ + 0*2³ +0*2² + 0*2¹ + 1*2⁰
=1024 + 512 + 256 + 128 + 64 + 32 + 0 + 0 + 0 + 0 + 1
=2017
正整数转二进制
“除二取余,倒序排列,高位补零”就是正整数转二进制的方法。
这里通过一个流程图来演示:9转化为二进制的最终结果是1001。
负整数转化二进制
“正数计算,反向取值,结果加一”
Python中位运算符
符号 | 描述 |
---|---|
& | 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 |
| | 按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1。 |
^ | 按位异或运算符:当两对应的二进位相异时,结果为1 |
~ | 按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1 |
>> | 左移动运算符:运算数的各二进位全部左移若干位,由”<<”右边的数指定移动的位数,高位丢弃,低位补0。 |
>> | 右移动运算符:把”>>”左边的运算数的各二进位全部右移若干位,”>>”右边的数指定移动的位数 |
1、& 运算符
通常用于二进制取位操作,其 &1 的结果可以用来判断数字的奇偶性,若结果是0则是偶数,是1则是奇数。
>>> 22&1
0
>>> 13&1
1
2、| 运算符
通常用于二进制特定位上的无条件赋值,其 |1 可以把二进制的最末尾强制变为1,实际上就是把一个数变为最接近的奇数,如果变为偶数,只需要 |1 后 加1减1 即可。
>>> 220|1
221
>>> 33|1
33
3、^ 运算符
^ 运算符可以用作简单的加密, ^ 运算的逆运算是它自身,那就意味着一个数2次异或同一个数,结果不会发生改变。
>>> 2017^888^888
2017
^ 运算符还可以做两个数字的交换,类似 + - 运算的结果。
a=2017 b=1993 a=a+b b=a-b a=a-b 结果a=1993 b=2017
位运算如下
a = 2017
b = 1993
a = a^b
b = a^b
a = a^b
print('a = ',a)
print('b = ',b)
^ 运算符版本的交换两数不适用于一个数的自我交换。如果上述程序的“b”改成“a”的话,其结果是变量a=0。所以,在使用快速排序时,由于涉及到一个数的自我交换,如果要在其中使用位运算版的交换两数的话,应该先判断。
4、<< 运算符
a << b相当于把 a 的二进制整体左移 b 个位置后补 b 个 0 。
例如:10 << 5
10 的二进制是 1010
100<<2 后的二进制式 101000000 等于 320
相当于 10 乘以 2 的 5 次方
通过上面的实例,可以得出,每向左移动1位相当于该数乘以2。通常来说,位运算更加底层,效率更高,因此程序中 * 2 的操作尽可能的用左位移来代替。
定义一些常量可能会用到 << 运算。 可以用 (1<<16)-1 来表示65535。很多算法和数据结构要求必须式2的幂,此时可以用 << 来定义常量。
6、>> 运算符
和 << 相似,其相当于除以 2 的 b 次方,取整。我们可以使用 >> 来代替二分查找、堆的插入操作等。
功能 | 示例 | 位运算 |
---|---|---|
去掉最后一位 | (101101->10110) | x >> 1 |
在最后加一个0 | (101101->1011010) | x << 1 |
在最后加一个1 | (101101->1011011) | x << 1+1 |
把最后一位变成1 | (101100->101101) | x | 1 |
把最后一位变成0 | (101101->101100) | x | 1-1 |
最后一位取反 | (101101->101100) | x ^ 1 |
把右数第k位变成1 | (101001->101101,k=3) | x | (1 << (k-1)) |
把右数第k位变成0 | (101101->101001,k=3) | x and not (1 << (k-1)) |
右数第k位取反 | (101001->101101,k=3) | x ^ (1 << (k-1)) |
取末三位 | (1101101->101) | x & 7 |
取末k位 | (1101101->1101,k=5) | x & (1 << k-1) |
取右数第k位 | (1101101->1,k=4) | x >> (k-1) & 1 |
把末k位变成1 | (101001->101111,k=4) | x | (1 << k-1) |
末k位取反 | (101001->100110,k=4) | x ^ (1 << k-1) |
把右边连续的1变成0 | (100101111->100100000) | x & (x+1) |
把右起第一个0变成1 | (100101111->100111111) | x | (x+1) |
把右边连续的0变成1 | (11011000->11011111) | x | (x-1) |
取右边连续的1 | (100101111->1111) | (x ^ (x+1)) >> 1 |
去掉右起第一个1的左边 | (100101000->1000) | x & (x ^ (x-1)) |