2016-03-21 16 views
0

Als ich das versucht:Warum HashSet unterscheidet 0,0 und -0,0

HashSet<Double> set = new HashSet<>(); 
Double d1 = new Double(0); 
Double d2 = new Double(0); 
Double d3 = new Double(-0); 
set.add(d1); 
System.out.println(set.contains(d2)); 
System.out.println(set.contains(d3)); 

Der Ausgang war das, was ich erwartet hatte:

true 
true 

Aber als ich versuchte:

HashSet<Double> set = new HashSet<>(); 
Double d1 = new Double(0.0); 
Double d2 = new Double(0.0); 
Double d3 = new Double(-0.0); 
set.add(d1); 
System.out.println(set.contains(d2)); 
System.out.println(set.contains(d3)); 

oder

set.add(Double.valueOf(d1)); 
System.out.println(set.contains(Double.valueOf(d2))); 
System.out.println(set.contains(Double.valueOf(d3))); 

Zu meiner Überraschung war die Ausgabe:

true 
false 

Warum dies geschehen? Wie mache ich HashSet treat (0.0) und (-0.0) gleich? Gibt es einen besseren Weg als if(num == -0.0) num = 0.0;?

+0

Versuchen Sie mit 'Double.valueOf()' anstelle von 'new Double()'? – fge

+1

Es tut es nicht, aber 'Double' tut. – EJP

+0

Das Vergleichen von Fließkommawerten mit == ist in der Tat gefährlich. Tu es nicht. – ncmathsadist

Antwort

4

Dies wird durchfür Double erklärt.

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.

So ein Double von 0.0 erstellt ist nicht das gleiche wie ein Double von -0.0 erstellt. Das gleiche gilt nicht, wenn Sie 0 und -0 verwenden, da ganze Zahlen Zweierkomplement verwenden, das keine negative Nullvorstellung hat. -0 ist das gleiche wie 0. double s, auf der anderen Seite, use the IEEE standard for floating point values, die einen negativen Nullwert erkennt.

Dieses Verhalten ist alles behoben, so gibt es keine Möglichkeit, HashSet behandeln 0.0 und -0.0 als gleich. Wenn Sie dies tun möchten, müssen Sie alle negativen Nullwerte manuell in positive Nullen konvertieren, bevor Sie sie hinzufügen oder suchen.

2

-0.0 ist ein Literal für einen double Wert, der aus 0.0 unterscheidet.

-0 ist die Negation Operator auf den int Wert angewendet 0, die 0 nur den int Wert.

Daher ist new Double(-0) entspricht new Double(0), während new Double(-0.0) und new Double(0.0) tatsächlich zwei nicht gleich Double Objekte erzeugen.

Für einige Erklärungen, warum zwei verschiedene Gleitkommawerte erforderlich sind, siehe this question.

1

Wie in Wikipedia (Thanks) erklärt, unterstützt das IEEE-Format für Gleitkommazahlen aus verschiedenen Gründen negative und positive Nullen. https://en.wikipedia.org/wiki/Signed_zero

Der Grund, warum Sie die Werte 0.0 und -0.0 in Ihrer Hashmappe finden, ist direkt von der IEEE-Darstellung abgeleitet.Die Methode Double # hashCode verwendet die Rohbits der Fließkommazahl, um den Hashcode zu berechnen. Da 0,0 und -0,0 und möglicherweise sogar +0,0 bitormäßig verschieden sind, da einige numerische Berechnungen dies offensichtlich erfordern, sind ihre Bits unterschiedlich und daher die Hashcodes.