什么是按位运算符?

IT技术 javascript boolean bitwise-operators boolean-logic
2021-02-02 14:35:06

我是一个写代码只是为了好玩的人,并没有在学术或专业环境中真正深入研究它,所以像这些按位运算符之类的东西真的让我望而却步。

我正在阅读一篇关于 JavaScript 的文章,它显然支持按位运算。我一直在一些地方看到这个操作,我试图阅读关于它到底是什么,但我似乎根本不明白。那么它们是什么?清晰的例子会很棒!:D

还有几个问题 - 按位运算的一些实际应用是什么?你什么时候可以使用它们?

6个回答

由于没有人提出过为什么这些有用的主题:

在处理标志时,我经常使用按位运算。例如,如果您想将一系列标志传递给一个操作(例如,File.Open()同时启用读取模式和写入模式),您可以将它们作为单个值传递。这是通过在位集中(字节、短整型、整型或长整型)中为每个可能的标志分配它自己的位来实现的。例如:

 Read: 00000001
Write: 00000010

因此,如果您想通过读取和写入,您将通过 (READ | WRITE) 然后将两者组合成

00000011

然后可以在另一端解密,如:

if ((flag & Read) != 0) { //...

其中检查

00000011 &
00000001

返回

00000001

它不是 0,所以该标志确实指定了 READ。

您可以使用 XOR 来切换各种位。我在使用标志指定方向输入(向上、向下、向左、向右)时使用了它。例如,如果精灵在水平移动,而我希望它转身:

     Up: 00000001
   Down: 00000010
   Left: 00000100
  Right: 00001000
Current: 00000100

在这种情况下,我只是将当前值与 (LEFT | RIGHT) 进行异或,这将关闭 LEFT 并打开 RIGHT。

位移位在多种情况下很有用。

x << y

是相同的

x * 2 y

如果您需要快速乘以 2 的幂,但要注意将 1 位移入最高位 - 这会使数字为负,除非它是无符号的。它在处理不同大小的数据时也很有用。例如,从四个字节读取一个整数:

int val = (A << 24) | (B << 16) | (C << 8) | D;

假设 A 是最重要的字节,而 D 是最不重要的。它最终会变成:

A = 01000000
B = 00000101
C = 00101011
D = 11100011
val = 01000000 00000101 00101011 11100011

颜色通常以这种方式存储(最高有效字节被忽略或用作 Alpha):

A = 255 = 11111111
R = 21 = 00010101
G = 255 = 11111111
B = 0 = 00000000
Color = 11111111 00010101 11111111 00000000

要再次查找值,只需将位向右移动直到它位于底部,然后屏蔽剩余的高阶位:

Int Alpha = Color >> 24
Int Red = Color >> 16 & 0xFF
Int Green = Color >> 8 & 0xFF
Int Blue = Color & 0xFF

0xFF与 相同11111111所以基本上,对于 Red,你会这样做:

Color >> 16 = (filled in 00000000 00000000)11111111 00010101  (removed 11111111 00000000)
00000000 00000000 11111111 00010101 &
00000000 00000000 00000000 11111111 =
00000000 00000000 00000000 00010101 (The original value)
x<<n ,所以 n 必须是 2^value 的形式?
2021-03-20 14:35:06

值得注意的是,作为其他答案列出的单位真值表一次仅适用于一两个输入位。使用整数时会发生什么,例如:

int x = 5 & 6;

答案在于每个输入的二进制扩展:

  5 = 0 0 0 0 0 1 0 1
& 6 = 0 0 0 0 0 1 1 0
---------------------
      0 0 0 0 0 1 0 0

每列中的每一对位都通过“与”函数运行以在底线上给出相应的输出位。所以上述表达式的答案是 4。CPU 已经(在本例中)并行完成了 8 个单独的“AND”运算,每列一个。

我提到这个是因为我还记得有这个“啊哈!” 多年前我了解到这一点的那一刻。

哇,这现在更有意义了。这听起来比看起来要复杂得多。谢谢。我不确定选择哪个作为正确答案,因为有很多好的答案,我不能投票,所以..谢谢
2021-03-12 14:35:06

按位运算符是一次处理一点的运算符。

仅当其两个输入均为 1 时,AND 才为 1。

如果一个或多个输入为 1,则 OR 为 1。

仅当其输入之一为 1 时,XOR 才为 1。

只有当它的输入为 0 时 NOT 才为 1。

这些可以最好地描述为真值表。输入可能性在顶部和左侧,结果位是两个输入的交点处显示的四个值之一(在 NOT 的情况下为两个,因为它只有一个输入)值。

AND|0 1      OR|0 1
---+----    ---+----
  0|0 0       0|0 1
  1|0 1       1|1 1

XOR|0 1     NOT|0 1
---+----    ---+---
  0|0 1        |1 0
  1|1 0

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

    203: 1100 1011
AND  15: 0000 1111
------------------
 IS  11: 0000 1011

这些是按位运算符,在 JavaScript 中都支持:

  • op1 & op2--AND运算符比较两位,如果两位都为 1,则结果为 1;否则返回 0。

  • op1 | op2--OR运算符比较两个位,如果位互补,则结果为 1;否则返回 0。

  • op1 ^ op2--EXCLUSIVE-OR运算符比较两个位,如果任一位为 1,则返回 1,如果两个位均为 0 或 1,则返回 0。

  • ~op1--COMPLEMENT运算符用于反转操作数的所有位。

  • op1 << op2--SHIFT LEFT运算符向左移动位,丢弃最左边的位,并将最右边的位赋值为 0。每次向左移动有效地将 op1 乘以 2。

  • op1 >> op2--SHIFT RIGHT运算符向右移动位,丢弃最右边的位,并为最左边的位分配值 0。每次向右移动有效地将 op1 分成两半。最左边的符号位被保留。

  • op1 >>> op2-- SHIFT RIGHT-ZERO FILL运算符将位向右移动,丢弃最右边的位,并将最左边的位赋值为 0。每次向右移动都有效地将 op1 分成两半。最左边的符号位被丢弃。

“如果这些位是互补的” - 哇?
2021-03-15 14:35:06
@JeffHillman 根据您在评论中的描述,1 和 1 不是“互补的”。然后我不清楚为什么1 | 1给出1而不是0|然后应该如何^. 几天前我不得不使用这个 Q/A 作为重复目标,我希望 10 年后,对于此类问题,人们会有更清晰的规范重复。
2021-03-15 14:35:06
@AndreyTyukin 两位是互补的,如果其中一个是 1,另一个是 0。
2021-03-23 14:35:06

更详细地说,它与所讨论值的二进制表示有很大关系。

例如(十进制):
x = 8
y = 1

会出来(二进制):
x = 1000
y = 0001

从那里,您可以进行诸如“and”或“or”之类的计算操作;在这种情况下:
× | y =
1000 
0001 |
------
1001

或... 9 十进制

希望这可以帮助。

出于某种原因,这对我来说最有意义。x | y = 1000 0001 |虽然仍然不确定这 部分
2021-03-11 14:35:06
| 是 OR 操作?
2021-03-28 14:35:06