Java標準ライブラリ(6)の compare(double、double) の実装を見ていました。
public static int compare(double d1, double d2) {
if (d1 < d2)
return -1; // Neither val is NaN, thisVal is smaller
if (d1 > d2)
return 1; // Neither val is NaN, thisVal is larger
long thisBits = Double.doubleToLongBits(d1);
long anotherBits = Double.doubleToLongBits(d2);
return (thisBits == anotherBits ? 0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1)); // (0.0, -0.0) or (NaN, !NaN)
}
この実装のメリットは何ですか?
編集:「メリット」は言葉の(非常に)悪い選択でした。これがどのように機能するか知りたいと思いました。
@Shooverの答えは正しいです(読んでください!)が、これよりも少し多くのことがあります。
Double::equals
の javadoc の状態:
「この定義により、ハッシュテーブルが適切に動作します。」
Javaデザイナーが、ラップされたdouble
インスタンスに==
と同じセマンティクスでequals(...)
およびcompare(...)
を実装することを決定したと仮定します。 equals()
はラップされたNaNに対して常にfalse
を返すことを意味します。マップまたはコレクションでラップされたNaNを使用しようとするとどうなるかを考えてください。
List<Double> l = new ArrayList<Double>();
l.add(Double.NaN);
if (l.contains(Double.NaN)) {
// this wont be executed.
}
Map<Object,String> m = new HashMap<Object,String>();
m.put(Double.NaN, "Hi mum");
if (m.get(Double.NaN) != null) {
// this wont be executed.
}
あまり意味がありません。
-0.0
と+0.0
は異なるビットパターンを持っていますが、==
に応じて等しいため、他の異常が存在します。
したがって、Javaデザイナーは、今日のこれらのDoubleメソッドのより複雑な(より直感的な)定義を(当然IMOで)決定しました。
説明はコードのコメントにあります。 Javaには_0.0
_と_-0.0
_の両方に二重値があり、「not a number」(NaN
)。単純な_==
_は使用できません。これらの値の演算子。doubleToLongBits()
ソースを覗いて Double.equals()
メソッドのJavadoc :
ほとんどの場合、クラス
Double
、_d1
_、および_d2
_の2つのインスタンスでは、d1.equals(d2)
の値はtrue
であることに注意してください。_d1.doubleValue() == d2.doubleValue()
_値
true
も持っています。ただし、2つの例外があります。
- _
d1
_と_d2
_の両方が_Double.NaN
_を表す場合、_Double.NaN == Double.NaN
_の値はtrue
であっても、equalsメソッドはfalse
を返します。- _
d1
_が_+0.0
_を表し、_d2
_が_-0.0
_を表す、またはその逆の場合、_+0.0 == -0.0
_の値はfalse
であっても、等しいテストの値はtrue
になります。この定義により、ハッシュテーブルが適切に動作します。
メリットは、仕様を満たす最も単純なコードであるということです。
新人プログラマの一般的な特徴の1つは、ソースコードの過大評価と過小評価仕様です。この場合、仕様は次のとおりです。
http://Java.Sun.com/javase/6/docs/api/Java/lang/Double.html#compareTo%28Java.lang.Double%29
...動作と動作の理由(equals()との一貫性)を完全に明確にします。
その実装により、実数を<NaNとして、-0.0を<0.0として定義できます。