Lately I've written a project in Java and noticed a very strange feature with double/Double implementation. The double type in Java has two 0's, i.e. 0.0 and -0.0 (signed zero's). The strange thing is that:
0.0 == -0.0
evaluates to true, but:
new Double(0.0).equals(new Double(-0.0))
evaluates to false. Does anyone know the reason behind this?
It is all explained in the javadoc:
Note that in most cases, for two instances of class Double, d1 and d2, the value of d1.equals(d2) is true if and only if
d1.doubleValue() == d2.doubleValue()
also has the value true. However, there are two exceptions:
If d1 and d2 both represent Double.NaN, then the equals method returns true, even though Double.NaN==Double.NaN has the value false.
If d1 represents +0.0 while d2 represents -0.0, or vice versa, the equal test has the value false, even though +0.0==-0.0 has the value true.
This definition allows hash tables to operate properly.
Now you might ask why 0.0 == -0.0 is true. In fact they are not strictly identical. For example:
Double.doubleToRawLongBits(0.0) == Double.doubleToRawLongBits(-0.0); //false
is false. However, the JLS requires ("in accordance with the rules of the IEEE 754 standard") that:
Positive zero and negative zero are considered equal.
hence 0.0 == -0.0 is true.
It important to undertand the use of signed zero in the Double class. (Loads of experienced Java programmers don't).
The short answer is that (by definition) "-0.0 is less than 0.0" in all the methods provided by the Double class (that is, equals(), compare(), compareTo(), etc)
Double allows all floating point numbers to be "totally ordered on a number line".
Primitives behave the way a user will think of things (a real world definition) ... 0d = -0d
The following snippets illustrate the behaviour ...
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
There are other posts that are relevant and nicely explain the background ...
1: Why do floating-point numbers have signed zeros?
2: Why is Java's Double.compare(double, double) implemented the way it is?
And a word of caution ...
If you don't know that, in the Double class, "-0.0 is less than 0.0", you may get caught out when using methods like equals() and compare() and compareTo() from Double in logic tests. For example, look at ...
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");
}
and for equals you might try ... new Double(d3).equals(0d) || new Double(d3).equals(-0d)
By using == statement you are comparing values. With equals your are comparing objects.
Related
When I tried this:
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));
The output was what I expected:
true
true
But when I tried:
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));
or
set.add(Double.valueOf(d1));
System.out.println(set.contains(Double.valueOf(d2)));
System.out.println(set.contains(Double.valueOf(d3)));
To my surprise, the output was:
true
false
Why this happened? How do I make HashSet treat (0.0) and (-0.0) the same?
Is there a better way than if(num == -0.0) num = 0.0;?
This is explained by the docs for Double.
If d1 represents +0.0 while d2 represents -0.0, or vice versa, the equal test has the value false, even though +0.0==-0.0 has the value true.
So a Double created from 0.0 is not the same as a Double created from -0.0. The same is not true when you use 0 and -0 because integers use twos-complement, which has no notion of negative zero. -0 is the same as 0. doubles, on the other hand, use the IEEE standard for floating point values, which does recognize a negative zero value.
This behavior is all fixed, so there's no way to have a HashSet treat 0.0 and -0.0 as the same. If you want to do that, you'll need to manually convert all negative zero values into positive zeros before adding or searching for them.
-0.0 is a literal for a double value that is distinct from 0.0.
-0 is the negation operator applied to the int value 0, which gives just the int value 0.
Therefore, new Double(-0) is equivalent to new Double(0), whereas new Double(-0.0) and new Double(0.0) actually produce two non-equal Double objects.
See this question for some explanations for why it is necessary to have two different floating point zero values.
As explained in Wikipedia (thanks), the IEEE format for floating point actually supports negative and positive zeros for various reasons. https://en.wikipedia.org/wiki/Signed_zero
The reason why you find the 0.0 and -0.0 different in your hashmap is directly derived from the IEEE representation. The Double#hashCode method uses the raw bits of the floating point number to calculate the hashcode. Since 0.0 and -0.0 and possibly even +0.0 are different in terms of bits, as some numerical calculations obviously require this, their bits are different and therefore the hashcodes.
This question already has answers here:
How to compare two double values in Java?
(7 answers)
Closed 7 years ago.
I have two double values. I want to check if two double values are same or not. I have two way to compare this double values.
First way :
double a = 0.1;
double b = 0.2;
if(a == b) {
System.out.println("Double values are same");
}
Another way to compare :
if(Double.compare(a, b) == 0) {
System.out.println("Double values are same");
}
Which one is the best way and accurate? Are both ways the same for comparison double values?
Double.compare handles the case of NaN and negative zeros differently than ==. For Double.compare, -0.0d is not equal to 0.0d.
For example the following code:
public static void main(String... args) {
double a = -0.0d;
double b = 0.0d;
if (a == b) {
System.out.println("a == b");
}
if (Double.compare(a, b) == 0) {
System.out.println("Double.compare(a, b) == 0");
}
}
will only print a == b.
The two operations are thus not equivalent. Using one over the other depend on your requirement.
The exact rule concerning == (and !=) can be found in the JLS, section 15.21.1:
Floating-point equality testing is performed in accordance with the rules of the IEEE 754 standard:
If either operand is NaN, then the result of == is false but the result of != is true. Indeed, the test x!=x is true if and only if the value of x is NaN.
Positive zero and negative zero are considered equal.
Otherwise, two distinct floating-point values are considered unequal by the equality operators. In particular, there is one value representing positive infinity and one value representing negative infinity; each compares equal only to itself, and each compares unequal to all other values.
Subject to these considerations for floating-point numbers, the following rules then hold for integer operands or for floating-point operands other than NaN:
The value produced by the == operator is true if the value of the left-hand operand is equal to the value of the right-hand operand; otherwise, the result is false.
The value produced by the != operator is true if the value of the left-hand operand is not equal to the value of the right-hand operand; otherwise, the result is false.
Let's analyze this part:
if(Double.compare(a, b) == 0)
By looking at the documentation of Double.compare, a possible implementation could be the following one (obviously it will be a more optimized one, but that's for the sake of the discussion):
return a == b ? 0 : (a < b ? -1 : +1);
Then, you have another comparison, so it becomes:
if((a == b ? 0 : (a < b ? -1 : +1)) == 0)
In the other case, you rely on a simple comparison using ==, that is:
if(a == b)
That said, in terms of accuracy I guess the result is the same, for the underlying representation of a double does not change and the comparison with 0 does not seem to affect the accuracy.
Which is the best?
Well, from the example above, I'd say the simpler one for you directly compare the values and you are interested only in equality, even though it's unlikely that you are facing with a problem which will benefit from choosing the best way for such a comparison.
Anyway, the approach using Double.compare is more suitable for those cases when you are not only interested in equality, but also in the concepts of greater than and/or less than.
Both of those options are perfectly valid for checking the equality of two numbers. I personally would say the == is nicer, but that's just me.
When double.compare() is better is when you want to know why your variables are not equal. It returns a little more information than true or false - a negative value if the left side is smaller, and a positive if the right side is smaller.
A few interesting observations w.r.t equals operator on 0 and 0.0
new Double(0.0).equals(0) returns false, while new Double(0.0).equals(0.0) returns true.
BigDecimal.ZERO.equals(BigDecimal.valueOf(0.0)) returns false, while BigDecimal.ZERO.equals(BigDecimal.valueOf(0)) returns true.
Looks like the string comparison is being done in both the cases. Could anyone throw some light on this.
Thanks.
BigDecimal 'equals' compares the value and the scale. If you only want to compare values (0 == 0.0) you should use compareTo:
BigDecimal.ZERO.compareTo(BigDecimal.valueOf(0.0)) == 0 //true
BigDecimal.ZERO.compareTo(BigDecimal.valueOf(0)) == 0 //true
See the javadoc.
As for the Double comparison, as explained by other answers, you are comparing a Double with an Integer in new Double(0.0).equals(0), which returns false because the objects have different types. For reference, the code for the equals method in JDK 7 is:
public boolean equals(Object obj) {
return (obj instanceof Double)
&& (doubleToLongBits(((Double)obj).value) ==
doubleToLongBits(value));
}
In your case, (obj instanceof Double) is false.
The 0 in your first expression is interpreted as an int, which may be autoboxed into an Integer, but not to a Double. So the type of the two is different, hence they are not equal. OTOH 0.0 is a double, which is autoboxed into a Double, so the two operands are deemed equal.
BigDecimals also contain a scale (i.e. number of digits to the right of the decimal separator dot). BigDecimal.ZERO has the value of "0", so its scale is 0. Hence it is not equal to "0.0", whose scale is 1.
If you want to compare values, use BigDecimal.compareTo:
BigDecimal.ZERO.compareTo(BigDecimal.valueOf(0.0)) == 0
BigDecimal.ZERO.compareTo(BigDecimal.valueOf(0)) == 0
new Double(0.0).equals(0) is actually boxed as something like this:
new Double(0.0).equals(Integer.valueOf(0))
Double.equals(...) will never return true unless given another Double instance.
new Double(0.0).equals(0); //false
as the argument you passed is integer. and the equels() in Double class checks whether the argument is od instance Double or not using instance of operator.
The Double's equals() method.
if (!(argument instanceof Double))
return false;
The argument you passed is integer, which is not instance of Double, so it returns false.
new Double(0.0).equals(0)
This line compares a double value of 0 (which is not exact zero) with integer of 0.
BigDecimal.ZERO.equals(BigDecimal.valueOf(0.0))
BigDecimal will compare the scale length in the equals operation.
For performance considerations BigDecimal, BigInteger caches small values
0 to 15 in case of BigDecimal (without fractions)
BigDecimal.ZERO will be new BigDecimal(BigInteger.ZERO, 0, 0, 1)
& valueOf method typically picks up from cache for 0 to 15 :)
please try doublevalue instead of compareto if you feel is not as beautiful and readable as or simply need an alternative like below:
BigDecimal a = new BigDecimal("0.00");
BigDecimal b = new BigDecimal("0.0");
BigDecimal c = new BigDecimal("0");
if(a.doubleValue()==BigDecimal.ZERO.doubleValue()) {
System.out.println("a equals");
}
if(b.doubleValue()==BigDecimal.ZERO.doubleValue()) {
System.out.println("b equals");
}
if(c.doubleValue()==BigDecimal.ZERO.doubleValue()) {
System.out.println("c equals");
}
The question says it all. I have an array of doubles and am doing something with them.
double expectedOutput[] = { 6.38792, 12.91079, 14.33333, 13.44517,
12.34539, 12.05397, 8.34061, 2.07900, -2.01999, -5.47802,
-8.21610, -9.26719, -11.02378 };
Ideally, i would test to see if
6.38792 == 6.38792 and end up with a 'pass'
Under certain conditions, i end up with the situation like
6.38792 != NaN
Knowing that this is a valid case sometimes, how can i represent NaN in my code?
I either need to include NaNs into my array of expected elements or somehow figure out that result is Not A Number
I am using Java
In Java, you can get NaN by using
Double.NaN
So you can just put this into your array.
If your question is how to check if something is NaN, you can call
Double.isNan(/* ... value ... */);
You'll have to test for it explicitly, since NaN != NaN, you can't just include it in your array. You have to use Double.isNaN(x).
double d = 0.0/0.0;
if(Double.isNan(d)){
// Double d is not a number.
}
Alternatively:
double d = Double.Nan;
if(Double.isNan(d)){
// Double d is not a number.
}
Since in many languages NaN is not equal to itself (and in Java also), you should handle it as a specific case. Use Float.NaN or Double.NaN to reference NaN. Use Float.isNaN or Double.isNaN to check if a specific value is NaN.
This is a case where Double objects actually are more useful than primitive doubles.
// auto-boxes them all to Double objects
Collection<Double> expectedOutput =
Arrays.asList(6.38792, 12.91079, 14.33333, 13.44517, 12.34539,
12.05397, 8.34061, 2.07900, -2.01999, -5.47802,
-8.21610, -9.26719, -11.02378, Double.NaN );
// maybe fill into HashSet for more efficient lookup?
// later:
double d = Double.NaN;
if(expectedOutput.contains(d)) {
System.out.println("found");
}
The reason is that Double.equals in fact implements the reflexivity condition of the equals contract, meaning that Double.valueOf(Double.NaN).equals(Double.valueOf(Double.NaN)) gives true, contrary to Double.NaN != Double.NaN.
I was looking at the implementation of compare(double, double) in the Java standard library (6). It reads:
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)
}
What are the merits of this implementation?
edit: "Merits" was a (very) bad choice of words. I wanted to know how this works.
The explanation is in the comments in the code. Java has double values for both 0.0 and -0.0, as well as "not a number" (NaN). You can't use simple == operator for these values. Take a peek into the doubleToLongBits() source and at the Javadoc for the Double.equals() method:
Note that in most cases, for two
instances of class Double, d1 and d2,
the value of d1.equals(d2) is true if
and only if
d1.doubleValue() == d2.doubleValue()
also has the value true. However,
there are two exceptions:
If d1 and d2 both represent Double.NaN, then the equals method returns true, even
though Double.NaN == Double.NaN has the value false.
If d1 represents +0.0 while d2 represents -0.0, or vice versa, the equal test has the value false, even though +0.0 == -0.0 has the value true.
This definition allows hash tables to operate properly.
#Shoover's answer is correct (read it!), but there is a bit more to it than this.
As the javadoc for Double::equals states:
"This definition allows hash tables to operate properly."
Suppose that the Java designers had decided to implement equals(...) and compare(...) with the same semantics as == on the wrapped double instances. This would mean that equals() would always return false for a wrapped NaN. Now consider what would happen if you tried to use a wrapped NaN in a Map or Collection.
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.
}
Doesn't make a lot of sense does it!
Other anomalies would exist because -0.0 and +0.0 have different bit patterns but are equal according to ==.
So the Java designers decided (rightly IMO) on the more complicated (but more intuitive) definition for these Double methods that we have today.
The merit is that it's the simplest code that fulfills the specification.
One common characteristic of rookie programmers is to overvalue reading source code and undervalue reading specifications. In this case, the spec:
http://java.sun.com/javase/6/docs/api/java/lang/Double.html#compareTo%28java.lang.Double%29
... makes the behavior and the reason for the behavior (consistency with equals()) perfectly clear.
That implementation allows a real number to be defined as < NaN, and -0.0 as < 0.0.