按位异或(异或)是啥意思?

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 中的任何 xyz

身份:存在单个元素 e,使得 S 中所有 xe . x = x . e = x

闭包:对于 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 在 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 = 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) remove 4 = 1

4^4 = 0

4 是自身的成员 remove 4 = 0

1^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 ) = 0

1^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 = 1

1^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 的数字的输出都将是同名数字,因为该数字将设置零没有的位。

【讨论】:

以上是关于按位异或(异或)是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

按位与&按位或|按位异或^

按位异或运算符

Python "按位或"和"按位异或"的区别

verilog 两个32位的数据怎么按位异或

matlab 如何实现按位异或 g=01001011 q=10100010 如何实现g q的按位异或 结果也是8位

深入理解按位异或运算符