web-dev-qa-db-ja.com

JavaのDouble.compare(double、double)がそのまま実装されているのはなぜですか?

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)
}

この実装のメリットは何ですか?


編集:「メリット」は言葉の(非常に)悪い選択でした。これがどのように機能するか知りたいと思いました。

35
DavidS

@Shooverの答えは正しいです(読んでください!)が、これよりも少し多くのことがあります。

Double::equalsjavadoc の状態:

「この定義により、ハッシュテーブルが適切に動作します。」

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で)決定しました。

41
Stephen C

説明はコードのコメントにあります。 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になります。

この定義により、ハッシュテーブルが適切に動作します。

43
shoover

メリットは、仕様を満たす最も単純なコードであるということです。

新人プログラマの一般的な特徴の1つは、ソースコードの過大評価と過小評価仕様です。この場合、仕様は次のとおりです。

http://Java.Sun.com/javase/6/docs/api/Java/lang/Double.html#compareTo%28Java.lang.Double%29

...動作と動作の理由(equals()との一貫性)を完全に明確にします。

2

その実装により、実数を<NaNとして、-0.0を<0.0として定義できます。

0
phoebus