按位异或(异或)是啥意思?
Posted
技术标签:
【中文标题】按位异或(异或)是啥意思?【英文标题】:What does bitwise XOR (exclusive OR) mean?按位异或(异或)是什么意思? 【发布时间】:2011-09-17 21:53:06 【问题描述】:我正在尝试理解 C# 或一般情况下的二元运算符,特别是 ^ - exclusive or。
例如:
给定一个正整数数组。除了一个出现奇数次的数字外,所有数字都出现偶数次。求 O(n) 时间和常数空间中的数。
这可以用 ^ 来完成,如下所示: 对所有元素进行按位异或。最后我们得到奇数出现的数字。
它是如何工作的?
当我这样做时:
int res = 2 ^ 3;
res = 1;
int res = 2 ^ 5;
res = 7;
int res = 2 ^ 10;
res = 8;
实际发生了什么?其他的魔法是什么?有什么参考资料我可以查找并了解更多关于它们的信息吗?
【问题讨论】:
是没有进位的二进制加法。 0+0 = 0、1+0=1、0+1=1 和 1+1=0(无进位)。 1+1 的正常二进制加法是 0 进位 1。 【参考方案1】:要了解它是如何工作的,首先您需要将两个操作数都写成二进制,因为按位运算适用于各个位。
然后您可以为您的特定运营商应用truth table。它作用于两个操作数中具有相同位置(相同位置值)的每一对位。所以A
的最左边位(MSB)与B
的MSB 结合起来产生结果的MSB。
示例:2^10
:
0010 2
XOR 1010 8 + 2
----
1 xor(0, 1)
0 xor(0, 0)
0 xor(1, 1)
0 xor(0, 0)
----
= 1000 8
结果是 8。
【讨论】:
【参考方案2】:位运算符将整数值内的位视为位的小数组。这些位中的每一个都像一个微小的bool
值。当您使用按位异或运算符时,对运算符作用的一种解释是:
最终结果是单个位以false
开头,如果“切换”的总数是偶数,则最后仍将是false
。如果“toggles”的总数是奇数,最后会是true
。
只要想一想“布尔值的小数组”,它就会开始变得有意义。
【讨论】:
【参考方案3】:另一种显示方式是使用 XOR 的代数;您无需了解有关单个位的任何信息。
对于任意数字 x、y、z:
XOR 是可交换的:x ^ y == y ^ x
XOR 是关联的:x ^ (y ^ z) == (x ^ y) ^ z
身份为0:x ^ 0 == x
每个元素都有自己的逆:x ^ x == 0
鉴于此,很容易证明所陈述的结果。考虑一个序列:
a ^ b ^ c ^ d ...
由于 XOR 是可交换的和关联的,所以顺序无关紧要。所以对元素进行排序。
现在任何相邻的相同元素x ^ x
都可以替换为0
(自逆属性)。并且任何0
都可以删除(因为它是身份)。
尽可能多地重复。任何出现偶数次的数字都有整数对,所以它们都变成0并消失。
最终你只剩下一个元素,即出现奇数次的元素。每次出现两次,那两个就消失了。最终只剩下一次。
[更新]
请注意,此证明仅需要对操作进行某些假设。具体来说,假设具有运算符.
的集合 S 具有以下属性:
关联性:x . (y . z) = (x . y) . z
用于 S 中的任何 x
、y
和 z
。
身份:存在单个元素 e
,使得 S 中所有 x
的 e . x = x . e = x
。
闭包:对于 S 中的任何 x
和 y
,x . y
也在 S 中。
自逆:对于 S 中的任何 x
,x . x = e
事实证明,我们不需要假设交换性;我们可以证明:
(x . y) . (x . y) = e (by self-inverse)
x . (y . x) . y = e (by associativity)
x . x . (y . x) . y . y = x . e . y (multiply both sides by x on the left and y on the right)
y . x = x . y (because x . x = y . y = e and the e's go away)
现在,我说“您不需要了解有关单个位的任何信息”。我在想任何满足这些属性的组就足够了,而且这样的组不一定与 XOR 下的整数同构。
但@Steve Jessup 在 cmets 中证明我错了。如果您将标量乘以 0,1 定义为:
0 * x = 0
1 * x = x
...那么这个结构满足所有的 axioms of a vector space 超过整数 mod 2。
因此,任何这样的结构都同构于按组件异或的一组位向量。
【讨论】:
它有这个代数,因为它只是在向量空间中的 2 阶素数域上的加法。那是因为在那个域中,当且仅当恰好其中一个值时,两个值的总和为 1和为 1。当且仅当其中一个操作数为真时,两个布尔值的逻辑 XOR 为真。所以逻辑异或是字段中的加法,然后“按位”使其成为向量空间。 @Steve:公平点。这就引出了一个有趣的问题……任何遵守这些关系的组都将具有问题中确定的属性。但是对于某些 n,所有这些组是否都与 (Z/2Z)^n 同构? @Nemo:这可能取决于您所说的n
是什么意思。例如,考虑在该域上具有无限基的向量空间。
@Steve:好的,那就叫它有限群吧。换句话说,如果一个有限群是关联的、交换的和自逆的,它必然同构于 0,1 上的某个 n 维向量空间?
我认为是的,是的 - 如果我们采用具有这些属性的任何组并定义明显的标量乘法,那么我们在该字段上就有一个向量空间。它是否一定有维度等同于选择公理(证明在一个方向上比在另一个方向上更容易),但如果它是有限的,那么它肯定会:-)【参考方案4】:
XOR(异或)运算符的定义是:
0 XOR 0 = 0
0 XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0
一种想象的方式,就是说右边的“1”改变了左边的位,右边的0不改变左边的位。但是,XOR 是可交换的,所以如果两边颠倒也是如此。 由于任何数字都可以用二进制形式表示,因此任何两个数字都可以进行异或运算。
为了证明它是可交换的,你可以简单地看一下它的定义,并看到对于两边的每个位组合,如果边改变,结果是相同的。为了证明它是关联的,您可以简单地遍历所有可能的 3 位相互异或的组合,无论顺序如何,结果都将保持不变。
现在,正如我们上面所证明的那样,让我们看看如果我们对同一个数字进行异或运算会发生什么。由于该操作适用于单个位,因此我们可以仅对两个数字进行测试:0 和 1。
0 XOR 0 = 0
1 XOR 1 = 0
所以,如果你将一个数字与自身异或,你总是得到 0(信不信由你,但编译器已经使用了 XOR 的这个属性,当需要将 0 加载到 CPU 寄存器中时。执行速度更快一个位操作,而不是将 0 显式地压入寄存器。编译器只会生成汇编代码来异或一个寄存器到它自己)。
现在,如果 X XOR X 为 0,并且 XOR 是关联的,并且您需要找出在所有其他数字都已重复两次(或任何其他奇数次)的数字序列中没有重复的数字)。如果我们将重复的数字放在一起,它们将异或为 0。任何与 0 异或的东西都将保持其自身。因此,在对这样的序列进行异或运算后,您最终会得到一个不重复(或重复偶数次)的数字。
【讨论】:
【参考方案5】:This 有很多通过位摆弄完成的各种功能的示例。有些可能非常复杂,所以要小心。
要了解位操作,您至少需要做的是:
二进制形式的输入数据 一个真值表,告诉您如何“混合”输入以形成结果对于异或,真值表很简单:
1^1 = 0
1^0 = 1
0^1 = 1
0^0 = 0
要在结果中获得位 n
,请将规则应用于第一个和第二个输入中的位 n
。
如果您尝试计算1^1^0^1
或任何其他组合,您会发现如果有奇数个1,结果为1,否则为0。您还会发现任何与自身异或的数字都是 0,这与您进行计算的顺序无关,例如1^1^(0^1) = 1^(1^0)^1
.
这意味着当您对列表中的所有数字进行异或运算时,重复(或出现偶数次)的数字将异或为 0,而您将只剩下出现奇数个的数字次。
【讨论】:
【参考方案6】:我知道这是一篇相当老的帖子,但我想简化答案,因为我在寻找其他内容时偶然发现了它。 XOR(异或/或),可以简单翻译为切换开/关。 这将排除(如果存在)或包括(如果不存在)指定的位。
使用 4 位 (1111) 我们从 0-15 得到 16 个可能的结果:
decimal | binary | bits (expanded)
0 | 0000 | 0
1 | 0001 | 1
2 | 0010 | 2
3 | 0011 | (1+2)
4 | 0100 | 4
5 | 0101 | (1+4)
6 | 0110 | (2+4)
7 | 0111 | (1+2+4)
8 | 1000 | 8
9 | 1001 | (1+8)
10 | 1010 | (2+8)
11 | 1011 | (1+2+8)
12 | 1100 | (4+8)
13 | 1101 | (1+4+8)
14 | 1110 | (2+4+8)
15 | 1111 | (1+2+4+8)
二进制值左侧的decimal value 是用于异或和其他按位运算的数值,表示相关位的总值。请参阅Computer Number Format 和Binary Number - Decimal 了解更多详情。
例如:0011
是第 1 位和第 2 位为打开,第 4 位和第 8 位为关闭。它表示为3
的十进制值以表示打开的位,并以扩展形式显示为1+2
。
至于 XOR 背后的逻辑发生了什么,这里有一些例子 来自原帖
2^3 = 1
2 是 1+2 的成员 (3) remove 2 = 12^5 = 7
2 不是 1+4 的成员 (5) 添加 2 = 1+2+4 (7)2^10 = 8
2 是 2+8 的成员 (10) 删除 2 = 8
更多示例
1^3 = 2
1 是 1+2 的成员 (3) 删除 1 = 24^5 = 1
4 是 1+4 的成员 (5) remove 4 = 14^4 = 0
4 是自身的成员 remove 4 = 01^2^3 = 0逻辑:((1^2)^(1+2))
(1^2) 1 不是 2 的成员 add 2 = 1+2 (3) (3^3) 1 和 2 是 1+2 (3) 删除 1+2 (3 ) = 01^1^0^1 = 1 逻辑:(((1^1)^0)^1)
(1^1) 1 是 1 的成员 remove 1 = 0 (0^0) 0 是 0 的成员 remove 0 = 0 (0^1) 0 不是 1 的成员 add 1 = 11^8^4 = 13 逻辑:((1^8)^4)
(1^8) 1 不是 8 的成员 add 1 = 1+8 (9) (9^4) 1 和 8 不是 4 的成员添加 1+8 = 1+4+8 (13)4^13^10 = 3 逻辑:((4^(1+4+8))^(2+8))
(4^13) 4 是 1+4+8 的成员 (13) 删除 4 = 1+8 (9) (9^10) 8 是 2+8 的成员 (10) remove 8 = 2 1 不是 2+8的成员 (10) 添加 1 = 1+2 (3)4^10^13 = 3 逻辑:((4^(2+8))^(1+4+8))
(4^10) 4 不是 2+8 的成员 (10) 添加 4 = 2+4+8 (14) (14^13) 4 和 8 是 1+4+8 的成员 (13) 删除 4+8 = 1 2 不是 1+4+8的成员 (13) 添加 2 = 1+2 (3)
【讨论】:
您仍然获得 +1。感谢新用户和好奇者的努力。 太棒了。你是从哪里知道这个的?可以给学习其他按位运算一些参考吗? @user132458 老实说,这正是我对按位运算如何工作的理解。最佳资源取决于您的用例,例如程序语言。 EG:C# vs php vs Python,以及它们如何利用按位运算及其局限性。然而,就一般的按位运算而言,wiki 是一个不错的资源en.wikipedia.org/wiki/Bitwise_operation。 在 2^5 中,你说 “2 不是 1+4 (5) add 2 = 1+2+4 (7)”的成员。但是为什么你认为 5 是 1+4 而不是 2 + 3?在这种情况下,2 将是 2+3 的成员。我没有得到这部分。 没有比这更好的解释了。【参考方案7】:这是基于一个简单的事实,即数字与自身的异或结果为零。
一个数字与 0 的 XOR 得到数字本身。
所以,如果我们有一个数组 = 5,8,12,5,12。
5 发生了 2 次。 8 发生 1 次。 12 发生了 2 次。
我们必须找到出现奇数次的数字。显然,8 是数字。
我们从 res=0 开始,并对数组的所有元素进行 XOR。
int res=0;
for(int i:array)
res = res ^ i;
1st Iteration: res = 0^5 = 5
2nd Iteration: res = 5^8
3rd Iteration: res = 5^8^12
4th Iteration: res = 5^8^12^5 = 0^8^12 = 8^12
5th Iteration: res = 8^12^12 = 8^0 = 8
【讨论】:
感谢您的精彩解释! 感谢您的精彩解释! 这就是我要找的。谢谢!【参考方案8】:从名称(按位)很明显,它在位之间运行。 让我们看看它是如何工作的, 例如,我们有两个数字 a=3 和 b=4, 3 的二进制表示是 011,4 的二进制表示是 100,所以基本上相同位的异或是 0,相反位的异或是 1。 在给定的示例 3^4 中,“^”是一个异或符号,将给我们 111,其十进制值为 7。 再举一个例子,如果你给了一个数组,其中每个元素都出现两次,除了一个元素,你必须找到那个元素。 你怎么能那样做?相同数字的简单异或将始终为 0,并且恰好出现一次的数字将是您的输出。因为任何一个带有 0 的数字的输出都将是同名数字,因为该数字将设置零没有的位。
【讨论】:
以上是关于按位异或(异或)是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章