位运算与用法
看看这段代码:
x = 1 # 0001
x << 2 # Shift left 2 bits: 0100
# Result: 4
x | 2 # Bitwise OR: 0011
# Result: 3
x & 1 # Bitwise AND: 0001
# Result: 1
我能理解Python(还有其他语言)里的算术运算符,但我一直搞不懂“位运算符”。在上面的例子(来自一本Python书)中,我明白左移运算,但其他两个我就不太明白了。
另外,位运算符到底是用来干嘛的呢?如果能给我一些例子就太好了。
17 个回答
位运算符到底有什么用呢?我希望能看到一些例子。
位运算最常见的用途之一就是解析十六进制颜色。
比如,这里有一个 Python 函数,它可以接受像 #FF09BE
这样的字符串,并返回它的红色、绿色和蓝色值的元组。
def hexToRgb(value):
# Convert string to hexadecimal number (base 16)
num = (int(value.lstrip("#"), 16))
# Shift 16 bits to the right, and then binary AND to obtain 8 bits representing red
r = ((num >> 16) & 0xFF)
# Shift 8 bits to the right, and then binary AND to obtain 8 bits representing green
g = ((num >> 8) & 0xFF)
# Simply binary AND to obtain 8 bits representing blue
b = (num & 0xFF)
return (r, g, b)
我知道还有更有效的方法来实现这个功能,但我觉得这个例子很好地展示了位移和位运算的布尔操作。
这里有一个常见的用法:
|
用来把某个比特位设置为1
&
用来检查或清除某个比特位
设置一个比特位(这里的 n 是比特位的编号,0 是最不重要的比特位):
unsigned char a |= (1 << n);
清除一个比特位:
unsigned char b &= ~(1 << n);
切换一个比特位(如果是1就变成0,如果是0就变成1):
unsigned char c ^= (1 << n);
测试一个比特位(检查这个比特位是1还是0):
unsigned char e = d & (1 << n);
举个例子来说明:
x | 2
用来把 x
的第1个比特位设置为1
x & 1
用来检查 x
的第0个比特位是1还是0
位运算符是处理多位值的运算符,但从概念上来说,它们是一次处理一位。
与
运算(AND)只有在两个输入都是1时结果才是1,否则结果是0。或
运算(OR)只要有一个或两个输入是1,结果就是1,否则结果是0。异或
运算(XOR)只有在恰好一个输入是1时结果才是1,否则结果是0。非
运算(NOT)只有在输入是0时结果才是1,否则结果是0。
这些运算通常可以用真值表来展示。输入的可能性在上面和左边,结果位则是四个值中的一个(对于NOT运算,因为只有一个输入,所以只有两个值)。
AND | 0 1 OR | 0 1 XOR | 0 1 NOT | 0 1
----+----- ---+---- ----+---- ----+----
0 | 0 0 0 | 0 1 0 | 0 1 | 1 0
1 | 0 1 1 | 1 1 1 | 1 0
举个例子,如果你只想要一个整数的低4位,你可以用15(也就是二进制的1111)和它进行与运算:
201: 1100 1001
AND 15: 0000 1111
------------------
IS 9 0000 1001
在这种情况下,15中的零位实际上起到了过滤的作用,强制结果中的位也变成零。
此外,>>
和<<
通常也被视为位运算符,它们分别将一个值向右和向左“移动”一定数量的位,移动到你想要的方向时会丢掉那边的位,而在另一边则会填入零位。
例如:
1001 0101 >> 2 gives 0010 0101
1111 1111 << 4 gives 1111 0000
需要注意的是,Python中的左移运算比较特殊,因为它并不是使用固定的宽度来丢弃位——许多语言是根据数据类型使用固定宽度,而Python则会扩展宽度以适应额外的位。为了在Python中实现丢弃的效果,你可以在左移后跟一个位与运算,比如将一个8位值左移四位:
bits8 = (bits8 << 4) & 255
考虑到这一点,另一个位运算符的例子是,如果你有两个4位的值想要打包成一个8位的值,你可以使用所有三种运算符(左移
、与
和或
):
packed_val = ((val1 & 15) << 4) | (val2 & 15)
& 15
操作会确保两个值只有低4位。<< 4
是一个4位的左移,将val1
移动到8位值的高4位。|
则简单地将这两个值结合在一起。
如果val1
是7而val2
是4:
val1 val2
==== ====
& 15 (and) xxxx-0111 xxxx-0100 & 15
<< 4 (left) 0111-0000 |
| |
+-------+-------+
|
| (or) 0111-0100