8

1つの同じオブジェクト、特にstringまたは任意のプリミティブ型または非常に単純な型(struct)の異なる値を生成する.GetHashCode()別のマシンで呼び出されたときのメソッド?

例えば、"Hello World".GetHashCode()異なるマシンで異なる値を生成するため。私は主にC#.NETを求めていますが、これはJavaや他の言語にも当てはまると思いますか。

編集する

以下の答えとコメントから指摘されるように、それは私に知られています.GetHashCode()することができますオーバーライドそして、それが異なるバージョンのフレームワーク間で生成される結果についての保証はありません。したがって、私は単純型を念頭に置いていることを明確にすることが重要です。GetHashCode()私はすべてのマシンで同じバージョンのフレームワークを使用しています。


  • あなたの楽しみのために - blogs.msdn.com/b/ericlippert/archive/2011/02/28/… - Austin Salonen
  • 違いは、x86と64の間の文字列にのみ存在します。「x86とx64では、文字列の異なる戻り値」を検索してください。 @CodyGrayが提供するリンク内 - digEmAll
  • @digEmAll、私はできません、実際、私の質問は、実際のコードで裏付けられるよりもむしろ仮想的なものでした。私は窓分散アプリケーションに内部負荷分散を実装する方法を考えています - 私はサービスを異なるローカルサーバーにデプロイしています、そして私は具体的なサービスを決定することができます。文字列トークンで実行します。そして、私は組み込みハッシュをおそらく最速で最も簡単な方法と考えていましたが、それは私が間違っていたようです。 - Ivaylo Slavov
  • @IvayloSlavov:それがあなたの要件であるならば、GetHashCodeは絶対に、積極的に使うのは間違ったことです。 GetHashCodeは、ハッシュテーブルのバランスをとるためだけに使用します。他の目的でハッシュコードが必要な場合は、その目的に適した独自のハッシュコードアルゴリズムを作成してください。 - Eric Lippert
  • @IvayloSlavov:文字列を安定してハッシュするには、名前空間のメソッドとクラスを使用します。System.Security.Cryptography。例えばあなたが使用することができますMD5 - digEmAll

2 답변


14

短い答え:はい。

しかし、短い答えは面白くないのですか?

実装しているときGetHashCode()次の保証をする必要があります。

いつGetHashCode()このAppドメインでは、これと等しいと見なされるべきである別のオブジェクトで呼び出されると、同じ値が返されます。

それでおしまい。実際にやらなければならないことがいくつかあります(可能な限り等しくないオブジェクトでビットを分散させますが、そもそもハッシュ化のすべての利点よりも優先されるのであまり時間をかけないでください)。そうしなければ吸いますが、実際には壊れません。あなたがそれほど遠くに行かなければそれは壊れるでしょう。

dict[myObj] = 3;
int x = dict[myObj];//KeyNotFoundException

はい。実装している場合GetHashCode()なぜ私はそれより先に進むのでしょうか、そしてなぜ私はしないのですか?

まず、どうして私は違うのでしょうか。

多分それはアセンブリのわずかに異なるバージョンであり、私はビルドの間に改良した(あるいは少なくとも試みた)。

たぶん1つは32ビット、もう1つは64ビットで、効率をよくするためにそれぞれ異なるアルゴリズムを選択しました(特にコレクションや文字列などのオブジェクトをハッシュする場合はこれまでにないことです)。 。

多分私は "等しい"オブジェクトを構成するものを決定する際に検討することにしたいくつかの要素は、このような方法でシステムごとに異なります。

たぶん私は、同僚が私のハッシュコードに誤って依存しているような場合を捉えるために、実際に故意に異なるビルドで異なるシードを導入するかもしれません! (私はMSが彼らの実装でこれをすると聞きましたstring.GetHashCode()しかし、私がそれを信頼できる情報源から聞いたのか、それとも信頼できる情報源から聞いたのかを思い出すことはできません。

しかし、主に、それは最初の2つの理由のうちの1つでしょう。

では、どうして私はそのような保証をしなければならないのでしょうか。

たぶん私がそうするならば、それは偶然によるでしょう。要素が単一の整数idだけに基づいて等しいかどうかを比較できる場合は、それが私のハッシュコードとして使用されることになります。それ以外のものは、あまり良くないハッシュのためにはもっと仕事になるでしょう。これを変更する可能性は低いので、変更するかもしれません。

私がそうするかもしれないもう一つの理由は、私がその保証を自分が欲しいということです。私がそれを提供することができないと言うことは何もありません、私がする必要がないということだけ。


さて、実用的なものに行きましょう。機械に依存しない保証が必要な場合があります。あなたが反対のことを望んでいるかもしれない場合があります。

まず、論理を確認してください。衝突に対処できますか?それでは始めましょう。

それがあなた自身のクラスであれば、そのような保証を提供するように実装し、それを文書化すれば完了です。

それがあなたのクラスではない場合は、次に実装してくださいIEqualityComparer<T>それを提供するような方法で。例えば:

public class ConsistentGuaranteedComparer : IEqualityComparer<string>
{
  public bool Equals(string x, string y)
  {
    return x == y;
  }
  public int GetHashCode(string obj)
  {
    if(obj == null)
      return 0;
    int hash = obj.Length;
    for(int i = 0; i != obj.Length; ++i)
      hash = (hash << 5) - hash + obj[i];
    return hash;
  }
}

それから組み込みのハッシュコードの代わりにこれを使ってください。

私たちが反対を望んでいるかもしれない興味深いケースがあります。ハッシュしている文字列のセットを制御できれば、同じハッシュコードを持つ一連の文字列を選ぶことができます。あなたのハッシュベースのコレクションのパフォーマンスは、最悪のケースに襲われ、かなり残酷なものになるでしょう。たぶん私はあなたがそれに対処することができるより速くこれをし続けることができるので、それはサービス拒否攻撃になることができます。これが起こるケースはあまりありませんが、重要なのは私が送るXML文書を扱っていて、いくつかの要素を除外できない場合です(多くのフォーマットはそれらの中の要素の自由を可能にします)。そうしてNameTableあなたのパーサーの中は怪我をするでしょう。この場合、毎回新しいハッシュメカニズムを作成します。

public class RandomComparer : IEqualityComparer<string>
{
  private int hashSeed = Environment.TickCount;
  public bool Equals(string x, string y)
  {
    return x == y;
  }
  public int GetHashCode(string obj)
  {
    if(obj == null)
      return 0;
    int hash = hashSeed + obj.Length;
    for(int i = 0; i != obj.Length; ++i)
      hash = hash << 5 - hash + obj[i];
    hash += (hash <<  15) ^ 0xffffcd7d;
    hash ^= (hash >>> 10);
    hash += (hash <<   3);
    hash ^= (hash >>>  6);
    hash += (hash <<   2) + (hash << 14);
    return hash ^ (hash >>> 16)
  }
}

これは特定の用途では一貫していますが、用途ごとでは一貫していません。そのため、攻撃者は入力を強制的にDoSsedにすることはできません。ちなみにNameTableを使用しないIEqualityComparer<T>必要でない限り、文字列を構築せずにインデックスと長さを持つchar配列を扱いたいのですが、似たようなことをします。

ちなみに、Javaではハッシュコードはstringが指定されて変更されることはありませんが、これは他のクラスには当てはまりません。

編集:アプローチの全体的な質についていくつかの研究を行ったことConsistentGuaranteedComparer上記のように、私は自分の答えにそのようなアルゴリズムがあることにもう満足していません。それは概念を説明するのに役立ちますが、それは人が好むかもしれないほど良いディストリビューションを持っていません。もちろん、そのようなことをすでに実装しているのであれば、保証を破ることなしにそれを変更することはできません。この研究の後に書かれた私のこの図書館次のように:

public class ConsistentGuaranteedComparer : IEqualityComparer<string>
{
  public bool Equals(string x, string y)
  {
    return x == y;
  }
  public int GetHashCode(string obj)
  {
    return obj.SpookyHash32();
  }
}

それはRandomComparer上記はそれほど悪くはありませんが、改善することもできます。

public class RandomComparer : IEqualityComparer<string>
{
  private int hashSeed = Environment.TickCount;
  public bool Equals(string x, string y)
  {
    return x == y;
  }
  public int GetHashCode(string obj)
  {
    return obj.SpookyHash32(hashSeed);
  }
}

あるいは、予測がさらに難しい場合は、

public class RandomComparer : IEqualityComparer<string>
{
  private long seed0 = Environment.TickCount;
  private long seed1 = DateTime.Now.Ticks;
  public bool Equals(string x, string y)
  {
    return x == y;
  }
  public int GetHashCode(string obj)
  {
    return obj.SpookyHash128(seed0, seed1).GetHashCode();
  }
}


  • これは私が聞いたことをはるかに超えています。私はこの情報を持っていて本当に本当にあなたの努力に感謝しています。ありがとうございました - Ivaylo Slavov
  • 私が言ったように、短い答えは面白くない:) - Jon Hanna
  • 私はNameTableのハッシュの実装についての情報を探していました - なぜそれがGetHashCode()と違うのか疑問に思いました、そしてこの答えはそれをカバーしました。よくやった! - Clay
  • 「MSは次の目的のために実装してこれを行っていると聞きましたstring.GetHashCode()...".NETソースが利用可能になりました今信頼できる情報源を持っていますそれは彼らが実際にいくつかのビルドでランダムハッシュコードを使用していることを示していますFEATURE_RANDOMIZED_STRING_HASHINGビルド変数が設定されています。また、DEBUG彼らも作るhash1 ^= ThisAssembly.DailyBuildNumber;ハッシュ値を永続化しようとするような愚かなことをしている人がいないことを確認するため - Scott Chamberlain

1

それ意志実行が異なる同じマシンでも、結果が異なります。

そのため、基本的には(実際に使用されている)使用中に何かをチェックすることができます。現在プログラムの実行が、その後それに対して何かをチェックするためにそれを格納するためには意味がありません。あなたが得た数が生成される原因ランタイム

編集

文字列の特定のケースでは、マシンのアーキテクチャが異なる場合を除いて、異なるマシンでも同じ結果が得られます。


  • もっと明確にしてもらえますか。私の質問の再考を考慮に入れてください - 私は、継承不可能な単純型または原始型のみを要求することを明確にしました。あなたもより多くの情報のためにいくつかのリンクを共有することができるでしょうか?前もって感謝します - Ivaylo Slavov
  • それは本当ではありません。文字列の場合は、プラットフォームを変更した場合にのみ異なる値が取得されます(x86 vs x64)。それ以外の場合、GetHashValueは常に同じ値を返します。 - digEmAll
  • @digEmAll:修正しました - Tigran
  • @IvayloSlavov:編集した投稿を確認してください。 - Tigran
  • まだ間違っています。同じ文字列、同じフレームワークバージョン、同じ結果。ただし、そうである必要はありません。 - Jon Hanna

リンクされた質問


関連する質問

最近の質問