Java double precision

I

info

I know the following behaviour is an old problem,
but still I don't understand why such a simple piece of code:


double val = 0;
for(int i=0;i<10;i++) {
val+=0.1;
System.out.println(val);
}

has the following (terrible) output:

0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999


???

Why, as a developer, I have to use a trick like this to solve the
problem:

java.text.DecimalFormat df = new
java.text.DecimalFormat("###.########");
double val = 0;
for(int i=0;i<10;i++) {
val+=0.1;
val = df.parse(df.format(val)).doubleValue();
System.out.println(val);
}


Thank you in advance
Vincenzo Caselli
(e-mail address removed)
http://www.censnet.it
 
M

Michael Borgwardt

I know the following behaviour is an old problem,
but still I don't understand why such a simple piece of code: []
has the following (terrible) output: []
0.7999999999999999
0.8999999999999999
0.9999999999999999


???

Because double and float are internally represented as *binary* fractions
according to the IEEE standard 754
and can therefore not represent decimal fractions exactly.
http://mindprod.com/jgloss/floatingpoint.html
http://www.math.byu.edu/~schow/work/IEEEFloatingPoint.htm
Why, as a developer, I have to use a trick like this to solve the
problem:

java.text.DecimalFormat df = new
java.text.DecimalFormat("###.########");
double val = 0;
for(int i=0;i<10;i++) {
val+=0.1;
val = df.parse(df.format(val)).doubleValue();
System.out.println(val);
}

*groan* You're 95% there and yet took the TOTALLY wrong turn at the last
intersection. You want to *format* numbers, so why are you using
DecimalFormat.parse()??? What do you think the format() method is for?

Furthermore, if you really need exact representation of decimal fractions
(usually the case only for financial applications), use java.math.BigDecimal.
 
P

Patricia Shanahan

I know the following behaviour is an old problem,
but still I don't understand why such a simple piece of code:


double val = 0;
for(int i=0;i<10;i++) {
val+=0.1;
System.out.println(val);
}

has the following (terrible) output:

0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999


???

Why, as a developer, I have to use a trick like this to solve the
problem:

java.text.DecimalFormat df = new
java.text.DecimalFormat("###.########");
double val = 0;
for(int i=0;i<10;i++) {
val+=0.1;
val = df.parse(df.format(val)).doubleValue();
System.out.println(val);
}


Thank you in advance
Vincenzo Caselli
(e-mail address removed)
http://www.censnet.it

There are two incompatible objectives for string conversion
of floating point data:

1. Produce a tidy result showing only meaningful digits.

2. Produce a result that uniquely identifies the floating
point number.

Language and library developers pick one for the default
conversion. In C, for example, printf aims for #1,
defaulting to 6 digit precision.

Java uses #2 as the default, producing enough digits to
ensure that the reverse conversion will recover the double.
The result of adding 0.1+0.1+0.1 really is different
from 0.3.

I don't fully understand the reason for your "trick". I
would have used the DecimalFormat when aiming for tidy
output, but would not have converted back or used the
result in continuing calculations. Doing so throws away
precision if the mathematical answer is not a short decimal
fraction. For example, try substituting 1/3.0 for 0.1 in
your test.

If you are only concerned with exact representation of short
decimal fractions, and don't need to deal with numbers like
1/3.0, consider using BigDecimal instead of double. Any
number that would be improved by your trick can be exactly
represented as a BigDecimal with scale=8.

Patricia
 
C

Chris Smith

I know the following behaviour is an old problem,
but still I don't understand why such a simple piece of code:

It's because you're thinking in decimal, but the computer thinks in
binary. 0.1 is a repeating decimal number in binary. To understand
this case, we could take an analogous algorithm in decimal; say, adding
1/3 instead of 1/10. In this example, we'll give the numbers ten
significant digits of precision, so:

0.3333333333
+ 0.3333333333
------------
= 0.6666666666
+ 0.3333333333
------------
= 0.9999999999

So the same thing happens with repeating decimal numbers in base 10 as
well. The cumulative error from adding 0.3333333333 instead of exactly
1/3 adds up. It's only counterintuitive because you're not expecting
0.1 to be a repeating decimal, and that's because you're not thinking in
base 2 like the computer is.
Why, as a developer, I have to use a trick like this to solve the
problem:

java.text.DecimalFormat df = new
java.text.DecimalFormat("###.########");
double val = 0;
for(int i=0;i<10;i++) {
val+=0.1;
val = df.parse(df.format(val)).doubleValue();
System.out.println(val);
}

No, you can write:

DecimalFormat df = new DecimalFormat("###.########");
double val = 0;
for (int i = 0; i < 10; i++)
{
val += 0.1;
System.out.println(df.format(val));
}

As Patricia said, you're assuming that the "correct" answer is achieved
by truncating the result in decimal that then parsing it back again.
Only in the very limited case of nice round numbers is that true. This
would be a very poor idea if you were working with any kind of measured
or calculated quantity. You shouldn't be assuming enough precision that
rounding error will matter anyway, so there's no need to make that round
trip.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
Joined
Jun 10, 2009
Messages
1
Reaction score
0
Hello, First of all, sorry for my ignorance. I have the following two questions:
1. Have the results showing in the program below anything to do with this discussion? I mean, is it the same problem?
2. Does my friend need to worry about this issue, if she is writing a program for a bank? :flute:

Can anyone explain what is happening below?


for(int i=0;i<20;i++)
System.out.println(i*1.26);

-----
0.0
1.26
2.52
3.7800000000000002
5.04
6.3
7.5600000000000005
8.82
10.08
11.34
12.6
13.86
15.120000000000001
16.38
17.64
18.9
20.16
21.42
22.68
23.94
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top