XOR操作员 - 它是如何工作的?

时间:2013-08-14 18:42:29

标签: c# binary bitwise-operators xor

请您用简单的英语向我解释一下XOR(^)运算符及其在以下代码中的作用:

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

2 个答案:

答案 0 :(得分:9)

XOR代表排他性或。它确保A或B是真的但不是两者都是。在这种情况下,我们进行按位操作,这样你就可以制作一个很好的结果图,它们如下;

0 ^ 1 = 1
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 0 = 0

由于您将其应用于整数,因此上述结果将应用于操作数中的每个位。因此,我们假设您分别为高度,长度和宽度设置了值1,2,3。

你会先

0001 ^ 0010导致0011然后将XOR' d变为3所以0011 ^ 0011为您提供0000

编辑:提供评论中的wiki链接以补充我的解释; http://en.wikipedia.org/wiki/Exclusive_or#Computer_science

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

所以最好一点一点地做这件事。考虑运算符迭代两组位并比较它们的对。因此,在这种情况下,让我们从右到左工作(在这种情况下最不重要)。

1 ^ 0 = 1 // xxx1
0 ^ 1 = 1 // xx11
0 ^ 0 = 0 // x011
0 ^ 0 = 0 // 0011  - end of input

如此拼凑,你得到0011。基本上,取每对输入并参考结果的真值表。注释显示x的输出是尚未计算的值。

关于碰撞,是的,在这种情况下有很多碰撞。如果我说它是独特的,这是一个糟糕的词选择。我真正的意思是,如果你有2个,8个,4个作为你的值XOR' n它们按顺序总是会产生相同的值。

答案 1 :(得分:2)

稍微详细一点,您会在XOR方法中看到很多getHashCode()字段,因为它是获取对象签名的安全方式。签名的概念是它就像一个对象的指纹,它需要适合32位。许多对象使用此签名作为快速比较(但是,如果您计划使用它,请查看维基百科文章,因为您需要注意相等性和哈希码),或者某些一种寻址方式(如.net的Dictionary和Java的HashMap)。

我获得Box指纹的明显解决方案是简单地将值相加,这样如果其中任何一个改变,你将获得不同的指纹:  bx.Height + bx.Length + bx.Width

鉴于等于操作可能真的很贵(即非常慢),如果我们需要测试两个盒子的相等性:

  • Box {5, 10, 15}
  • Box {30, 40, 50}

我们可以比较两个哈希码,看看它们是不同的,并跳过完全相等的比较,而不是进行完全等于比较。在字典中,为我们提供一种快速查找 bin (元素)以放置对象的方法至关重要。

但是如果这些值中的任何一个太高,我们就会得到一个整数溢出异常,所以我们使用XOR而不是使用加法。另一个解决方案,也是C#相当独特的解决方案,是使用unchecked{ ... }块,但使用XOR被认为更优雅。

我们可以做一件更微妙的事情来提高性能,你会看到很多自动生成的哈希码方法(比如ReSharper或IntelliJ产生的那些): 我们可以通过移动(乘以)每个值来使订单变得重要。

    public int hashCode() {
        int result = x;
        result = 31 * result ^ y;
        result = 31 * result ^ z;
        return result;
    }

现在发生的事情是,哈希码中的每个字段实际上都在最终的32位中占有一席之地。这意味着两个方框:

  • Box {1, 20, 30}
  • Box {1, 30, 20}

不会有相同的哈希码(它们与您当前的系统具有相同的哈希码,但它们是不同的!)

除了你想知道的有关哈希码的信息之外,我还会说一件事。

在Java / Scala和.net框架中,如果重载equals或hash-code,则必须也会使其他重载。 必须还要确保如果两个对象A和B具有不同的哈希码,则对A.Equals(B)的调用必须为false。