xor
ハッシュ時に使用する危険なデフォルト関数です。and
and よりも優れていますが、それはor
あまり意味がありません。
xor
は対称なので、要素の順序が失われます。したがって、"bad"
ハッシュ結合はと同じになり"dab"
ます。
xor
ペアワイズの同一の値をゼロにマッピングします。「共通」の値をゼロにマッピングすることは避けてください。
その(a,a)
ため、0にマッピングされ、0に(b,b)
もマッピングされます。このようなペアは、ほとんどの場合、ランダム性が意味するよりも一般的であるため、ゼロよりはるかに多くの衝突が発生します。
これらの2つの問題により、xor
最終的には表面上はまともなように見えるハッシュコンバイナになりますが、さらに検査した後ではありません。
最近のハードウェアでは、通常、追加と同じくらいの速さで追加されますxor
(おそらく、これをオフにするためにより多くの電力を使用します)。加算の真理値表はxor
、問題のビットに似ていますが、両方の値が1の場合、次のビットにビットを送信します。つまり、消去する情報が少なくなります。
したがって、ifの場合hash(a) + hash(b)
よりも、結果は0ではなく、より優れています。hash(a) xor hash(b)
a==b
hash(a)<<1
これは対称的なままです。したがって、同じ結果"bad"
を"dab"
得るのは依然として問題です。適度なコストでこの対称性を破ることができます。
hash(a)<<1 + hash(a) + hash(b)
別名hash(a)*3 + hash(b)
。(hash(a)
シフトソリューションを使用する場合は、一度計算して保存することをお勧めします)。の代わりに奇数定数を使用する3
と、「- k
bit」の符号なし整数がそれ自体に全単射でマッピングされます。符号なし整数のマップは2^k
someの数学モジュロk
であり、奇数定数はに対して比較的素数2^k
です。
より洗練されたバージョンについては、を調べることができますboost::hash_combine
。
size_t hash_combine( size_t lhs, size_t rhs ) {
lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2);
return lhs;
}
ここでは、いくつかのシフトされたバージョンのseed
定数と定数(基本的にランダムな0
sと1
sです。特に、32ビットの固定小数点部分としての黄金比の逆数です)といくつかの加算とxorを足し合わせます。この休憩は対称、着信ハッシュされた値、すなわち、0にすべてのコンポーネントのハッシュを想像(貧弱であれば、いくつかの「ノイズ」を紹介- 、上記のハンドルを、それは井戸のスミアが発生1
して0
。それぞれが結合した後、俺のナイーブは3*hash(a)+hash(b)
単に出力0
でのその場合)。
(C / C ++に精通していない場合、a size_t
は、メモリ内のオブジェクトのサイズを説明するのに十分な大きさの符号なし整数値です。64ビットシステムでは、通常64ビットの符号なし整数です。32ビットシステムでは、32ビットの符号なし整数。)