tags:

views:

351

answers:

5

In my program I have one array with 25 double values 0.04 When I try to sum these values in a loop I get following results:

0.0 + 0.04 = 0.04
0.04 + 0.04 = 0.08
0.08 + 0.04 = 0.12
0.12 + 0.04 = 0.16
0.16 + 0.04 = 0.2
0.2 + 0.04 = 0.24000000000000002
0.24000000000000002 + 0.04 = 0.28
0.28 + 0.04 = 0.32
0.32 + 0.04 = 0.36
0.36 + 0.04 = 0.39999999999999997
0.39999999999999997 + 0.04 = 0.43999999999999995
0.43999999999999995 + 0.04 = 0.4799999999999999
0.4799999999999999 + 0.04 = 0.5199999999999999
0.5199999999999999 + 0.04 = 0.5599999999999999
0.5599999999999999 + 0.04 = 0.6
0.6 + 0.04 = 0.64
0.64 + 0.04 = 0.68
0.68 + 0.04 = 0.7200000000000001
0.7200000000000001 + 0.04 = 0.7600000000000001
0.7600000000000001 + 0.04 = 0.8000000000000002
0.8000000000000002 + 0.04 = 0.8400000000000002
0.8400000000000002 + 0.04 = 0.8800000000000002
0.8800000000000002 + 0.04 = 0.9200000000000003
0.9200000000000003 + 0.04 = 0.9600000000000003

Why on earth could that happen?!

+18  A: 

The most common storage for floating-point values in programming languages - IEEE singles and doubles - does not have exact representations for most decimal fractions.

The reason is that they store values in binary floating-point format, rather than decimal floating-point format. The only fractional values which can be represented exactly are those which are sums of negative powers of two. Numbers like:

  • 0.5 (2^-1)
  • 0.125 (2^-3)
  • 0.625 (2^-1 + 2^-3)

Etc.

What you are seeing is the fact that representations of numbers like 0.96 are not exactly representable, because they are not expressible as a sum of negative powers of two. Thus, when printed out with full precision as a decimal fraction, they won't match the original value.

Barry Kelly
"Rather than decimal" kinda gives the wrong idea. If it used decimal, it'd be limited to fractional values which are sums of negative powers of ten, so that wouldn't really solve much. Someone reading your answer may get the idea that "the problem would go away if only they used base10"
jalf
@jalf, true but at least a decimal floating point representation would surprise fewer people used to simple pocket accounting. Adding up a pile of 20 nickels and not getting exactly a buck is surprising to a lot of people. A decimal notation would get that case right, and trade that for funny issues with numbers that should be familiar from grade school arithmetic lessons.
RBerteig
+11  A: 

See also "What Every Computer Scientist Should Know About Floating Point"

John the Statistician
That document is very dense for someone new to floating-point representation in most programming languages. I wouldn't recommend it outside people with at least a year, if not three, in CS education.
Barry Kelly
I concur. On the other hand, it's nice for self-taught practitioners and the overachievers to know where it is, in case they are facing numeric issues.
John the Statistician
It's still something people should know, even if it's too dense for them to read though. ;)
jalf
A: 

Duplicate of this question

Paul
+2  A: 

Other answers mentioned why, but not how to avoid it.

There are several solutions:

  • Scaling: if all your numbers are multiples of 0.01 (for instance), multiply everything by 100 and use integer arithmetic (which is exact).
  • Numeric type: if your language has a numeric type (like a numeric type in SQL), you can use it.
  • Arbitrary precision rationals: use a bignum library like GMP, which allows you to represent these numbers as the ratio of two integers.
  • Decimal floating point: if you have a decimal floating point like the one in IEEE-754r, you can use it.
CesarB
+1  A: 

You may wish to check out the java BigDecimal class as an alternative to floats and doubles.

Ewen Cartwright