Velocity Reviews > Java > Problem with a double

# Problem with a double

jorgeba
Guest
Posts: n/a

 12-09-2007
Hi,

I have an amazing problem with a double in Java.

for (double i = 0; i<1; i=i+0.2)
System.out.println (i);

Output:
0
0.2
0.399999999 !!!!!!!!!!!
0.6
0.8

It is amazing! Does someone understand it?

Jorge

Daniel Pitts
Guest
Posts: n/a

 12-09-2007
jorgeba wrote:
> Hi,
>
> I have an amazing problem with a double in Java.
>
> for (double i = 0; i<1; i=i+0.2)
> System.out.println (i);
>
> Output:
> 0
> 0.2
> 0.399999999 !!!!!!!!!!!
> 0.6
> 0.8
>
> It is amazing! Does someone understand it?
>
> Jorge

This is not specific to Java. This has to do with the way doubles are
stored in memory, and the way they are rounded before display.

--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

Joshua Cranmer
Guest
Posts: n/a

 12-09-2007
jorgeba wrote:
> Hi,
>
> I have an amazing problem with a double in Java.
>
> for (double i = 0; i<1; i=i+0.2)
> System.out.println (i);
>
> Output:
> 0
> 0.2
> 0.399999999 !!!!!!!!!!!
> 0.6
> 0.8
>
> It is amazing! Does someone understand it?
>
> Jorge

The short answer: A computer cannot precisely represent a decimal
number. Therefore, it is forced to round off all of decimals. The
0.399999999 here is an example of where it was forced to round off.

The long answer: Java's default Double.toString(double) (how it converts
a double to a string) does some voodoo magic that prints out "0.2" when
the internal representation is equal to what 0.2 would be. Since the
decimal number has an infinite binary expansion, the computer rounds off
the number. When it adds 0.2 to that number, the round off (it appears
to be down here) is accumulated twice and the number is off, I believe,
by one ulp: the last binary digit in the representation is incorrect
(guesswork there).

Whenever one works with floating-point numbers on computers, one should
always have tolerance guards. A double has 52 bits of significance --
about 15 to 16 correct significant figures, although the last few may
have some accumulated round-off error. In a strictfp method/class, all
arithmetic is done in those 52 bits; otherwise, it may use the
computer's extended precision if available (Intel uses an 80-bit fp
number, which should give another dozen or so significant bits).

To limit the printout of these numbers, one can use:

System.out.printf("%.5d\n",i); // Java 5+

which prints the decimal digit to 5 decimal places.

--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth

Arne Vajhøj
Guest
Posts: n/a

 12-09-2007
jorgeba wrote:
> I have an amazing problem with a double in Java.
>
> for (double i = 0; i<1; i=i+0.2)
> System.out.println (i);
>
> Output:
> 0
> 0.2
> 0.399999999 !!!!!!!!!!!
> 0.6
> 0.8
>
> It is amazing! Does someone understand it?

That is how floating point works.

Floating point is intended for measurements with a bit
of inaccuracy.

You may have 0.4 km from your home to your children's school.

But it is not really wrong to say that there is 0.399999999 km.

On the other hand if you are doing accounting, then your auditor
prefer all calculations to be exact.

http://www.lahey.com/float.htm

Arne

Stefan Ram
Guest
Posts: n/a

 12-09-2007
jorgeba <(E-Mail Removed)> writes:
>It is amazing! Does someone understand it?

Finite Sums of Dual fractions, as used by »double«, can not
represent all decimal fractions precisely. The output
sometimes is beautified, so that one can not always see this.
But one can see it in:

public class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( new java.math.BigDecimal( 0.1 ));
java.lang.System.out.println( new java.math.BigDecimal( "0.1" )); }}

0.100000000000000005551115123125782702118158340454 1015625
0.1

http://docs.sun.com/source/806-3568/ncg_goldberg.html

Mark Thornton
Guest
Posts: n/a

 12-09-2007
Joshua Cranmer wrote:
> A double has 52 bits of significance --

Normalised doubles have 53 bit mantissas. The first bit is always one so
they don't bother to store it.

Patricia Shanahan
Guest
Posts: n/a

 12-09-2007
jorgeba wrote:
> Hi,
>
> I have an amazing problem with a double in Java.
>
> for (double i = 0; i<1; i=i+0.2)
> System.out.println (i);
>
> Output:
> 0
> 0.2
> 0.399999999 !!!!!!!!!!!
> 0.6
> 0.8
>
> It is amazing! Does someone understand it?

It is indeed amazing. When I run a program containing your code:

public class DoubleRounding {
public static void main(String[] args) {
for (double i = 0; i<1; i=i+0.2)
System.out.println (i);
}
}

I get:

0.0
0.2
0.4
0.6000000000000001
0.8

which has only the degree of rounding error I would expect from double.

0.399999999, as the result of two additions of 0.2, would imply much
bigger rounding errors than you should get with double.

Are you sure the output came from exactly the code you posted?

Patricia

Michael Jung
Guest
Posts: n/a

 12-09-2007
jorgeba <(E-Mail Removed)> writes:
> I have an amazing problem with a double in Java.
>
> for (double i = 0; i<1; i=i+0.2)
> System.out.println (i);
>
> Output:
> 0
> 0.2
> 0.399999999 !!!!!!!!!!!
> 0.6
> 0.8
>
> It is amazing! Does someone understand it?

You have to realize that 0.2 (and most of its multiples) are not
machine (JVM) numbers in that there are represented as is. In fact,
you can construct examples like .2 + .2 != .4 in Java due to this
(this concrete example might not work, but something along the lines
can be constructed).

Printing such numbers is therefore not as trivial as it seems. See
the javadoc description of Double.toString to see how it is solved.
By carefully calculating the steps mentioned, you will recover your
output. That doesn't make it intuitive, though

Basically, .399999999 represents .2+.2 (whatever they represent in
java code...) when printed, while .4 represents another number close
by when printed.

Michael

Patricia Shanahan
Guest
Posts: n/a

 12-09-2007
Joshua Cranmer wrote:
> jorgeba wrote:
>> Hi,
>>
>> I have an amazing problem with a double in Java.
>>
>> for (double i = 0; i<1; i=i+0.2)
>> System.out.println (i);
>>
>> Output:
>> 0
>> 0.2
>> 0.399999999 !!!!!!!!!!!
>> 0.6
>> 0.8
>>
>> It is amazing! Does someone understand it?
>>
>> Jorge

>
> The short answer: A computer cannot precisely represent a decimal
> number. Therefore, it is forced to round off all of decimals. The
> 0.399999999 here is an example of where it was forced to round off.
>
> The long answer: Java's default Double.toString(double) (how it converts
> a double to a string) does some voodoo magic that prints out "0.2" when
> the internal representation is equal to what 0.2 would be. Since the
> decimal number has an infinite binary expansion, the computer rounds off
> the number. When it adds 0.2 to that number, the round off (it appears
> to be down here) is accumulated twice and the number is off, I believe,
> by one ulp: the last binary digit in the representation is incorrect
> (guesswork there).

I still don't see how to get 0.399999999 from adding 0 + 0.2 + 0.2.

The double representation of 0.2 has at most half a unit least place
(ulp) of rounding error. Adding 0 to a number does not change it, so
that cannot increase the rounding error. Similarly, adding a number to
itself doubles it, which involves only a change in the exponent, not the
mantissa.

Given all that, I would expect at most the smallest possible rounding
error on conversion of the 0 + 0.2 + 0.2 result back to the shortest
decimal that rounds to its internal representation. With 53 bits
effective mantissa, counting the unrepresented bit, and a number whose
absolute magnitude is less than one, the rounding error should be less
than 2**(-53) or about 1e-16. A rounding error in the tenth decimal
place is over a million times too large.

Patricia

Patricia Shanahan
Guest
Posts: n/a

 12-09-2007
Patricia Shanahan wrote:
> Joshua Cranmer wrote:
>> jorgeba wrote:
>>> Hi,
>>>
>>> I have an amazing problem with a double in Java.
>>>
>>> for (double i = 0; i<1; i=i+0.2)
>>> System.out.println (i);
>>>
>>> Output:
>>> 0
>>> 0.2
>>> 0.399999999 !!!!!!!!!!!
>>> 0.6
>>> 0.8
>>>
>>> It is amazing! Does someone understand it?
>>>
>>> Jorge

>>
>> The short answer: A computer cannot precisely represent a decimal
>> number. Therefore, it is forced to round off all of decimals. The
>> 0.399999999 here is an example of where it was forced to round off.
>>
>> The long answer: Java's default Double.toString(double) (how it
>> converts a double to a string) does some voodoo magic that prints out
>> "0.2" when the internal representation is equal to what 0.2 would be.
>> Since the decimal number has an infinite binary expansion, the
>> computer rounds off the number. When it adds 0.2 to that number, the
>> round off (it appears to be down here) is accumulated twice and the
>> number is off, I believe, by one ulp: the last binary digit in the
>> representation is incorrect (guesswork there).

>
> I still don't see how to get 0.399999999 from adding 0 + 0.2 + 0.2.
>
> The double representation of 0.2 has at most half a unit least place
> (ulp) of rounding error. Adding 0 to a number does not change it, so
> that cannot increase the rounding error. Similarly, adding a number to
> itself doubles it, which involves only a change in the exponent, not the
> mantissa.
>
> Given all that, I would expect at most the smallest possible rounding
> error on conversion of the 0 + 0.2 + 0.2 result back to the shortest
> decimal that rounds to its internal representation. With 53 bits
> effective mantissa, counting the unrepresented bit, and a number whose
> absolute magnitude is less than one, the rounding error should be less
> than 2**(-53) or about 1e-16. A rounding error in the tenth decimal
> place is over a million times too large.

nearest double to 0.4 has to have the same mantissa as 0.2, but with
exponent one greater, the same as the result of 0 + 0.2 + 0.2. No other
value that rounds to that exponent and mantissa has a shorter decimal
representation than 0.4, so "0.4" is the correct answer.

Patricia

 Posting Rules You may not post new threads You may not post replies You may not post attachments You may not edit your posts BB code is On Smilies are On [IMG] code is On HTML code is OffTrackbacks are On Pingbacks are On Refbacks are Off Forum Rules

 Similar Threads Thread Thread Starter Forum Replies Last Post Web learner ASP .Net 3 04-26-2006 05:26 PM The Man With No Name DVD Video 3 02-04-2006 01:45 AM Sydex C++ 12 02-17-2005 06:30 PM Tom Accuosti Firefox 3 09-27-2004 10:02 PM sb C++ 4 02-19-2004 07:39 PM