C# XOR运算符-它是如何工作的?

C# XOR运算符-它是如何工作的?,c#,binary,bitwise-operators,xor,C#,Binary,Bitwise Operators,Xor,请用简单的英语向我解释什么是XOR(^)运算符,以及它在以下代码中的作用: public int GetHashCode(Box bx) { int hCode = bx.Height ^ bx.Length ^ bx.Width; return hCode.GetHashCode(); } XOR代表异或。它确保A或B为真,但决不能两者都为真。在本例中,我们正在执行一个逐位运算,这样您就可以生成一个漂亮的结果图,如下所示: 0 ^ 1 = 1 1 ^ 1 = 0 1 ^ 0

请用简单的英语向我解释什么是XOR(
^
)运算符,以及它在以下代码中的作用:

public int GetHashCode(Box bx)
{
    int hCode = bx.Height ^ bx.Length ^ bx.Width;
    return hCode.GetHashCode();
} 

XOR代表异或。它确保A或B为真,但决不能两者都为真。在本例中,我们正在执行一个逐位运算,这样您就可以生成一个漂亮的结果图,如下所示:

0 ^ 1 = 1
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 0 = 0
由于将其应用于整数,上述结果将应用于操作数中的每一位。所以我们假设高度、长度和宽度的值分别为1、2、3

你会先

0001^0010导致0011,然后将其异或为3,所以0011^0011,这将给您0000

编辑:从评论中提供wiki链接以补充我的解释

编辑:为什么
0001^0010
会导致
0011

所以最好是一点一点地做。想象一下,操作符迭代两组位并比较它们的对。因此,在本例中,让我们从右向左工作(在本例中,从最不重要到最重要)

因此,将其拼接在一起,您将得到
0011
。基本上,获取每对输入并参考真值表以获得结果。注释显示的输出中,
x
是一个尚未计算的值


关于碰撞,是的,在这种情况下有很多碰撞。如果我说它是独一无二的,那是一个糟糕的词语选择。我真正的意思是,如果你有2,8,4作为你的值,那么按这个顺序对它们进行异或将总是产生相同的值。

详细说明一下,你会看到很多
getHashCode()
方法中的
XOR
在字段之间进行异或,因为这是获取对象签名的安全方法。签名的概念是,它就像一个物体的指纹,需要放入32位。这个签名被许多对象用作快速比较(不过,如果您打算使用它,请查看wikipedia的那篇文章,因为您需要小心等式和哈希代码),或者用于某种寻址(例如.net的
Dictionary
和Java的
HashMap

对于我来说,获取盒子指纹的明显解决方案是简单地将值相加,这样,如果其中任何一个值发生变化,您将获得不同的指纹:
bx.Height+bx.Length+bx.Width

考虑到equals操作可能非常昂贵(即非常慢),如果我们需要测试两个框的相等性:

  • 框{5,10,15}
  • 框{30,40,50}
我们可以比较两个哈希代码,看它们是否不同,跳过完全相等比较,而不是进行完全相等比较。在字典中,这对于给我们一个快速的方法来找到一个容器(一个元素)来放置对象是至关重要的

但是如果这些值中的任何一个太高,我们可能会得到一个整数溢出异常,因此我们不使用加法,而是使用XOR。另一种解决方案是使用
unchecked{…}
块,这是C#特有的,但使用XOR被认为更优雅

我们可以做一件更微妙的事情来提高性能,您将在许多自动生成的hashcode方法(如ReSharper或IntelliJ生成的方法)中看到这一点: 我们可以通过移动(乘以)每个值来使订单变得重要

    public int hashCode() {
        int result = x;
        result = 31 * result ^ y;
        result = 31 * result ^ z;
        return result;
    }
现在发生的是,哈希代码中的每个字段在结果32位中都有一个有效的位置。这意味着两个框:

  • 框{1,20,30}
  • 框{1,30,20}
不会有相同的哈希代码(它们与当前系统具有相同的哈希代码,但它们不同!)

关于散列码,你想知道的比你想知道的还要多,但我还要说一件事


在Java/Scala和.net framework中,如果重载等于或哈希代码,则必须同时重载另一个。您还必须确保,如果两个对象A和B具有不同的哈希代码,那么对A.Equals(B)的调用必须为false

只需谷歌与之相关的真值表,它看起来像是按位的XOR@Groostav再进一步扩展一下,这里是这样做的,因为对于这些值,
a^b^c
的结果总是相同的。在得到散列之前,他们基本上是将所有的值合并成一个,这样散列对a、b和c的值是唯一的。“按位操作”是什么意思?@YairNevet bitwise表示它正在逐个操作二进制值。正如您在我的示例中看到的,我选择了整数值1、2和3。0001、0010和0011是它们的二进制表示形式。按位运算符对这些值进行操作,而不是对这些值的整数表示进行操作。因此,就像我们使用ASCII(我不知道它是什么字符)一样,某些字符的值为0001,这将被视为与整数1完全相同,因为它们的二进制表示形式是相同的。@YairNevet您可以查看wiki文章以了解更多信息,我认为我的解释不是很清楚。。。但基本上所有类型都在某种程度上用二进制表示,按位运算符处理二进制值,而不是二进制表示的值。@YairNevet整数通常为32或64位,具体取决于您使用的操作系统和语言。可以用4位表示的最大整数值为15。我选择使用那些低数字,因为它们只需要几位。如果您要检查二进制文件中的那些整数,那么这些值将是相同的,但在左边还有28个零。
    public int hashCode() {
        int result = x;
        result = 31 * result ^ y;
        result = 31 * result ^ z;
        return result;
    }