按位操作和使用
考虑这个代码:
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书中),我理解左移,而不是其他两个。
另外,实际使用的按位运算符是什么? 我会欣赏一些例子。
按位运算符是操作多位值的操作符,但在概念上一次一位。
-
AND
只有在两个input都是1的情况下才为1,否则为0。 - 如果其中一个或两个input都是1,则
OR
为1,否则为0。 - 只有当其中一个input为1时,
XOR
为1,否则为0。 - 只有当它的input为0时
NOT
才是1,否则为0。
这些通常可以最好地显示为真值表。 input可能性位于顶部和左侧,结果位是input交叉处显示的四个值之一(在NOT的情况下为两个,因为它只有一个input)。
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中的左移是不常见的,因为它没有使用固定的宽度来放弃位,而许多语言使用基于数据types的固定宽度,Python只是扩展宽度以适应额外的位。 为了在Python中获得丢弃行为,可以按照左移位,例如在8位值左移四位:
bits8 = (bits8 << 4) & 255
考虑到这一点,按位运算符的另一个例子是,如果您有两个4位值要打包成8位,则可以使用全部三个运算符( left-shift
and
和)。
packed_val = ((val1 & 15) << 4) | (val2 & 15)
-
& 15
操作将确保这两个值只有低4位。 -
<< 4
是将val1
移动到8位值的前4位的4位移位。 -
|
简单地将这两者结合起来。
如果val1
是7并且val2
是4:
val1 val2 ==== ==== & 15 (and) xxxx-0111 xxxx-0100 & 15 << 4 (left) 0111-0000 | | | +-------+-------+ | | (or) 0111-0100
一个典型的用法:
|
用于将某位设置为1
&
用于testing或清除某个位
-
设置一个位(其中n是位数,0是最低有效位):
unsigned char a |= (1 << n);
-
清楚一点:
unsigned char b &= ~(1 << n);
-
切换一下:
unsigned char c ^= (1 << n);
-
testing一下:
unsigned char e = d & (1 << n);
以你的列表为例:
x | 2
x | 2
用于将x
的第1位设置为1
x & 1
用于testingx
位0是1还是0
实际使用的按位运算符是什么? 我会欣赏一些例子。
按位操作最常见的用途之一是parsinghex颜色。
例如,下面是一个Python函数,它接受一个像#FF09BE
这样的string,并返回其红色,绿色和蓝色值的元组。
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)
我知道有更有效的方法来实现这一点,但我相信这是一个非常简洁的例子,说明了移位和按位布尔操作。
我希望这个澄清这两个:
x | 2 0001 //x 0010 //2 0011 //result = 3
x & 1 0001 //x 0001 //1 0001 //result = 1
把0看作是假的,把1看作是真的。 然后,按位和(&)和或(|)就像常规和和一样工作,或者除了一次执行该值的所有位之外。 通常情况下,如果您有30个可以设置的选项(比如窗口上的绘制样式),则不需要传入30个单独的布尔值来设置或取消设置每个选项,以便您使用| 将选项组合成单个值,然后使用&检查是否设置了每个选项。 这种标志传递风格被OpenGL广泛使用。 由于每一位都是一个单独的标志,所以你可以得到两个幂(也就是只有一个位集的数字)的标志值,1(2 ^ 0)2(2 ^ 1)4(2 ^ 2)8(2 ^ 3)如果标志打开,则两个幂指示哪个位置位。
还要注意2 = 10所以x | 2是110(6)而不是111(7)如果没有任何位重叠(在这种情况下是这样)| 像添加一样。
我没有看到上面提到的,但你也会看到一些人使用左右偏移来进行算术运算。 x的左移相当于乘以2 ^ x(只要不溢出),右移相当于除以2 ^ x。
最近我看到有人用x << 1和x >> 1来加倍和减半,但我不确定他们是否只是在聪明或者真的比正常运算符有明显的优势。
这个例子将显示所有四个2位值的操作:
10 | 12 1010 #decimal 10 1100 #decimal 12 1110 #result = 14
10 & 12 1010 #decimal 10 1100 #decimal 12 1000 #result = 8
以下是使用的一个例子:
x = raw_input('Enter a number:') print 'x is %s.' % ('even', 'odd')[x&1]
我认为问题的第二部份:
另外,实际使用的按位运算符是什么? 我会欣赏一些例子。
只是部分解决。 这是我在这件事上的两分钱。
编程语言中的按位操作在处理大量的应用程序时起着基本的作用。 几乎所有的低级计算都必须使用这种操作来完成。
在所有需要在两个节点之间发送数据的应用程序中,比如:
-
计算机networking;
-
电信应用(手机,卫星通信等)。
在较低层的通信中,数据通常以所谓的帧发送。 帧只是通过物理通道发送的字节串。 这些帧通常包含实际的数据加上一些其他的字段(以字节编码),它们是所谓的报头的一部分 。 头部通常包含对与通信状态(例如,具有标志(比特))有关的一些信息进行编码的字节,帧计数器,校正和错误检测码等。为了获得帧中传输的数据,并且构build帧来发送数据,您将需要确保按位操作。
一般来说,在处理这类应用程序时,API是可用的,所以您不必处理所有这些细节。 例如,所有现代编程语言都为套接字连接提供库,所以实际上并不需要构buildTCP / IP通信框架。 但是想一想为你编写这些API的好人,他们必须肯定地处理框架结构; 利用各种按位操作来从低级到高级的通信。
作为一个具体的例子,想象一下,有人给你一个包含原始数据的文件,这些数据是由电信硬件直接捕获的。 在这种情况下,为了查找帧,您需要读取文件中的原始字节,并尝试通过逐位扫描数据来find某种types的同步字。 识别出同步字后,您将需要获取实际的帧,并在必要时将其移动(这只是故事的开始),以获取正在传输的实际数据。
另一个非常不同的低级应用系列是当你需要使用一些(古老的)端口(比如并行和串行端口)来控制硬件的时候。 这个端口是通过设置一些字节来控制的,这个字节的每一位在指令方面都有一个特定的含义(参见http://en.wikipedia.org/wiki/Parallel_port )。 如果你想构build软件来处理那些硬件,你需要按位操作来把你要执行的指令翻译成端口可以理解的字节。
例如,如果您有一些物理button连接到并行端口来控制其他设备,那么您可以在软件应用程序中find一行代码:
read = ((read ^ 0x80) >> 4) & 0x0f;
希望这个贡献。
另一个常见的用例是操纵/testing文件权限。 请参阅Python stat模块: http : //docs.python.org/library/stat.html 。
例如,要将文件的权限与所需的权限集进行比较,可以执行如下操作:
import os import stat #Get the actual mode of a file mode = os.stat('file.txt').st_mode #File should be a regular file, readable and writable by its owner #Each permission value has a single 'on' bit. Use bitwise or to combine #them. desired_mode = stat.S_IFREG|stat.S_IRUSR|stat.S_IWUSR #check for exact match: mode == desired_mode #check for at least one bit matching: bool(mode & desired_mode) #check for at least one bit 'on' in one, and not in the other: bool(mode ^ desired_mode) #check that all bits from desired_mode are set in mode, but I don't care about # other bits. not bool((mode^desired_mode)&desired_mode)
我将结果作为布尔值来计算,因为我只关心真实或虚假,但打印出每个值的bin()值是一个值得的练习。
整数的位表示通常用于科学计算来表示真假信息的arrays,因为按位运算比通过布尔数组迭代要快得多。 (高级语言可能使用位数组的想法。)
一个很好的例子就是Nim游戏的一般解决scheme。 看看Wikipedia页面上的 Python代码。 它大量使用按位独占或^
。
有一个更好的方法可以find两个值之间的数组元素,但是正如这个例子所示, &在这里工作,而不是。
import numpy as np a=np.array([1.2, 2.3, 3.4]) np.where((a>2) and (a<3)) #Result: Value Error np.where((a>2) & (a<3)) #Result: (array([1]),)
我没有看到它提到,这个例子将显示2位值的( – )十进制运算:AB(只有当A包含B)
当我们在程序中持有一个代表位的动词的时候,这个操作是需要的。 有时我们需要添加位(如上),有时我们需要删除位(如果动词包含的话)
111 #decimal 7 - 100 #decimal 4 -------------- 011 #decimal 3
用python: 7&〜4 = 3(从7中删除代表4的位)
001 #decimal 1 - 100 #decimal 4 -------------- 001 #decimal 1
用python: 1&〜4 = 1(从1中删除代表4的位 – 在这种情况下1不是'contains'4)..
虽然操纵一个整数的位是有用的,通常对于networking协议,可以指定到位,可能需要操纵较长的字节序列(不容易转换为一个整数)。 在这种情况下,使用允许按位操作数据的位串string很有用 – 例如,可以将string“ABCDEFGHIJKLMNOPQ”作为string或hex并将其移位(或执行其他按位操作):
>>> import bitstring >>> bitstring.BitArray(bytes='ABCDEFGHIJKLMNOPQ') << 4 BitArray('0x142434445464748494a4b4c4d4e4f50510') >>> bitstring.BitArray(hex='0x4142434445464748494a4b4c4d4e4f5051') << 4 BitArray('0x142434445464748494a4b4c4d4e4f50510')