【问题标题】:What is the purpose of the tilde in this situation?在这种情况下,波浪号的目的是什么?
【发布时间】:2011-11-26 04:50:15
【问题描述】:

此代码块中波浪号的用途可能是什么?

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

^ 运算符(C# 参考) 视觉工作室 2010 二进制 ^ 运算符是为整数类型和 bool 预定义的。对于整数类型,^ 计算其操作数的按位异或。对于 bool 操作数,^ 计算其操作数的逻辑异或;也就是说,当且仅当它的一个操作数恰好为真时,结果才为真。

~ 运算符(C# 参考) 视觉工作室 2010 ~ 运算符对其操作数执行按位补码运算,这具有反转每个位的效果。为 int、uint、long 和 ulong 预定义了按位补码运算符。

~(波浪号)运算符对其单个整数操作数执行按位补码。 (因此,~ 运算符是一元运算符,如 ! 和一元 -、& 和 * 运算符。)对数字进行补码意味着将所有 0 位更改为 1,将所有 1 更改为 0

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

【问题讨论】:

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

标签: c#


【解决方案1】:

这只是生成哈希码的一种方式。我不是哈希码中的 XOR 的忠实拥护者,除非您想要一些与顺序无关的东西,但这是一种以合理任意但可重复的方式翻转位的合理方式。

基本上,这里有两个 32 位值,您需要将它们以某种形式组合以创建另一个 32 位值。代码可能只是将这些值异或在一起而没有任何按位补码:

return DimensionId.Id ^ ElementId.Id;

...但是对于ElementId.Id == DimensionId.Id 的情况,这总是为零,这可能并不理想。另一方面,如果两个 ID 相同,我们现在总是以 -1 结束,如 cmets 中所述(doh!)。另一方面,它使对 {6, 4} 具有与 {4, 6} 不同的哈希码,而简单的 XOR 则没有……换句话说,它使排序变得重要。同样,如果您的 real 标识符可能来自相对较小的池,这可能很重要。

XOR 本身确保对 either ID 中的 any 位的更改会对最终的哈希码产生影响。

就我个人而言,我通常从有效的 Java 中遵循 Josh Bloch 的模式,例如

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

...但这只是因为这种散列方式的某些属性1,它不会使您显示的实现在任何意义上都“错误”。


1 在许多常见场景中,它似乎可以很好地生成不同的值。显然它不能防止哈希冲突,但是如果你的 ID 实际上是从 1、2、3 的序列生成的......那么这在现实生活中的冲突中会比 XOR 做得更好。我确实看到一个网页分析了这种方法以及哪些数字运作良好等,但我不记得在哪里。

【讨论】:

  • Jon Skeet- 完全无知的问题:哈希码中异或的替代/更好的方法是什么? XOR 是我知道的唯一方法。
  • @RitchMelton:当您发表评论时,我可能正在输入我喜欢的代码......请参阅我的答案的底部。
  • @Jon - 我在 C# 深度第二版中错过了这些运算符吗?无论如何感谢您的信息!
  • 但是,对于 ElementId.Id == DimensionId.Id 的情况,使用 ~ 总是会给出 -1。
  • @AdamRackis:不,我没有在 C# 中深入介绍这些内容,因为它们自 C# 1 以来就没有改变。
猜你喜欢
  • 2014-05-21
  • 2013-04-23
  • 1970-01-01
  • 2012-04-21
  • 1970-01-01
  • 2021-12-27
  • 1970-01-01
  • 1970-01-01
  • 2020-08-08
相关资源
最近更新 更多