考虑以下代码:
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 :(得分:146)
按位运算符是处理多位值的运算符,但概念上一次一位。
AND
仅在其输入的两个为1时才为1,否则为0。OR
为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中获得丢弃行为,您可以使用按位and
进行左移,例如将8位值向左移位4位:
bits8 = (bits8 << 4) & 255
考虑到这一点,另一个按位运算符示例是,如果要将两个4位值打包成8位值,则可以使用所有三个运算符(left-shift
,{ {1}}和and
):
or
packed_val = ((val1 & 15) << 4) | (val2 & 15)
操作将确保两个值只有较低的4位。& 15
是一个4位移位,用于将<< 4
移动到8位值的前4位。val1
只是将这两者结合在一起。如果|
为7且val1
为4:
val2
答案 1 :(得分:40)
一种典型用法:
|
用于将某个位设置为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
用于将x
的第1位设置为1
x & 1
用于测试x
的位0是1还是0
答案 2 :(得分:36)
实际使用的按位运算符是什么?我很欣赏一些例子。
按位运算最常见的用途之一是解析十六进制颜色。
例如,这是一个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)
我知道有更有效的方法来实现这一点,但我相信这是一个非常简洁的例子,说明了移位和按位布尔运算。
答案 3 :(得分:9)
我认为问题的第二部分是:
另外,实际使用的是按位运算符?我很欣赏一些例子。
只是部分解决了。这是我的两分钱。
编程语言中的按位运算在处理大量应用程序时起着至关重要的作用。几乎所有的低级计算都必须使用这种操作来完成。
在所有需要在两个节点之间发送数据的应用程序中,例如:
计算机网络;
电信应用(手机,卫星通信等)。
在较低级别的通信层中,数据通常以所谓的帧发送。帧只是通过物理通道发送的字节串。这些帧通常包含实际数据和一些其他字段(以字节为单位编码),这些字段是所谓的标题的一部分。标题通常包含编码与通信状态有关的一些信息的字节(例如,带有标志(位)),帧计数器,校正和错误检测代码等。要在帧中获取传输的数据,并构建要发送数据的帧,您需要进行按位操作。
通常,在处理这类应用程序时,API可用,因此您无需处理所有这些细节。例如,所有现代编程语言都为套接字连接提供了库,因此您实际上不需要构建TCP / IP通信帧。但想想那些为你编写这些API的好人,他们肯定要处理框架结构;使用各种按位运算从低级别到高级别的通信来回。
作为一个具体的例子,假设有人给你一个文件,其中包含由电信硬件直接捕获的原始数据。在这种情况下,为了找到帧,您需要读取文件中的原始字节,并尝试通过逐位扫描数据来查找某种同步字。识别同步字后,您需要获取实际帧,并在必要时(这只是故事的开头) SHIFT 来获取正在传输的实际数据。
另一个非常不同的低级别应用程序系列是当您需要使用某些(某种古老的)端口(例如并行和串行端口)来控制硬件时。通过设置一些字节来控制这些端口,并且该字节的每个位在指令方面对该端口具有特定含义(例如参见http://en.wikipedia.org/wiki/Parallel_port)。如果您想构建使用该硬件执行某些操作的软件,则需要按位操作将要执行的指令转换为端口所理解的字节。
例如,如果您有一些物理按钮连接到并行端口以控制其他设备,则可以在软应用程序中找到一行代码:
read = ((read ^ 0x80) >> 4) & 0x0f;
希望这有所贡献。
答案 4 :(得分:6)
我希望这澄清了这两点:
x | 2
0001 //x
0010 //2
0011 //result = 3
x & 1
0001 //x
0001 //1
0001 //result = 1
答案 5 :(得分:5)
将0视为假,将1视为真。然后按位和(&amp;)和或(|)就像常规和/或工作一样,除了它们一次完成值中的所有位。通常,如果您有30个可以设置的选项(比如窗口上的绘制样式),您将看到它们用于标记,您不希望传递30个单独的布尔值来设置或取消设置每个选项,以便您使用|将选项组合成单个值,然后使用&amp;检查是否设置了每个选项。 OpenGL大量使用这种标记传递方式。由于每个位都是一个单独的标志,因此您可以获得两个幂的标志值(也就是仅设置一个位的数字)1(2 ^ 0)2(2 ^ 1)4(2 ^ 2)8(2 ^ 3)如果标志打开,则2的幂告诉您设置了哪个位。
另请注意2 = 10所以x | 2是110(6)而不是111(7)如果没有比特重叠(在这种情况下是真的)|像添加一样。
答案 6 :(得分:5)
我没有看到上面提到的,但你也会看到有些人使用左右移位进行算术运算。左移x乘以2 ^ x(只要它不溢出),右移相当于除以2 ^ x。
最近我见过人们使用x&lt;&lt; 1和x>&gt;尽管我不确定他们是否只是想要变得聪明,或者是否真的比普通的操作员有明显的优势。
答案 7 :(得分:3)
此示例将显示所有四个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]
答案 8 :(得分:2)
整数的位表示通常用于科学计算中以表示真假信息的数组,因为按位运算比迭代一组布尔值快得多。 (更高级别的语言可能会使用位数组的概念。)
一个很好的,相当简单的例子就是Nim游戏的一般解决方案。请查看Python上的the Wikipedia page代码。它大量使用按位异或,^
。
答案 9 :(得分:2)
另一个常见的用例是操纵/测试文件权限。请参阅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 :(得分:2)
设定
可以使用数学运算来组合集合。
|
将两个集合组合成一个包含其中任何一个项目的新集合。 &
仅在两者中获取项目。 -
获取第一组中的项目但不获取第二组中的项目。 ^
可以在任一集中获取项目,但不能同时获取两者。自己动手:
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}
答案 11 :(得分:1)
可能有更好的方法来查找数组元素在两个值之间的位置,但正如此示例所示, &amp; 在这里工作,而 和 没有。
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 :(得分:1)
我没有看到它提到,这个例子将显示2位值的( - )十进制操作:A-B(仅当A包含B)
当我们在程序中保存表示位的动词时,需要此操作。有时我们需要添加位(如上所述),有时我们需要删除位(如果动词包含那么)
111 #decimal 7
-
100 #decimal 4
--------------
011 #decimal 3
使用python: 7&amp; 〜4 = 3(从7中删除代表4的位)
001 #decimal 1
-
100 #decimal 4
--------------
001 #decimal 1
使用python: 1&amp; 〜4 = 1(从1中删除代表4的位 - 在这种情况下1不是'包含'4)..
答案 13 :(得分:0)
虽然操作整数位有用,但通常对于可以指定为位的网络协议,可以要求操纵较长的字节序列(不容易转换为一个整数)。在这种情况下,使用允许对数据进行逐位运算的bitstring库是有用的 - 例如可以将字符串'ABCDEFGHIJKLMNOPQ'作为字符串或十六进制导入并将其移位(或执行其他按位操作):
>>> import bitstring
>>> bitstring.BitArray(bytes='ABCDEFGHIJKLMNOPQ') << 4
BitArray('0x142434445464748494a4b4c4d4e4f50510')
>>> bitstring.BitArray(hex='0x4142434445464748494a4b4c4d4e4f5051') << 4
BitArray('0x142434445464748494a4b4c4d4e4f50510')
答案 14 :(得分:0)
以下按位运算符:&,|,^和~以logic gates影响的方式返回值(基于其输入)信号。您可以使用它们来模拟电路。
答案 15 :(得分:0)
要翻转位(即1的补码/取反),您可以执行以下操作:
由于将值与所有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'
答案 16 :(得分:0)
您可以使用位掩码将二进制转换为十进制;
int a = 1 << 7;
int c = 55;
for(int i = 0; i < 8; i++){
System.out.print((a & c) >> 7);
c = c << 1;
}
这是 8 位数字,您也可以做更多。