2013-04-05 91 views
1

我开始使用我的算法测试生成的HashCodes的唯一性的哈希函数。我写了下一个文本类来测试何时会生成相同的hashCode。加入HashCode魔术

class Program 
{ 
    static void Main(string[] args) 
    { 
     var hashes = new List<int>(); 
     for (int i = 0; i < 100000; i++) 
     { 
      var vol = new Volume(); 
      var code = vol.GetHashCode(); 
      if (!hashes.Contains(code)) 
      { 
       hashes.Add(code); 
      } 
      else 
      { 
       Console.WriteLine("Same hash code generated on the {0} retry", hashes.Count()); 
      } 
     } 
    } 
} 

public class Volume 
{ 
    public Guid DriverId = Guid.NewGuid(); 
    public Guid ComputerId = Guid.NewGuid(); 
    public int Size; 
    public ulong VersionNumber; 
    public int HashCode; 
    public static ulong CurDriverEpochNumber; 
    public static Random RandomF = new Random(); 

    public Volume() 
    { 
     Size = RandomF.Next(1000000, 1200000); 
     CurDriverEpochNumber ++; 
     VersionNumber = CurDriverEpochNumber; 
     HashCode = GetHashCodeInternal(); 
    } 

    public int GetHashCodeInternal() 
    { 
     unchecked 
     { 
      var one = DriverId.GetHashCode() + ComputerId.GetHashCode() * 22; 
      var two = (ulong)Size + VersionNumber; 
      var result = one^(int)two; 
      return result; 
     } 
    } 

} 

GUID字段DriverId,ComputerId和int大小是随机的。 我认为在某个时候我们会生成相同的散列码。你知道它会打破大集合的工作。魔术实际上是当重复的 哈希码生成时的重试数是相同的!我运行了几次示例代码并得到了接近相同的结果:冷杉在10170重试上运行重复,在7628上运行第二个,在7628上运行第三个7628 ,并且一次又一次在7628上运行。有时候我得到了一些其他结果。在大多数情况下它是在7628.

它对我没有任何解释。 它是错误的。 NET随机发生器还是什么?


谢谢大家。现在很明显,我的代码中存在bug(马修沃森)。我不得不调用GetHashCodeIntelrnal()而不是GetHashCode()。最好的GetHashCode独特的效果给了我:

public int GetHashCodeInternal() 
    { 
     unchecked 
     { 
      var one = DriverId.GetHashCode() + ComputerId.GetHashCode(); 
      var two = ((ulong)Size) + VersionNumber; 
      var result = one^(int)two << 32; 
      return result; 
     } 
    } 

卜仍接近140 000给它相同的代码...我认为这是不好的,因为已经有接近10 000集...

+0

*你知道它会打破大集合的工作。* - 你为什么这么想? – MarcinJuraszek 2013-04-05 10:30:28

+1

随机数发生器只是一个伪随机数发生器(http://en.wikipedia.org/wiki/Pseudorandom_number_generator),这意味着结果可以以某种方式预测。 – pascalhein 2013-04-05 10:31:36

+0

“你为什么这么想?” - 如果在集合中有什么项目具有相同的哈希码?或者如果某些地方有通过hashCode进行搜索但存在其他对象的hashCode呢?这是正常的吗? – 2013-04-05 10:37:24

回答

2

如果你改变你的Console.WriteLine()同时打印Volume.Size像这样:

Console.WriteLine("Same hash code generated on the {0} retry ({1})", hashes.Count, vol.Size); 

,你会看到,虽然hashes.Count始终是第一次碰撞一样,vol.Size通常是不同的。

这似乎排除了随机数发生器导致此问题 - 它看起来像GetHashCodeInternal()一些奇怪的属性。

更仔细的检查显示您正在调用错误的哈希码功能。

这条线:var code = vol.GetHashCode();

应该是:var code = vol.HashCode;

尝试,而不是!因为目前你正在调用默认的.Net GetHashCode(),这根本就不是你想要的。

+0

Oups ..谢谢。我是sory) – 2013-04-05 11:02:26

+0

这实际上很有趣,因为它演示了默认的.Net'GetHashCode()'是多么糟糕。我认为在GC决定运行时它必须重复,并且每次都在同一时刻踢球。 – 2013-04-05 11:06:16

+0

有什么不好的?如果旧对象已被垃圾收集,则重用相同的散列是很好的。 – 2013-04-05 17:31:17

1

你会需要通过随机数生成器,创建了一个可以重复使用的随机数生成器,因为目前您正在将它们的新实例相互靠得过近,导致使用相同的种子,因此会出现相同的数字序列。

您的结果将随机在种子日期的下一个蜱/秒产生种子的点上看似随机出现。所以,只是偶然的,真的。

+0

我试过使用相同的实例,它没有帮助。更新代码... – 2013-04-05 10:39:38

+0

请参阅我的代码更改...(new Random(DateTime.Now.Millisecond))。Next(1000000,1200000);也没有帮助。我需要做些什么来获得随机? – 2013-04-05 10:47:58

+0

创建类型的生成器_outside_,并将值传递给构造函数。但请记住,在一个紧密的循环中,“Next”仍然是可以预测的 - 考虑老虎机,他们有一个随机数发生器运行_constantly,总是产生数字,直到你按下一个按钮 - 独立于其他事物 - 然后选择当前的数字。让它一起运行或按需运行是错误的做法。 – 2013-04-05 10:51:46