1

While answering this question, I got these confusing results:

double d = 0.49999999999999990d; //output 0.4999999999999999 as expected
d = 0.49999999999999991d; //output 0.4999999999999999
d = 0.49999999999999992d; //output 0.49999999999999994
d = 0.49999999999999993d; //output 0.49999999999999994
d = 0.49999999999999994d; //output 0.49999999999999994 as expected
d = 0.49999999999999995d; //output 0.49999999999999994
d = 0.49999999999999996d; //output 0.49999999999999994
d = 0.49999999999999997d; //output 0.49999999999999994
d = 0.49999999999999998d; //output 0.5

Why is this behaviour showing?

NOTE: I got these outputs just by printing d; I mean I used:

System.out.println(d);
Peter Mortensen
31.3k22 gold badges110 silver badges134 bronze badges
asked Mar 29, 2012 at 11:33
1

3 Answers 3

2

Floating point types cannot exactly represent all Real numbers. In fact, a double is a 64-bit floating point type, and can therefore only represent 264 different values ... and there are an infinite number of Real numbers. (Indeed, there are an infinite number of Real numbers between 0.49999999999999990d and 0.49999999999999999d.)

You have picked some numbers that fall between consecutive values in the set-of-all double values. In other words, you've exceeded the limits of precision for the double type.

What can you do about it? Well one way to get more precision is to use the BigDecimal class, which can (in theory) give you in the region of 2 BILLION decimal digits of precision. The downside is that your code will be more complicated ... and significantly slower, depending on how much precision you use.

The other approach is to recognize that you probably don't need that much precision.

answered Mar 29, 2012 at 11:40
Sign up to request clarification or add additional context in comments.

Comments

1

System.out.println(d) will go through Double.toString which is a fairly complex method (as seen in its documentation) an will not always behave as you'd expect. It basically gives the shortest string which uniquely determines d.

Perhaps the output of this program clarifies this:

double[] tests = {
 0.49999999999999990d, //output 0.4999999999999999 as expected
 0.49999999999999991d, //output 0.4999999999999999
 0.49999999999999992d, //output 0.49999999999999994
 0.49999999999999993d, //output 0.49999999999999994
 0.49999999999999994d, //output 0.49999999999999994 as expected
 0.49999999999999995d, //output 0.49999999999999994
 0.49999999999999996d, //output 0.49999999999999994
 0.49999999999999997d, //output 0.49999999999999994
 0.49999999999999998d, //output 0.5
 };
String[] literals = {
 "0.49999999999999990d",
 "0.49999999999999991d",
 "0.49999999999999992d",
 "0.49999999999999993d",
 "0.49999999999999994d",
 "0.49999999999999995d",
 "0.49999999999999996d",
 "0.49999999999999997d",
 "0.49999999999999998d",
 };
String f = "%-25s%-65s%-25s%n";
System.out.printf(f, "Literal", "Actually represents", "Printed as");
for (int i = 0; i < tests.length; i++)
 System.out.printf(f, literals[i],
 new BigDecimal(tests[i]).toString(), 
 Double.valueOf(tests[i]));

Output:

Literal Actually represents Printed as 
0.49999999999999990d 0.49999999999999988897769753748434595763683319091796875 0.4999999999999999 
0.49999999999999991d 0.49999999999999988897769753748434595763683319091796875 0.4999999999999999 
0.49999999999999992d 0.499999999999999944488848768742172978818416595458984375 0.49999999999999994 
0.49999999999999993d 0.499999999999999944488848768742172978818416595458984375 0.49999999999999994 
0.49999999999999994d 0.499999999999999944488848768742172978818416595458984375 0.49999999999999994 
0.49999999999999995d 0.499999999999999944488848768742172978818416595458984375 0.49999999999999994 
0.49999999999999996d 0.499999999999999944488848768742172978818416595458984375 0.49999999999999994 
0.49999999999999997d 0.499999999999999944488848768742172978818416595458984375 0.49999999999999994 
0.49999999999999998d 0.5 0.5 

As can be seen, the literal is sometimes far from the value it actually represents, which means that Double.toString prints something that may look surprising.

answered Mar 29, 2012 at 11:43

Comments

0

Only certain numbers can be represented exactly as doubles. There are three such numbers in the range under consideration:

  • 0.49999999999999990
  • 0.49999999999999994
  • 0.5

Everything between these numbers gets rounded to the nearest of the three.

If you look at how these doubles are represented in hex, you'll see that the three numbers have consecutive mantissas (the part before the p):

In [20]: float.hex(0.49999999999999990)
Out[20]: '0x1.ffffffffffffep-2'
In [21]: float.hex(0.49999999999999994)
Out[21]: '0x1.fffffffffffffp-2'
In [22]: float.hex(0.5)
Out[22]: '0x1.0000000000000p-1'

Representing numbers such as 0.49999999999999992 exactly would require more bits of mantissa than double can offer.

answered Mar 29, 2012 at 11:39

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.