Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Problem with a double

Reply
Thread Tools

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?

Thank you in advance,
Jorge
 
Reply With Quote
 
 
 
 
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?
>
> Thank you in advance,
> 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/>
 
Reply With Quote
 
 
 
 
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?
>
> Thank you in advance,
> 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
 
Reply With Quote
 
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.

Try read an introduction like:
http://www.lahey.com/float.htm

Arne
 
Reply With Quote
 
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

See also

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

 
Reply With Quote
 
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.
 
Reply With Quote
 
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
 
Reply With Quote
 
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
 
Reply With Quote
 
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?
>>
>> Thank you in advance,
>> 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
 
Reply With Quote
 
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?
>>>
>>> Thank you in advance,
>>> 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.


I've thought about this some more, and the answer should be "0.4". The
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

 
Reply With Quote
 
 
 
Reply

Thread Tools

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 Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
from List <double> to double[] Web learner ASP .Net 3 04-26-2006 05:26 PM
Should I be concerned about buying DVD18s (Double-sided, double-layered) The Man With No Name DVD Video 3 02-04-2006 01:45 AM
cannot convert parameter from 'double (double)' to 'double (__cdecl *)(double)' error Sydex C++ 12 02-17-2005 06:30 PM
Double double display display problem problem Tom Accuosti Firefox 3 09-27-2004 10:02 PM
structs of double as double[] sb C++ 4 02-19-2004 07:39 PM



Advertisments