为什么我们要在两个数字之间使用按位运算符?
Why would we use bitwise operators between 2 numbers?
鉴于以下信息,我不明白为什么您会想要使用 &
运算符计算例如 2 个十六进制整数。我理解下面解释的反转模式,我可以自己计算它,但是很难推断为什么(从我在互联网上看到的帖子)。什么是真实世界的场景,可以让我在这里有洞察力?
0xff00 & 0xf0f0 is 0xf000
0xff00 ^ 0xf0f0 is 0x0ff0
0xff00 | 0xf0f0 is 0xfff0
For &, the result value is the bitwise AND of the operand values.
For ^, the result value is the bitwise exclusive OR of the operand values.
For |, the result value is the bitwise inclusive OR of the operand values.
在我自己的脑海里,我目前是这样想的:
if ( 65280 & 61680 ) // evaluates to 61440, not boolean?
这些运算符用于很多事情,但如今在高级语言中,它们最常与标志一起使用。它是 C 等低级语言的遗留物,其中内存分配和释放并不总是微不足道的,并且是在硬件资源稀缺的时候开发的。
假设某些操作有 3 个可能的标志,它们可以以任何给定的组合提供。提供标志的一种快速、简单且有效的方法是将每个标志分配给整数中的一个位。
public static final int FLAG_1 = 1; // 00000001
public static final int FLAG_2 = 1 << 1; // 00000010
public static final int FLAG_3 = 1 << 2; // 00000100
然后要发送多个标志,我可以使用按位或“|”操作员。
someFunc(FLAG_1 | FLAG_3).
要读取传递的标志,我可以使用按位 & 运算符。
public void someFunc(int flags) {
if ((flags & FLAG_1) == FLAG_1 /*Or (flags & FLAG_1) != 0 */) {
// Passed in flag 1.
}
}
还有其他方法可以做到这一点,但这种方法非常有效,易于阅读,并且会导致堆上的对象分配为零。如果您想到其他方法可以在 Java 中完成此操作,比方说使用 enums/ints 的数组或集合,或者将每个标志作为单独的方法参数,那么很明显为什么要改用这种模式.
对于 if 语句中的一个非常基本的示例:
if ( (65280 & 1) == 0 ){
// 65280 is even!
}
x & 1
是 0
如果 x
是偶数
x & 1
是 1
如果 x
是奇数
我认为如果你需要实现一个 boolean
的小数组,将它表示为 int
或 long
可能是个好主意,每个位代表一个数组元素:
- 如果这些数组的数量很大,那么内存使用是一个问题;或
- 如果您正在进行大量计算。
在这种情况下,您将使用移位运算符和 &
、|
、&=
、|=
或 ^=
进行测试,清除、设置或翻转数组的元素。 (另请注意,这可以并行用于数组的多个元素。)
这种情况很少见。为了可读性,最好使用常规 array
或 ArrayList
。但是,这两个用例我都至少出现过一次。一个是使用强力回溯算法编写数独求解器;我不记得细节了,但我想我用了一个 int
的 9 位来表示行、列或正方形中的单元格是否被占用。如果我没记错的话,我的一些代码同时测试了多个单元格,我可以用一个 &
运算符来完成。由于通过回溯求解可能涉及大量的组合,我相信使用这种机制可以显着缩短 运行ning 时间。另一个案例涉及 table 个项目,这些项目保留有关项目是否具有某些属性的信息。属性的数量比较少(10到20之间),但是物品的数量可以运行上千万。 Set
本来是表示属性集的自然选择,但由于我需要保留大量 HashSet
,内存是一个问题。
除非内存或时间有很大差异,否则我不会推荐这个。它带有 "trickiness" 的味道,我更喜欢表达您要完成的目标的直接代码。
鉴于以下信息,我不明白为什么您会想要使用 &
运算符计算例如 2 个十六进制整数。我理解下面解释的反转模式,我可以自己计算它,但是很难推断为什么(从我在互联网上看到的帖子)。什么是真实世界的场景,可以让我在这里有洞察力?
0xff00 & 0xf0f0 is 0xf000
0xff00 ^ 0xf0f0 is 0x0ff0
0xff00 | 0xf0f0 is 0xfff0
For &, the result value is the bitwise AND of the operand values.
For ^, the result value is the bitwise exclusive OR of the operand values.
For |, the result value is the bitwise inclusive OR of the operand values.
在我自己的脑海里,我目前是这样想的:
if ( 65280 & 61680 ) // evaluates to 61440, not boolean?
这些运算符用于很多事情,但如今在高级语言中,它们最常与标志一起使用。它是 C 等低级语言的遗留物,其中内存分配和释放并不总是微不足道的,并且是在硬件资源稀缺的时候开发的。
假设某些操作有 3 个可能的标志,它们可以以任何给定的组合提供。提供标志的一种快速、简单且有效的方法是将每个标志分配给整数中的一个位。
public static final int FLAG_1 = 1; // 00000001
public static final int FLAG_2 = 1 << 1; // 00000010
public static final int FLAG_3 = 1 << 2; // 00000100
然后要发送多个标志,我可以使用按位或“|”操作员。
someFunc(FLAG_1 | FLAG_3).
要读取传递的标志,我可以使用按位 & 运算符。
public void someFunc(int flags) {
if ((flags & FLAG_1) == FLAG_1 /*Or (flags & FLAG_1) != 0 */) {
// Passed in flag 1.
}
}
还有其他方法可以做到这一点,但这种方法非常有效,易于阅读,并且会导致堆上的对象分配为零。如果您想到其他方法可以在 Java 中完成此操作,比方说使用 enums/ints 的数组或集合,或者将每个标志作为单独的方法参数,那么很明显为什么要改用这种模式.
对于 if 语句中的一个非常基本的示例:
if ( (65280 & 1) == 0 ){
// 65280 is even!
}
x & 1
是0
如果x
是偶数x & 1
是1
如果x
是奇数
我认为如果你需要实现一个 boolean
的小数组,将它表示为 int
或 long
可能是个好主意,每个位代表一个数组元素:
- 如果这些数组的数量很大,那么内存使用是一个问题;或
- 如果您正在进行大量计算。
在这种情况下,您将使用移位运算符和 &
、|
、&=
、|=
或 ^=
进行测试,清除、设置或翻转数组的元素。 (另请注意,这可以并行用于数组的多个元素。)
这种情况很少见。为了可读性,最好使用常规 array
或 ArrayList
。但是,这两个用例我都至少出现过一次。一个是使用强力回溯算法编写数独求解器;我不记得细节了,但我想我用了一个 int
的 9 位来表示行、列或正方形中的单元格是否被占用。如果我没记错的话,我的一些代码同时测试了多个单元格,我可以用一个 &
运算符来完成。由于通过回溯求解可能涉及大量的组合,我相信使用这种机制可以显着缩短 运行ning 时间。另一个案例涉及 table 个项目,这些项目保留有关项目是否具有某些属性的信息。属性的数量比较少(10到20之间),但是物品的数量可以运行上千万。 Set
本来是表示属性集的自然选择,但由于我需要保留大量 HashSet
,内存是一个问题。
除非内存或时间有很大差异,否则我不会推荐这个。它带有 "trickiness" 的味道,我更喜欢表达您要完成的目标的直接代码。