按位运算和使用

3zz*_*zzy 94 python binary bit-manipulation operators

考虑以下代码:

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
Run Code Online (Sandbox Code Playgroud)

我可以理解Python(和其他语言)中的算术运算符,但我从来没有完全理解'按位'运算符.在上面的例子中(来自Python书),我理解左移但不是其他两个.

另外,实际使用的是按位运算符?我很欣赏一些例子.

pax*_*blo 154

按位运算符是处理多位值的运算符,但概念上一次一位.

  • 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
Run Code Online (Sandbox Code Playgroud)

一个例子是如果你只想要一个整数的低4位,你和它15(二进制1111),所以:

    201: 1100 1001
AND  15: 0000 1111
------------------
 IS   9  0000 1001
Run Code Online (Sandbox Code Playgroud)

在这种情况下,15中的零位有效地充当滤波器,迫使结果中的位也为零.

此外,>><<通常包括作为位运算符,并且它们"换挡"分别向右和由一定数目的比特的左,扔掉,你向移位端的辊位,并且在进料在零位的值另一端.

所以,例如:

1001 0101 >> 2 gives 0010 0101
1111 1111 << 4 gives 1111 0000
Run Code Online (Sandbox Code Playgroud)

请注意,Python中的左移是不寻常的,因为它没有使用丢弃位的固定宽度 - 而许多语言使用基于数据类型的固定宽度,Python只是扩展宽度以满足额外位.为了在Python中获得丢弃行为,您可以按位左移,and例如在8位值中向左移位4位:

bits8 = (bits8 << 4) & 255
Run Code Online (Sandbox Code Playgroud)

考虑到这一点,另一个按位运算符示例是,如果要将两个4位值打包成8位值,则可以使用所有三个运算符(left-shift,andor):

packed_val = ((val1 & 15) << 4) | (val2 & 15)
Run Code Online (Sandbox Code Playgroud)
  • & 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
Run Code Online (Sandbox Code Playgroud)

  • python中的按位移位不以任何数字为模; `0xff << 4 = 0xff0`和类似`0xffffffff << 32 = 0xffffffff00000000` (3认同)

pie*_*fou 41

一个典型的用法:

| 用于将某个位设置为1

& 用于测试或清除某一点

  • 设置一个位(其中n是位号,0是最低有效位):

    unsigned char a |= (1 << n);

  • 清楚一点:

    unsigned char b &= ~(1 << n);

  • 切换一下:

    unsigned char c ^= (1 << n);

  • 测试一下:

    unsigned char e = d & (1 << n);

以您的列表为例:

x | 2用于将第1位设置x为1

x & 1用于测试位0 x是1还是0


bgu*_*uiz 37

什么是按位运算符实际用于?我很欣赏一些例子.

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

例如,这是一个接受类似String 的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)
Run Code Online (Sandbox Code Playgroud)

我知道有更有效的方法来实现这一点,但我相信这是一个非常简洁的例子,说明了移位和按位布尔运算.


egu*_*aio 13

我认为问题的第二部分:

另外,实际使用的是按位运算符?我很欣赏一些例子.

已经部分解决了.这是我的两分钱.

编程语言中的按位运算在处理大量应用程序时起着至关重要的作用.几乎所有的低级计算都必须使用这种操作来完成.

在所有需要在两个节点之间发送数据的应用程序中,例如:

  • 计算机网络;

  • 电信应用(蜂窝电话,卫星通信等).

在较低级别的通信层中,数据通常以所谓的发送.帧只是通过物理通道发送的字节串.这些帧通常包含实际数据和一些其他字段(以字节为单位编码),这些字段是所谓的标题的一部分.标题通常包含编码与通信状态有关的一些信息的字节(例如,带有标志(位)),帧计数器,校正和错误检测代码等.要在帧中获取传输的数据,并构建要发送数据的帧,您需要确保按位操作.

通常,在处理这类应用程序时,可以使用API​​,因此您无需处理所有这些细节.例如,所有现代编程语言都为套接字连接提供了库,因此您实际上不需要构建TCP/IP通信帧.但想想那些为你编写这些API的好人,他们肯定要处理框架结构; 使用各种按位运算从低级别到高级别的通信来回.

举一个具体的例子,假设有人给你一个文件,其中包含由电信硬件直接捕获的原始数据.在这种情况下,为了找到帧,您需要读取文件中的原始字节,并尝试通过逐位扫描数据来查找某种同步字.在识别同步字之后,您将需要获取实际帧,并在必要时将它们移位(这只是故事的开始)以获取正在传输的实际数据.

另一个非常不同的低级应用程序系列是当您需要使用某些(某种古老的)端口(例如并行和串行端口)来控制硬件时.通过设置一些字节来控制这些端口,并且对于该端口,该字节的每个位在指令方面具有特定含义(例如参见http://en.wikipedia.org/wiki/Parallel_port).如果要构建使用该硬件执行某些操作的软件,则需要按位操作将要执行的指令转换为端口可以理解的字节.

例如,如果您有一些物理按钮连接到并行端口以控制其他设备,则可以在软应用程序中找到一行代码:

read = ((read ^ 0x80) >> 4) & 0x0f; 
Run Code Online (Sandbox Code Playgroud)

希望这有所贡献.


Ama*_*osh 6

我希望这澄清了这两点:

x | 2

0001 //x
0010 //2

0011 //result = 3
Run Code Online (Sandbox Code Playgroud)
x & 1

0001 //x
0001 //1

0001 //result = 1
Run Code Online (Sandbox Code Playgroud)

  • 哎呀...试图成为西部最快的枪......结果是一个甚至不知道二元二进制的白痴:(修正了它. (4认同)

sto*_*tal 5

将0视为假,将1视为真.然后按位和(&)和或(|)就像常规一样工作,或者除了它们一次完成值中的所有位之外.通常,如果您有30个可以设置的选项(比如窗口上的绘制样式),您将看到它们用于标记,您不希望传递30个单独的布尔值来设置或取消设置每个选项,以便您使用| 将选项组合成单个值,然后使用&检查是否设置了每个选项.OpenGL大量使用这种标记传递方式.由于每个位都是一个单独的标志,因此您可以获得两个幂的标志值(也就是仅设置一个位的数字)1(2 ^ 0)2(2 ^ 1)4(2 ^ 2)8(2 ^ 3)如果标志打开,则2的幂告诉您设置了哪个位.

还要注意2 = 10所以x | 2是110(6)而不是111(7)如果没有一个位重叠(在这种情况下是真的)| 像添加一样.


P. *_*rth 5

我没有看到上面提到的,但你也会看到有些人使用左右移位进行算术运算.左移x乘以2 ^ x(只要它不溢出),右移相当于除以2 ^ x.

最近我看到人们使用x << 1和x >> 1进行加倍和减半,虽然我不确定他们是否只是想要聪明,或者是否真的比普通运算符有明显的优势.

  • 我反对使用位移运算符的论点是,大多数现代编译器可能已经优化了算术运算,因此聪明才是最好的或者最糟糕的是与编译器对抗.我没有C,编译器或CPU设计的专业知识,因此不要认为我是正确的.:) (2认同)