问题:按位操作和用法
考虑以下代码:
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书)中,我了解了左移功能,但不了解其他两个。
另外,按位运算符实际上是做什么用的?我会喜欢一些例子。
回答 0
按位运算符是对多位值进行运算的运算符,但从概念上讲一次只能运算一位。
AND
仅当其两个输入均为1时,才为1;否则为0。OR
如果其输入之一或全部为1,则为1,否则为0。XOR
仅当其输入之一恰好为1时为1,否则为0。NOT
仅当其输入为0时为1,否则为0。
这些通常可以最好地显示为真值表。输入的可能性在顶部和左侧,结果位是在输入交点处显示的四个值之一(如果不是,则为两个,因为它只有一个输入)。
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中的丢弃行为,您可以按位向左移动,and
例如在8位值中向左移动四位:
bits8 = (bits8 << 4) & 255
考虑到这一点,位运算符的另一个例子是,如果你有两个4位值要打包成一个8位的一个,你可以使用所有这三个操作员的(left-shift
,and
和or
):
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
回答 1
一种典型用法:
|
用于将某个位设置为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
回答 2
实际使用的按位运算符是什么?我会喜欢一些例子。
按位运算的最常见用途之一是解析十六进制颜色。
例如,这是一个Python函数,该函数接受类似于String的字符串,#FF09BE
并返回其Red,Green和Blue值的元组。
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)
我知道有达到此目的的更有效方法,但是我相信这是一个非常简洁的示例,说明了移位和按位布尔运算。
回答 3
我认为问题的第二部分:
另外,按位运算符实际上是做什么用的?我会喜欢一些例子。
仅得到部分解决。这是我的两分钱。
在处理许多应用程序时,编程语言中的按位运算起着基本作用。几乎所有低层计算都必须使用此类操作来完成。
在所有需要在两个节点之间发送数据的应用程序中,例如:
计算机网络;
电信应用(蜂窝电话,卫星通信等)。
在通信的较低层,数据通常以所谓的frame发送。帧只是通过物理通道发送的字节字符串。该帧通常包含实际数据以及一些其他字段(以字节为单位),这些字段是标头的一部分。标头通常包含字节,这些字节编码一些与通信状态有关的信息(例如,带有标志(位)),帧计数器,校正和错误检测代码等。要在帧中获取传输的数据并构建帧帧发送数据,则需要确定按位操作。
通常,在处理此类应用程序时,可以使用API,因此您不必处理所有这些细节。例如,所有现代编程语言都提供用于套接字连接的库,因此您实际上不需要构建TCP / IP通信框架。但是,请考虑为您编程这些API的优秀人员,他们肯定必须处理框架构造;使用各种按位运算来从低级通信到高级通信。
举一个具体的例子,假设有人给您一个文件,其中包含直接由电信硬件捕获的原始数据。在这种情况下,为了找到帧,您将需要读取文件中的原始字节,并通过逐位扫描数据来尝试找到某种同步字。在识别了同步字之后,您将需要获取实际的帧,并在必要时(并只是故事的开始)按Shift键以获取正在传输的实际数据。
另一个非常不同的低层应用程序系列是当您需要使用某些(较旧的)端口(例如并行端口和串行端口)来控制硬件时。通过设置一些字节来控制此端口,就指令而言,该字节的每个位对该端口具有特定含义(例如,请参见http://en.wikipedia.org/wiki/Parallel_port)。如果要构建可以对该硬件执行某些操作的软件,则将需要按位操作以将要执行的指令转换为端口可以理解的字节。
例如,如果您有一些物理按钮连接到并行端口以控制其他设备,则可以在软件应用程序中找到以下代码行:
read = ((read ^ 0x80) >> 4) & 0x0f;
希望这能有所作为。
回答 4
我希望这可以澄清这两个问题:
x | 2
0001 //x
0010 //2
0011 //result = 3
x & 1
0001 //x
0001 //1
0001 //result = 1
回答 5
将0视为假,将1视为真。然后按位的and(&)和or(|)就像常规的and和或或一样工作,只不过它们一次完成值中的所有位。通常,如果您可以设置30个选项(例如,在窗口上绘制样式),而又不想传递30个单独的布尔值来设置或取消设置每个布尔值,则可以将它们用作标志。将选项合并为一个值,然后使用&检查是否设置了每个选项。OpenGL大量使用这种标志传递方式。由于每个位都是一个单独的标志,因此您将获得以2(即仅设置了一位的数字)为幂的标志值1(2 ^ 0)2(2 ^ 1)4(2 ^ 2)8(2 ^ 3) 2的幂可以告诉您如果标志打开则将哪个位置1。
还要注意2 = 10,所以x | 2是110(6)而不是111(7)如果没有位重叠(在这种情况下为true)| 就像加法一样。
回答 6
我没有看到上面提到的内容,但是您还会看到一些人使用左右移位进行算术运算。左移x等于乘以2 ^ x(只要它不会溢出),右移等同于除以2 ^ x。
最近,我看到人们使用x << 1和x >> 1来加倍和减半,尽管我不确定他们是否只是想变得聪明,还是真的比普通运算符有明显的优势。
回答 7
套装
可以使用数学运算来组合集合。
- 联合运算符
|
将两个集合组合在一起,形成一个新集合,其中两个集合都包含项。 - 交集运算符
&
仅在两个项中都获得项。 - 差异运算符
-
在第一组中获得项目,但在第二组中则没有。 - 对称差运算符
^
获取任一集合中的项目,但不能同时获取两者。
自己尝试:
first = {1, 2, 3, 4, 5, 6}
second = {4, 5, 6, 7, 8, 9}
print(first | second)
print(first & second)
print(first - second)
print(second - first)
print(first ^ second)
结果:
{1, 2, 3, 4, 5, 6, 7, 8, 9}
{4, 5, 6}
{1, 2, 3}
{8, 9, 7}
{1, 2, 3, 7, 8, 9}
回答 8
本示例将向您显示所有四个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]
回答 9
另一个常见用例是操纵/测试文件权限。请参阅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()值将是值得进行的练习。
回答 10
在科学计算中,整数的位表示形式经常用于表示真假信息的数组,因为按位运算比迭代布尔数组快得多。(高级语言可能会使用位数组的概念。)
一个很好且相当简单的例子是Nim游戏的一般解决方案。看一下Wikipedia页面上的Python代码。它大量使用按位异或。^
回答 11
可能有更好的方法来查找数组元素在两个值之间的位置,但是如本示例所示,&在此处有效,而and则无效。
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]),)
回答 12
我没有看到它,本示例将为您显示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不是“包含” 4)。
回答 13
操纵整数的位很有用,但对于网络协议(可能一直指定到位)通常是有用的,但是可能需要操纵更长的字节序列(不容易转换为一个整数)。在这种情况下,使用允许对数据按位进行操作的位串库很有用-例如,可以将字符串“ ABCDEFGHIJKLMNOPQ”作为字符串或十六进制导入并对其进行位移(或执行其他按位操作):
>>> import bitstring
>>> bitstring.BitArray(bytes='ABCDEFGHIJKLMNOPQ') << 4
BitArray('0x142434445464748494a4b4c4d4e4f50510')
>>> bitstring.BitArray(hex='0x4142434445464748494a4b4c4d4e4f5051') << 4
BitArray('0x142434445464748494a4b4c4d4e4f50510')
回答 14
回答 15
要翻转位(即1的补码/取反),可以执行以下操作:
由于ExORed与全1的值会导致取反,因此对于给定的位宽,您可以使用ExOR对其进行取反。
In Binary
a=1010 --> this is 0xA or decimal 10
then
c = 1111 ^ a = 0101 --> this is 0xF or decimal 15
-----------------
In Python
a=10
b=15
c = a ^ b --> 0101
print(bin(c)) # gives '0b101'