web-dev-qa-db-ja.com

Java符号付きゼロとボクシング

最近、私はJavaでプロジェクトを書いて、double/Double実装の非常に奇妙な機能に気づきました。Javaのdouble型には2つの0、つまり0.0がありますおよび-0.0(符号付きゼロ)奇妙なことは、

0.0 == -0.0

trueと評価されますが、次のようになります。

new Double(0.0).equals(new Double(-0.0))

falseと評価されます。誰かがこの背後にある理由を知っていますか?

34
uhz

それはすべて javadoc で説明されています:

ほとんどの場合、クラスDoubleの2つのインスタンス、d1とd2の場合、d1.equals(d2)の値は、

   d1.doubleValue() == d2.doubleValue() 

また、値はtrueです。ただし、2つの例外があります。

  • D1とd2の両方がDouble.NaNを表す場合、Double.NaN == Double.NaNの値がfalseであっても、equalsメソッドはtrueを返します。
  • d1が+0.0を表し、d2が-0.0を表す場合、またはその逆の場合、+ 0.0 ==-0.0の値がtrueであっても、等価テストの値はfalseになります

この定義により、ハッシュテーブルは正しく動作します。


では、なぜ0.0 == -0.0はtrueです。実際、それらは厳密には同一ではありません。例えば:

Double.doubleToRawLongBits(0.0) == Double.doubleToRawLongBits(-0.0); //false

は偽です。ただし、 [〜#〜] jls [〜#〜] には、( "IEEE 754標準の規則に従って")次の条件を満たす必要があります。

正のゼロと負のゼロは等しいと見なされます。

したがって、0.0 == -0.0はtrueです。

44
assylias

Doubleクラスでの符号付きゼロの使用を理解することが重要です。 (経験豊富なJavaプログラマーの負荷はありません)。

短い答えは、(定義により)Doubleクラスによって提供されるすべてのメソッド(つまり、equals()、compare()、compareTo()など)で「-0.0は0.0より小さい」ということです。 )

Doubleを使用すると、すべての浮動小数点数を「完全に数直線上に並べる」ことができます。プリミティブは、ユーザーが物事を考える方法(実際の定義)で動作します... 0d = -0d

次のスニペットは、動作を示しています...

final double d1 = 0d, d2 = -0d;

System.out.println(d1 == d2); //prints ... true
System.out.println(d1 < d2);  //prints ... false
System.out.println(d2 < d1);  //prints ... false
System.out.println(Double.compare(d1, d2)); //prints ... 1
System.out.println(Double.compare(d2, d1)); //prints ... -1

関連し、背景をうまく説明している他の投稿があります...

1:浮動小数点数に符号付きゼロがあるのはなぜですか?

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

そして注意の言葉...

Doubleクラスでは、 "-0.0が0.0未満であることがわからない場合、equals()およびcompare()およびcompareTo()論理テストのDoubleから。たとえば、見てください...

final double d3 = -0d; // try this code with d3 = 0d; for comparison

if (d3 < 0d) {     
    System.out.println("Pay 1 million pounds penalty");
} else {           
    System.out.println("Good things happen"); // this line prints
}


if (Double.compare(d3, 0d) < 0) { //use Double.compare(d3, -0d) to match the above behaviour
    System.out.println("Pay 1 million pounds penalty"); // this line prints
} else {                              
    System.out.println("Good things happen"); 
}

等しい場合は、次を試してください... new Double(d3).equals(0d)||新しいDouble(d3).equals(-0d)

2
K John Smith