按位XOR(异或)是什么意思?

时间:2011-06-18 19:35:48

标签: math language-agnostic bit-manipulation operators xor

我正在尝试理解C#中的二元运算符,尤其是^ - exclusive or

例如:

  

给出一组正整数。除了一个出现奇数次数的数字之外,所有数字都出现偶数次。在O(n)时间和常数空间中找到数字。

     

这可以通过^完成,如下所示:对所有元素进行按位异或。最后我们得到奇数出现的数字。

它是如何工作的?

当我这样做时:

int res = 2 ^ 3;  
res = 1;  
int res = 2 ^ 5;  
res = 7;  
int res = 2 ^ 10;  
res = 8;  

实际发生了什么?还有什么其他的魔法?我可以查阅任何参考资料并了解更多信息吗?

8 个答案:

答案 0 :(得分:96)

我知道这是一个相当古老的帖子,但我想简化答案,因为我在寻找其他东西时偶然发现了它。
XOR(eXclusive OR /或者),可以简单地翻译为开关。
哪个将排除或包含指定的位。

使用4位(1111),我们从0-15得到16个可能的结果:

 decimal | binary | expanded
       0 | 0000   |
       1 | 0001   |
       2 | 0010   | 
       3 | 0011   | (1+2)
       4 | 0100   |
       5 | 0101   | (1+4)
       6 | 0110   | (2+4) 
       7 | 0111   | (1+2+4)
       8 | 1000   |
       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)

二进制值左侧的十进制值是XOR和其他按位操作中使用的数值。

例如:0011是第1位和第2位,第4位和第8位是关闭的。它表示为3的十进制值,用于表示打开的位,并以展开的形式显示为1+2


至于XOR背后的逻辑是什么,这里有一些例子 来自原帖

  

2 ^ 3 = 1

     
      
  • 2是 1 + 2 的成员(3)删除2 = 1
  •   
     

2 ^ 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 = 2
  •   
     

4 ^ 5 = 1

     
      
  • 4是 1 + 4 的成员(5)删除4 = 1
  •   
     

4 ^ 4 = 0

     
      
  • 4本身的成员删除4 = 0
  •   
     

1 ^ 2 ^ 3 = 0
逻辑:((1 ^ 2)^(1 + 2))

     
      
  • (1 ^ 2)1不是2的成员2 = 1 + 2 (3)
  •   
  • (3 ^ 3)1和2是 1 + 2 的成员(3)删除 1 + 2 (3 ) = 0
  •   
     

1 ^ 1 ^ 0 ^ 1 = 1
逻辑:(((1 ^ 1)^ 0)^ 1)

     
      
  • (1 ^ 1)1是1删除1 = 0
  • 的成员   
  • (0 ^ 0)0是0删除0 = 0
  • 的成员   
  • (0 ^ 1)0不是1 add 1 = 1
  • 的成员   
     

1 ^ 8 ^ 4 = 13
逻辑:((1 ^ 8)^ 4)

     
      
  • (1 ^ 8)1不是8的成员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)删除8 = 2      
        
    • 1不是 2 的成员+8 (10) add 1 = 1 + 2 < EM>(3)
    •   
  •   
     

4 ^ 10 ^ 13 = 3
逻辑:((4 ^(2 + 8))^(1 + 4 + 8))

     
      
  • (4 ^ 10)4不是 2 + 8 的成员(10)添加4 = 2 + 4 + 8 < EM>(14)
  •   
  • (14 ^ 13)4和8是 1 + 4 + 8 的成员(13)删除 4 + 8 = 1      
        
    • 2不是 1的成员 + 4 + 8 (13) add 2 = 1 + 2 (3)
    •   
  •   

答案 1 :(得分:53)

要了解它是如何工作的,首先需要以二进制形式编写两个操作数,因为按位运算适用于各个位。

然后,您可以为您的特定运营商应用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 :(得分:31)

另一种表明这一点的方法是使用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具有以下属性:

对于S中的任何x . (y . z) = (x . y) . zxy

代理人:z

身份:对于S中的所有e,存在单个元素e . x = x . e = xx

关闭:对于S中的任何xyx . y也在S中。

自反:对于S中的任何xx . 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在评论中证明我错了。如果您将标量乘法定义为{0,1}:

0 * x = 0
1 * x = x

...然后这个结构满足整数mod 2的所有axioms of a vector space

因此,任何此类结构都与分量XOR下的一组位向量同构。

答案 3 :(得分:5)

按位运算符将整数值内的位视为微小的位数。这些位中的每一位都像微小bool。当您使用按位异或运算符时,对运算符执行操作的一种解释是:

  • 对于第一个值中的每个位,如果设置了第二个值中的相应位,则切换该位

净效应是单个位开始false,如果“切换”的总数是偶数,则最后它仍为false。如果“切换”的总数为奇数,则最后为true

只要想想“微小的布尔值数组”,它就会开始变得有意义。

答案 4 :(得分:2)

这是基于一个简单的事实,即一个数字的XOR本身会产生零。

和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

答案 5 :(得分:1)

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(信不信由你,但是当需要将0加载到CPU寄存器中时,编译器会使用XOR的属性。执行速度更快有点操作,而不是明确地将0推入寄存器。编译器只会产生汇编代码,以便将寄存器XOR转换为自身。)

现在,如果X XOR X为0,并且XOR是关联的,您需要找出在一系列数字中没有重复的数字,其中所有其他数字已重复两次(或任何其他奇数次) )。如果我们将重复数字放在一起,它们将异或为0.任何与0异或的东西都将保留。因此,在对这样的序列进行异或运算之后,最终会留下一个不重复的数字(或重复偶数次)。

答案 6 :(得分:1)

This有很多不同功能的样本都是通过比特摆弄来完成的。有些可能非常复杂,所以要小心。

理解位操作需要做的是至少:

  • 输入数据,二进制形式
  • 一个真值表,告诉您如何“混合”输入以形成结果

对于XOR,真值表很简单:

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,而您将只留下出现奇数的数字次。

答案 7 :(得分:0)

从名称(按位)可以明显看出,它在位之间进行操作。 让我们看看它是如何工作的, 例如,我们有两个数字a = 3和b = 4, 3的二进制表示形式是011,4的二进制表示形式是100,因此基本上相同位的异或是0,而相反位则是1。 在给定的示例3 ^ 4中,其中“ ^”是异或符号,将为我们提供111,其十进制值为7。 再举一个例子,如果给定一个数组,其中每个元素除一个元素外都出现两次,并且必须找到该元素。 你该怎么做?相同数字的简单xor始终为0,而​​恰好出现一次的数字将作为输出。因为任何一个数字为0的输出都将是相同的名称数字,因为该数字将具有置零的设置位。