最近、Java で double のタプルのハッシュ コードを計算するときに奇妙な状況に遭遇しました。2 つのタプル (1.0,1.0) と (Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY) があるとします。Joshua Bloch の「Effective Java 」(項目 7) で述べられているイディオムを使用すると、これら 2 つのタプルは等しいとは見なされません (これらのタプルがオブジェクトであると想像してください)。hashCode()ただし、項目 8 に記載されている式を使用して各タプルを計算すると、同じ値に評価されます。
私の質問は次のとおりです。この式について、式を書いているときに見逃した何か奇妙なことがありますか?それとも、ハッシュコードの衝突の奇妙なケースですか?
状況を説明するための短い比較方法を次に示します (JUnit4 テストとして記述しましたが、mainメソッドに変換するのは非常に簡単です)。
@Test
public void testDoubleHashCodeAndInfinity(){
double a = 1.0;
double b = 1.0;
double c = Double.POSITIVE_INFINITY;
double d = Double.POSITIVE_INFINITY;
int prime = 31;
int result1 = 17;
int result2 = 17;
long temp1 = Double.doubleToLongBits(a);
long temp2 = Double.doubleToLongBits(c);
//this assertion passes successfully
assertTrue("Double.doubleToLongBits(Double.POSITIVE_INFINITY" +
"==Double.doubleToLongBits(1.0)",temp1!=temp2);
result1 = prime*result1 + (int)(temp1^(temp1>>>32));
result2 = prime*result2 + (int)(temp2^(temp2>>>32));
//this assertion passes successfully
assertTrue("Double.POSITIVE_INFINITY.hashCode()" +
"==(1.0).hashCode()",result1!=result2);
temp1 = Double.doubleToLongBits(b);
temp2 = Double.doubleToLongBits(d);
//this assertion should pass successfully
assertTrue("Double.doubleToLongBits(Double.POSITIVE_INFINITY" +
"==Double.doubleToLongBits(1.0)",temp1!=temp2);
result1 = prime*result1+(int)(temp1^(temp1>>>32));
result2 = prime*result2+(int)(temp2^(temp2>>>32));
//this assertion fails!
assertTrue("(1.0,1.0).hashCode()==" +
"(Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY).hashCode()",
result1!=result2);
}