2013-04-05 110 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