Comparing Scala and Java Double.NaN - java

Why does this comparison evaluate to true?
scala> Double.NaN equals java.lang.Double.NaN
res5: Boolean = true
But this one evaluates to false?
scala> Double.NaN == java.lang.Double.NaN
res6: Boolean = false
aside: this interesting Twitter thread prompted me to ask this question

This is not about Scala's NaN vs. Java's -- there is only one NaN:
scala> val a = Double.NaN
a: Double = NaN
scala> val b = java.lang.Double.NaN
b: Double = NaN
Nor is it about there being two objects with the same value. It's about the definition of NaN. Two NaNs are not == because that's the way NaN is defined -- it is not a number, but rather a special value that means "undefined." If you have two of those, how would you know whether they are equal? For example:
scala> val x = 0.0 / 0.0
x: Double = NaN
scala> val y = Math.sqrt(-1)
y: Double = NaN
scala> x == y
res9: Boolean = false
Fortunately they are not ==; they are not numbers whose values you can compare.
As for x.equals(y), well, why would you do that in Scala? But given that you did, you are running into the bit of Java weirdness that I.K. pointed us to the docs for. Let's demonstrate it:
public class Foo {
public static void main( String[] args ) {
double nan1 = 0.0 / 0.0; Double box1 = nan1;
double nan2 = Math.sqrt(-1); Double box2 = nan2;
System.out.println( nan1 == nan2 ); // false, as expected
System.out.println( box1.equals(box2) ); // true -- WTF???
}
}

Double.NaN is the same as java.lang.Double.NaN, as AmigoNice already said. It's a Double (or double in Java terms). So using == on it is the same as == in Java and returns false for two NaNs, as expected. However, using equals forces the compiler to box both sides to java.lang.Double, and Double.equals is defined to return true in this case (which I just learned and which surprised me).

scala> Double.NaN equals java.lang.Double.NaN
res5: Boolean = true
This evaluates to true because Double.NaN is equivalent to java.lang.Double.NaN. Consequently, the equals method for java.lang.Double is called. According to the Java documentation, for two doubles, d1 and d2, if d1 and d2 both represent Double.NaN, then the equals method returns true, even though the value should be false according to IEEE specification.
scala> Double.NaN == java.lang.Double.NaN
res6: Boolean = false
This evaluates to false because Scala's == operator follows the IEEE specification. It does not call down to the Java == operator. Also, NaN is not a number as mentioned by #AmigoNico. It is a place holder for a large number of "invalid" values. There is no way of knowing whether two NaN's are equal, because they could be represented by two different "invalid" values.

Related

Meaning of Double.doubleToLongBits(x)

I am writing a class Vec2D, representing a 2 dimensional vector. I store x and y in doubles.
When asked to generate equals(Object obj and hashCode(), eclipse generated this:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(x);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(y);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Vec2D other = (Vec2D) obj;
if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
return false;
if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
return false;
return true;
}
What is the significance of Double.doubleToLongBits(x) in this context? Can I not simply write x != other.x?
Short answer: Eclipse uses Double.doubleToLongBits because that's what Double.equals does:
The result is true if and only if the argument is not null and is a Double object that represents a double that has the same value as the double represented by this object. For this purpose, two double values are considered to be the same if and only if the method doubleToLongBits(double) returns the identical long value when applied to each.
Long answer: the JLS specifies a few differences between Double.equals and ==. For one difference specified in JLS 4.2.3 and JLS 15.21.1:
Positive zero and negative zero compare equal; thus the result of the expression 0.0==-0.0 is true and the result of 0.0>-0.0 is false. But other operations can distinguish positive and negative zero; for example, 1.0/0.0 has the value positive infinity, while the value of 1.0/-0.0 is negative infinity.
Another regards NaN:
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.
As you can see, it's possible for two double values to compare with == but actually correspond to different behavior when used in math and hash tables. Thus, when writing a generated equality method, Eclipse makes the assumption that two doubles are only equal if and only if all operations that can be done to them are identical, or (equivalently) if they were autoboxed and compared with their equals methods. This is particularly important if switching between double and Double—it would be particularly unexpected for equality properties to differ there.
Of course, you're free to drift from that assumption: Regardless of whether it's a good idea, you may assign special cases to any of the many possible NaN representations, in which case Double.doubleToRawLongBits() would be a better match for your equals and hashCode methods. By the same token, your use case might treat objects with +0.0 and -0.0 as equivalent and guarantee that NaN values are not possible, in which case a raw == comparison may work better for equals (but at which point emulating the same criteria for hashCode becomes difficult).
Because == and != follow IEEE-754 semantics for doubles, Double.NaN != Double.NaN and 0.0 == -0.0. These behaviors may not be what you want, so Double.doubleToLongBits() converts the 64 bits of double data to 64 bits of long data so that operations like bit shifts and XOR work.
Honestly, though, I would say that the use of doubleToLongBits is a bug here, since if you care about exact equality you should be using Double.doubleToRawLongBits() (which does not perform any translations on the double data at all) instead.
A quick glance at the online javadoc yields this:
Returns a representation of the specified floating-point value according to the IEEE 754 floating-point "double format" bit layout.
...
In all cases, the result is a long integer that, when given to the longBitsToDouble(long) method, will produce a floating-point value the same as the argument to doubleToLongBits (except all NaN values are collapsed to a single "canonical" NaN value).
So it's probably a way of standardizing the double representations of x and y, as NaN can have multiple double representations

Android - Comparison method violates its general contract

I've seen other questions about this exception but my compare method is so simple that I'm unable to figure out what's wrong with it and I can't reproduce it with any of the Android devices that I own.
I'm getting this exception from some users of my Android app, most of which seem to be on very new devices like GS3 or GS4, which I'm guessing run the Java 7 variant of merge sort.
Here's my compare method:
Collections.sort(collectionOfThings, new Comparator<Thing>()
{
public int compare(Thing lhs, Thing rhs)
{
//getDist() returns a Double with a capital D...perhaps that has something to do with it?
if(lhs.getDist() < rhs.getDist())
{
return -1;
}
if(lhs.getDist() == rhs.getDist())
{
return 0;
}
return 1;
};
});
Here's the exception:
Caused by: java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:743)
at java.util.TimSort.mergeAt(TimSort.java:479)
at java.util.TimSort.mergeCollapse(TimSort.java:404)
at java.util.TimSort.sort(TimSort.java:210)
at java.util.TimSort.sort(TimSort.java:169)
at java.util.Arrays.sort(Arrays.java:2038)
at java.util.Collections.sort(Collections.java:1891)
Seems to be limited to Android 4.0+. Any help is greatly appreciated.
No use in re inventing the wheel. I believe you should just return lhs.getDist().compareTo(rhs.getDist()); and let the provided implementation compareTo do the job .
Compares two Double objects numerically.
There are two ways in which comparisons performed by this method differ from those performed by the Java language numerical comparison operators (<, <=, ==, >=, >) when applied to primitive double values:
Double.NaN is considered by this method to be equal to itself and greater than all other double values (including Double.POSITIVE_INFINITY).
0.0d is considered by this method to be greater than -0.0d.
This ensures that the natural ordering of Double objects imposed by this method is consistent with equals.
I believe you get this Exception because your present implementation may not be apt to deal with Double.NaN and positive/negative zero values , and yet honor the general contract. Look at the OpenJDK Double#compare(double,double) source code :
public static int More ...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)
}
Also go through the documentation of Double#equals()
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.
Instead of comparing two Double objects, you should really be comparing their values (getDoubleValue()). Comparing two objects will not necessarily mean their values are equal.

Comparing doubles in Java gives odd results

I really can'get my head around why the following happens:
Double d = 0.0;
System.out.println(d == 0); // is true
System.out.println(d.equals(0)); // is false ?!
This however works as expected:
Double d = 0.0;
System.out.println(d == 0.0); // true
System.out.println(d.equals(0.0)); // true
I'm positive that this is related to autoboxing in some way, but I really don't know why 0 would be boxed differently when the == operator is used and when .equals is called.
Doesn't this implicitly violate the equals contract ?
* It is reflexive: for any non-null reference value
* x, x.equals(x) should return
* true.
EDIT:
Thanks for the fast answers. I figured that it is boxed differently, the real question is: why is it boxed differently ? I mean that this would be more intuitive if d == 0d than d.equals(0d) is intuitive and expected, however if d == 0 which looks like an Integer is true than 'intuitively' d.equals(0) should also be true.
just change it to
System.out.println(d.equals(0d)); // is false ?! now true
You were comparing double with Integer 0
Under the cover
System.out.println(d.equals(0)); // is false ?!
0 will be autoboxed to Integer and an instance of Integer will be passed to equals() method of Double class, where it will compare like
#Override
public boolean equals(Object object) {
return (object == this)
|| (object instanceof Double)
&& (doubleToLongBits(this.value) == doubleToLongBits(((Double) object).value));
}
which is going to return false of course.
Update
when you do comparison using == it compares values so there is no need to autobox , it directly operates on value. Where equals() accepts Object so if you try to invoke d1.equals(0) , 0 is not Object so it will perform autoboxing and it will pack it to Integer which is an Object.
Number objects only equal to numbers with the same value if they are of the same type. That is:
new Double(0).equals(new Integer(0));
new BigInteger("0").equals(new BigDecimal("0"));
and similar combinations are all false.
In your case, the literal 0 is boxed into an Integer object.
It's probably worth noting that you should compare floating point numbers like this:
|x - y| < ε, ε very small
d.equals(0) : 0 is an int. The Double.equals() code will return true only for Double objects.
When you perform
d == 0
this is upcast to
d == 0.0
however there are no upcasting rules for autoboxing and even if there were equals(Object) gives no hits that you want a Double instead of an Integer.

Floating point rounding (in java)

What is the best way of determining if a given float(or double) has no significant decimal places.
f(234.0) = true
f(34.45) = false
f(3.1322) = false
i.e. equivalent of
EQ(((int)number) * 1.0 , number)
where EQ is a given method to compare floating points and it is OK to assume that the float fits in an integer.
Math.rint(x) == x
Math.rint() returns a double, so it also works for large numbers where the long result of Math.round() overflows.
Note that this also gives true for positive and negative infinity. You can explicitly exclude them by Math.rint(x) == x && !Double.isInfinite(x).
Round the value to the nearest integer, and calculate the absolute difference to the actual value.
If that difference is less than a certain percentage of the actual value you are close "enough".
You could try something like this:
public static boolean f(double d) {
return d % 1 == 0;
}

What makes the following code print false?

public class Guess {
public static void main(String[] args){
<sometype> x = <somevalue>;
System.out.println(x == x);
}
}
i have to change sometype and somevalue so that it returns false? is it possible?
One:
float x = Float.NaN;
Two:
double x = 0.0/0.0;
Why?
As mentioned here already, NaN is never equal to another NaN - see http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html
So why this is not returning false?
Float x = Float.NaN;
The answer is that here, instead of a primitive assignment, there is a reference assignment. And there is a little auto boxing in the background. This is equal to:
Float x = new Float(Float.NaN);
Which is equal to:
Float x = new Float(0.0f / 0.0f);
Here x is a reference to a Float object, and the == operator tests reference equality, not value.
To see this returning false as well, the test should have been:
x.doubleValue()==x.doubleValue();
Which indeed returns false
Yes it is possible, you need to use:
// Edited for primitives :)
float x = Float.NaN;
// or
double x = Double.NaN;
This is because NaN is a special case that is not equal to itself.
From the JLS (4.2.3):
NaN is unordered, so the numerical comparison operators <, <=, >, and >= return false if either or both operands are NaN (§15.20.1). The equality operator == returns false if either operand is NaN, and the inequality operator != returns true if either operand is NaN (§15.21.1). In particular, x!=x is true if and only if x is NaN, and (x=y) will be false if x or y is NaN.
I can't think of any someType and someValue for which you could get x == x to come up false, sorry.
Update
Oh... yes, I think NAN is equal to nothing, even itself. So...
double and Double.NaN (or so).
This will print false:
!(x == x)
Other then that, it will only print false if you use NaN
float x = float.NaN;
Console.WriteLine(x == x);

Categories