以下の記事によれば、-1000~1000 の範囲で(int, int).GetHashCode
を検証したところ、98.3%衝突していたということ。
C#でDictionaryのキーに2つのintを使いたい場合の性能比較 (ただしキーの範囲は[-32768, 32767])
数字が衝撃的なので、自分でも確認してみる。
結論からいえば、現状の CoreCLR だと異なる結果となった。
オンラインサンドボックスで変わり目を試すことができたので、この記事では次のサービスによる実行結果を用いる。
C# Online Compiler | .NET Fiddle
以下のコードを使う。
範囲を -512~512 としているが、これはサービスのメモリ制限の都合。
using System; using System.Collections.Generic; public class Program { public static void Main() { var hashes = new HashSet<int>(); const int start = -512, end = 512; int count = 0; for (int x = start; x <= end; x++) { for (int y = start; y <= end; y++) { var hashCode = (x, y).GetHashCode(); if (hashes.Add(hashCode)) count++; } } const int len = end - start + 1; const double total = len * len; Console.WriteLine($"count={count}, collision rate={(total - count) / total:0.000%}"); } }
上のコードを、compiler = .NET CORE 3.1 で実行すると以下。
count=34849, collision rate=96.683%
冒頭記事の検証環境である Unity は Mono であり .NET CORE 3.1 と等価ではないが、この部分は同様そうで、大惨事な衝突状況となった。
次に、compiler = .NET 5 で実行すると以下。
count=1050625, collision rate=0.000%
🤗
🔎「Unity CoreCLR 移行 いつ」
Unity だけではなく例えば競プロなどでも C# は環境が古かったりするので、C# のよくないところ(C# が悪いわけじゃないけど)が出ているという感じがする。
ということで、該当環境でないか確認すれば、(int, int).GetHashCode
は問題なさそう。