2013-02-08 4 views
29

In letzter Zeit habe ich ein Projekt in Java geschrieben und bemerkte eine sehr seltsame Eigenschaft mit Doppel/Doppel-Implementierung. Der Double-Typ in Java hat zwei Nullen, d. H. 0.0 und -0.0 (vorzeichenbehaftete Nullen). Das Merkwürdige ist, dass:Java unterzeichnete Null und Boxen

0.0 == -0.0 

zu true auswertet, aber:

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

zu false auswertet. Weiß jemand den Grund dafür?

+5

Der übliche Weg, dies zu vermeiden, ist '0.0' hinzuzufügen. Sehen Sie [hier] (http://stackoverflow.com/a/8153449/823393) für ein wenig mehr Details. – OldCurmudgeon

Antwort

38

Alles in the javadoc erklärt:

Beachten Sie, dass

in den meisten Fällen für zwei Instanzen der Klasse Double, d1 und d2, der Wert von d1.equals (d2) ist wahr, wenn und nur dann, wenn
d1.doubleValue() == d2.doubleValue() 

hat auch den Wert wahr. Allerdings gibt es zwei Ausnahmen:

  • Wenn d1 und d2 beide Double.NaN darstellen, dann ist die Methode equals true zurückgibt, obwohl Double.NaN == Double.NaN den Wert false hat.
  • Wenn d1 für +0,0 steht, während d2 für -0,0 steht, oder umgekehrt, hat der Gleichheitstest den Wert false, obwohl +0.0 == - 0.0 den Wert wahr hat.

Diese Definition ermöglicht den ordnungsgemäßen Betrieb von Hashtabellen.


Nun könnte man fragen, warum 0.0 == -0.0 wahr ist. Tatsächlich sind sie nicht genau identisch. Zum Beispiel:

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

ist falsch. Allerdings erfordert die JLS ("in Übereinstimmung mit den Regeln der IEEE 754-Standard"), dass:

Positive Null und negative Null gleich betrachtet werden.

daher 0.0 == -0.0 ist wahr.

+2

Und die JLS erfordert das, weil das IEEE 754 es erfordert. – ninjalj

+1

@ninjalj Tatsächlich - Diese Klarstellung hinzugefügt. – assylias

-5

von == Anweisung Sie Werte vergleichen. Mit equals vergleichen Sie Objekte.

2

Es ist wichtig, die Verwendung von signierter Null in der Doppel Klasse undertand. (Viele erfahrene Java-Programmierer nicht).

Die kurze Antwort ist, dass (per Definition) "-0,0 weniger als 0.0" in allen von der Doppel-Klasse Methoden (dh, equals(), vergleichen(), compareTo(), usw.)

Mit Double können alle Gleitpunktzahlen "auf einer Nummernleitung vollständig angeordnet" werden. Primitive verhalten sich so, wie ein Benutzer über Dinge denkt (eine echte Definition) ...0T = -0D

Die folgenden Schnipsel das Verhalten veranschaulichen ...

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 

Es gibt andere Stellen, die relevant sind und schön den Hintergrund erklären ...

1: Why do floating-point numbers have signed zeros?

2: Why is Java's Double.compare(double, double) implemented the way it is?

Und ein Wort der Vorsicht ...

Falls Sie nicht wissen, in der Doppel Klasse, „-0,0 weniger als 0,0“, können Sie heraus hängen bleiben, wenn Methoden wie equals mit () und vergleichen() und compareTo() von Double in Logiktests. Blick zum Beispiel auf ...

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

und für gleich Sie könnten versuchen, ... neue Doppel (d3) .equals (0T) || neu Double (d3) .equals (-0d)