位运算与用法

113 投票
17 回答
154703 浏览
提问于 2025-04-15 16:05

看看这段代码:

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 个回答

40

位运算符到底有什么用呢?我希望能看到一些例子。

位运算最常见的用途之一就是解析十六进制颜色。

比如,这里有一个 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)

我知道还有更有效的方法来实现这个功能,但我觉得这个例子很好地展示了位移和位运算的布尔操作。

46

这里有一个常见的用法:

| 用来把某个比特位设置为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

174

位运算符是处理多位值的运算符,但从概念上来说,它们是一次处理一位。

  • 运算(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

撰写回答