什么是位运算符?
Posted
技术标签:
【中文标题】什么是位运算符?【英文标题】:What are bitwise operators? 【发布时间】:2010-09-21 13:26:48 【问题描述】:我只是为了好玩而编写代码并且在学术或专业环境中都没有真正深入研究过,所以像这些按位运算符这样的东西真的让我无法理解。
我正在阅读一篇关于 javascript 的文章,它显然支持按位运算。我一直在某些地方看到此操作,并且我尝试阅读以弄清楚它到底是什么,但我似乎根本不明白。那么它们是什么?清晰的例子会很棒! :D
还有几个问题 - 位运算有哪些实际应用?您什么时候可以使用它们?
【问题讨论】:
对于更多问题,您可能需要添加一个新的 SO 问题并参考这个问题。这样你可能会得到更好的答案。 【参考方案1】:在数字计算机编程中,按位运算在一个或多个位模式或二进制数字的各个位级别上进行操作。它是一种由处理器直接支持的快速、原始的操作,用于操作值以进行比较和计算。
运营:
按位与
按位或
按位非
按位异或
等
列表项
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
例如。
203: 1100 1011
AND 15: 0000 1111
------------------
= 11: 0000 1011
位运算符的使用
左移和右移运算符分别相当于乘以 x * 2y。例如。
int main()
int x = 19;
printf ("x << 1 = %d\n" , x <<1);
printf ("x >> 1 = %d\n", x >>1);
return 0;
// Output: 38 9
& 运算符可用于快速检查数字是奇数还是偶数
例如。
int main()
int x = 19;
(x & 1)? printf("Odd"): printf("Even");
return 0;
// Output: Odd
无需if else
语句即可快速查找 x 和 y 的最小值
例如。
int min(int x, int y)
return y ^ ((x ^ y) & - (x < y))
十进制转二进制
转化
例如。
#include <stdio.h>
int main ()
int n , c , k ;
printf("Enter an integer in decimal number system\n " ) ;
scanf( "%d" , & n );
printf("%d in binary number
system is: \n " , n ) ;
for ( c = 31; c >= 0 ; c -- )
k = n >> c ;
if ( k & 1 )
printf("1" ) ;
else
printf("0" ) ;
printf(" \n " );
return 0 ;
XOR 门加密是一种流行的技术,因为它的复杂性和可供程序员使用。
从技术面试的角度来看,按位 XOR 运算符是最有用的运算符。
按位移位仅适用于 +ve 数字
按位逻辑的使用范围也很广
【讨论】:
“复杂性和真实性...” ?The left-shift and right-shift operators are equivalent to multiplication and division by x * 2y respectively.
没错! muyiy.cn/question/program/102.html
我的解决方案repl.it/@xgqfrms/…【参考方案2】:
由于没有人提出这些为什么有用的主题:
在处理标志时,我经常使用按位运算。例如,如果您想将一系列标志传递给操作(例如,File.Open()
,同时启用读取模式和写入模式),您可以将它们作为单个值传递。这是通过在位集(字节、短、整数或长)中为每个可能的标志分配它自己的位来实现的。例如:
Read: 00000001
Write: 00000010
所以如果你想通过 read AND write,你会通过 (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 * 2y
如果您需要快速乘以 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 【参考方案3】:这些是位运算符,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 减半。最左边的符号位被丢弃。
【讨论】:
“如果位是互补的” - 哇? @AndreyTyukin 如果其中一个为 1,另一个为 0,则两个位是互补的。 @JeffHillman 根据您在评论中的描述,1 和 1 不是“互补的”。然后我不清楚为什么1 | 1
给出1
而不是0
,以及|
应该如何与^
不同。几天前我不得不使用这个 Q/A 作为重复目标,我希望 10 年后,对于这类问题会有一个更清晰的规范重复。【参考方案4】:
这样想可能会有所帮助。这就是 AND (&) 的工作原理:
它基本上说这两个数字都是数字,所以如果你有两个数字 5 和 3,它们将被转换为二进制,计算机会思考
5: 00000101
3: 00000011
都是一个:00000001 0为假,1为真
所以 5 和 3 的 AND 为 1。 OR (|) 运算符的作用相同,只是其中一个数字必须为 1 才能输出 1,而不是两者。
【讨论】:
【参考方案5】:我一直听说 JavaScript 位运算符有多慢。我对my latest blog post 进行了一些测试,发现在几个测试中它们比算术替代方法快 40% 到 80%。也许他们曾经很慢。在现代浏览器中,我喜欢它们。
我的代码中有一个案例,因此会更快、更容易阅读。我会睁大眼睛了解更多。
【讨论】:
【参考方案6】:按位运算符是一次处理一个位的运算符。
只有当两个输入都为 1 时,AND 才为 1。
如果一个或多个输入为 1,则 OR 为 1。
只有当其中一个输入恰好为 1 时,XOR 才为 1。
只有当输入为 0 时才为 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
【讨论】:
【参考方案7】:当提到“按位”一词时,有时会澄清它不是“逻辑”运算符。
例如在 JavaScript 中,bitwise operators treat their operands as a sequence of 32 bits (zeros and ones);同时,logical operators are typically used with Boolean (logical) values 但可以使用非布尔类型。
以 expr1 && expr2 为例。
如果可以转换则返回 expr1 为假;否则,返回 expr2。 因此,当与布尔值一起使用时, && 如果两个操作数都是 真的;否则,返回 false。
a = "Cat" && "Dog" // t && t returns Dog
a = 2 && 4 // t && t returns 4
正如其他人所指出的,2 和 4 是按位与,因此它将返回 0。
您可以将以下内容复制到test.html或其他内容中并进行测试:
<html>
<body>
<script>
alert("\"Cat\" && \"Dog\" = " + ("Cat" && "Dog") + "\n"
+ "2 && 4 = " + (2 && 4) + "\n"
+ "2 & 4 = " + (2 & 4));
</script>
【讨论】:
【参考方案8】:值得注意的是,作为其他答案列出的单位真值表一次只能处理一个或两个输入位。使用整数时会发生什么,例如:
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”操作,每列一个。
我之所以提到这个,是因为我还记得有这个“啊哈!”多年前我得知这件事的那一刻。
【讨论】:
哇,现在更有意义了。这听起来比看起来要复杂得多。谢谢。我不确定选择哪个作为正确答案,因为有很多好的答案,我不能投票。谢谢【参考方案9】:为了进一步分解,它与所讨论值的二进制表示有很大关系。
例如(十进制): x = 8 y = 1 会出来(二进制): x = 1000 y = 0001 从那里,您可以进行计算操作,例如“和”或“或”;在这种情况下: x | y = 1000 0001 | ------ 1001 或...9 十进制希望这会有所帮助。
【讨论】:
|
是 OR 运算?
出于某种原因,这对我来说是最有意义的。仍然不确定x | y = 1000 0001 |
部分虽然以上是关于什么是位运算符?的主要内容,如果未能解决你的问题,请参考以下文章