2011-09-27 136 views
8

这个代码块中代字号的用途是什么?波浪在这种情况下的目的是什么?

public override int GetHashCode() 
    { 
     return ~this.DimensionId.Id^this.ElementId.Id; 
    } 

^运算符(C#参考) Visual Studio 2010中 二元^运算符预定义的整型和布尔。对于整型,^计算其操作数的按位异或。对于bool操作数,^计算逻辑异或操作数;也就是说,当且仅当其中一个操作数为真时,结果才是真的。

〜算符(C#参考) Visual Studio 2010中 操作符〜对其运算数执行,其具有反转每个比特的效果的按位求补操作。按位补充运算符是为int,uint,long和ulong预定义的。

〜(代字号)运算符对其单个整数操作数执行按位补码。 (因此〜运算符是一元运算符,例如!和一元运算符,即&和*运算符)。补数表示将所有0位全部更改为1,将所有1全部更改为0

什么是原因为什么它会在这种情况下使用(而不是简单地排除它)?

+0

如果值很小,xor运算符往往会产生较差的散列分布。翻转这些位可以改变这一点。这实际上运作的可能性不好。将素数乘以1,并更好地添加作品。 –

回答

13

这只是生成哈希码的一种方式。我并不是散列码中的XOR的狂热粉丝,除非你想要一些与顺序无关的东西,但它是以合理的任意但可重复的方式翻转位的合理方式。

基本上你在这里有两个32位值,你需要以某种形式组合以创建另一个32位值。代码可能刚才异或的值加在一起没有任何位补:

return DimensionId.Id^ElementId.Id; 

...但总是给零其中ElementId.Id == DimensionId.Id,这可能是不理想的情况。另一方面,如评论(doh!)所述,如果两个ID是相同的,我们现在总是以-1结尾。另一方面,它使得{6,4}对具有与{4,6}不同的散列码,而简单的XOR则不会......换言之,它使得排序很重要。同样,如果您的标识符可能来自相对较小的池,那么这可能很重要。

的XOR本身可以确保更改任何要么 ID使最终散列码的差异。我个人通常遵循Josh Bloch的有效Java模式,例如,

unchecked 
{ 
    int hash = 17; 
    hash = hash * 31 + DimensionId.Id; 
    hash = hash * 31 + ElementId.Id; 
    return hash; 
} 

...但是这只是因为一些散列这样的特性,并且不会让你出任何意义上的“错误”的执行情况。


这似乎在一些常见的场景产生不同的值工作得很好。显然它不能防止哈希冲突,但如果您的ID实际上是从1,2,3的序列中生成的,那么这将在XOR的实际冲突中更好。我看到一个分析这种方法的网页,哪些数字工作得很好等,但我不记得在哪里。

+0

Jon Skeet-完全无知的问题:散列码中XOR的替代/更好的方法是什么? XOR是我知道做得好的唯一方式。 –

+0

@RitchMelton:当您评论时,我可能会将我的首选代码放入...请参阅我的答案的底部。 –

+0

@Jon - 我是否在C#深度第二版中错过这些运算符?无论如何,谢谢你的信息! –

相关问题