数値は、ほとんどの座標平面でクラスター化する傾向があります。なぜなら、快適な範囲内の数字を使用する傾向があるからです。このため、単純な xor の組み合わせは望ましくありません。すべての数値 wherex == y
が衝突し、すべての数値 where などが衝突するx + 1 == y
からです。
これを回避するには、x 座標で xor する前に、y 座標のバイトを逆にすることをお勧めします。これにより、1 つの入力の変動性が最も高い領域 (下位バイト) と、他の入力の変動性が最も低い領域 (上位バイト) が結合されます。このようなアルゴリズムは、数のクラスター (1 から 1000 の間の x の値など) を考慮するときに、より均一な分布を提供します。
ハッシュ アルゴリズムは、ハッシュが重度のクラスタリングなしで数値フィールドを生成する場合に最適に機能するため、このようなソリューションは、ハッシュの衝突が頻繁に発生しないため、ハッシュ関連のデータ構造を実際に高速化します。
もちろん、以下は最適化されていません。ニーズに合わせてトリミングできる可能性がありますが、基本的な考え方は次のとおりです。
public int hashCode() {
long bits = Double.doubleToLongBits(y);
byte[] ybits = new byte[] {
(byte)((y >> 56) & 0xff),
(byte)((y >> 48) & 0xff),
(byte)((y >> 40) & 0xff),
(byte)((y >> 32) & 0xff),
(byte)((y >> 24) & 0xff),
(byte)((y >> 16) & 0xff),
(byte)((y >> 8) & 0xff),
(byte)((y >> 0) & 0xff),
};
byte[] xbits = new byte[] {
(byte)((x >> 56) & 0xff),
(byte)((x >> 48) & 0xff),
(byte)((x >> 40) & 0xff),
(byte)((x >> 32) & 0xff),
(byte)((x >> 24) & 0xff),
(byte)((x >> 16) & 0xff),
(byte)((x >> 8) & 0xff),
(byte)((x >> 0) & 0xff),
};
// this combines the bytes of X with the reversed order
// bytes of Y, and then packs both of those into 4 bytes
// because we need to return an int (4 bytes).
byte[] xorbits = new byte[] {
(xbits[0]^ybits[7])^(xbits[4]^ybits[3]),
(xbits[1]^ybits[6])^(xbits[5]^ybits[2]),
(xbits[2]^ybits[5])^(xbits[6]^ybits[1]),
(xbits[3]^ybits[4])^(xbits[7]^ybits[0]),
};
int value = 0;
for (int i = 0; i < 3; i++) {
value = (value << 8) + (by[i] & 0xff);
}
return value;
}
私が提案する最初の最適化は、その後のルックアップのためにオブジェクトにハッシュコードをキャッシュすることです。プロファイリングでそれが問題であることが示唆された場合は、作成/破棄された配列をより効率的に管理することをお勧めします。