compare Java Double.Max_VALUE with large double numbers returns true

1k Views Asked by At

Why do these simple double comparisons return true?

System.out.println(Double.MAX_VALUE == (Double.MAX_VALUE - 99 * Math.pow(10, 290)));
System.out.println(new Double(Double.MAX_VALUE).equals(new Double(Double.MAX_VALUE - 99 * Math.pow(10, 290))));

I know it's probably a IEEE 754 precision problem, but I can't figure out what the exact problem is here.

3

There are 3 best solutions below

0
On BEST ANSWER

Very large floating point numbers are very imprecise. What you are seeing is rounding error.

We could demonstrate floating point in base-10 (scientific notation), say with 1 digit for the exponent and 4 digits for the base:

1234*10^1  == 1234
1234*10^-1 == 123.4
1234*10^9  == 1,234,000,000,000
1235*10^9  == 1,235,000,000,000

It follows that:

1234*10^9 - 1234*10^1 == 1234*10^9

You can see that as the numbers get larger, we lose precision. Lots of it.

For kicks, you can test it:

double d = 10;
while(Double.MAX_VALUE - d == Double.MAX_VALUE)
    d *= 10;
System.out.println(d);

We can determine that the gap between Double.MAX_VALUE and the next smallest value (called an ULP) is somewhere around 10^292, which is a very large gap.

We can determine its exact value with the help of Math#ulp:

long       lng = Double.doubleToRawLongBits(Double.MAX_VALUE);
double nextMax = Double.longBitsToDouble(lng - 1);
System.out.println(Math.ulp(nextMax));

Which is about 1.99584*10^292, or 2^971.

1
On

I think the problem is in this line

                                                        |  
                                                        v
new Double(Double.MAX_VALUE).equals(new Double(Double.MAX_VALUE - 99999999999999999999999D))

DOUBLE MAX_VALUE = Double.MAX_VALUE - 99999999999999999999999D

AND you're comparing it with

new Double(Double.MAX_VALUE - 99999999999999999999999D)

which I think is just the same so it will always return true.

1
On

The larger floating-point numbers get, the larger the gap between one floating-point number and the next one down or up. This is because an error of 0.5 is pretty important in a measurement of value 1, but utterly insignificant in a measurement of value 1000000000000.

Double.MAX_VALUE is huge, and the numbers you're subtracting from it are less huge. In fact, the difference is big enough that the numbers you're subtracting are less huge than the gap between Double.MAX_VALUE and the next double down, so Double.MAX_VALUE is the closest representable number to the exact result. Thus, you just get Double.MAX_VALUE back.