-3

I was generating some data for a little test project and used my old stand-by, perl. I found when I added .1 to 0 through 10, where I expect 6.0, the string output become "5.99999999999999". When I start at 5.9, the same fraction is missing when I get to 8.8: 8.79999999999998.

I tested this with Perl v5.12.3 that ships with Mac OS 10.7.5 as well as the version with the macports (v5.12.4). I'm on a 2.2 ghz i7 15" macbook pro.

for (my $i=0; $i<10; $i+=.1) {
   print $i."\n";
}

Strangest thing I've seen since the old Pentium bug, and I can't seem to find any discussion on this. Am I missing something or is something wonky?

  • If you want it to be more precise, use "use bignum;" or round it in some way. You are using floats and [there are quite a few questions about them](http://stackoverflow.com/questions/2038647/why-does-ghci-say-that-1-1-1-1-1-1-3-3-is-true). – bliof Mar 24 '13 at 19:23
  • 1
    see http://perldoc.perl.org/perlfaq4.html#Why-am-I-getting-long-decimals-%28eg%2c-19.9499999999999%29-instead-of-the-numbers-I-should-be-getting-%28eg%2c-19.95%29%3f and the link given there. – Ekkehard.Horner Mar 24 '13 at 19:24
  • 1
    It's not a bug. It is by design and it's the same in all languages. Frankly, I find it especially amusing that someone with maybe two days of programming experience thinks that an established compiler has an addition bug. https://news.ycombinator.com/item?id=142274 – Sinan Ünür Mar 24 '13 at 23:33

1 Answers1

10

The decimal fraction 0.1 can't be represented in Base 2, much like the fraction ⅓ can't be represented in base 10 (0.33333...). If you would sum the numbers from 0 to 3 with steps of ⅓, with a precision of, say, two digits, we would get 2.97 as our answer. This is analogous to the problem of representing fractions as floating point numbers.

No matter how large your float is (how many decimal digits you use), these issues won't go away. To solve these problems, either use appropriate integers internally, and convert them once you have to communicate with other code/the outside world like

for my $i (0 .. 100) {
  say $i/10;
}

or use bignum. This replaces perl's numbers with overloaded objects which can represent numbers of arbitrary accuracy:

use bignum;
for (my $i = 0; $ i<= 10; $i += 0.1) {
  say $i;
}
amon
  • 57,091
  • 2
  • 89
  • 149
  • Alternative to bignum, fixed precision decimals using `Math::Decimal` – Neil Slater Mar 24 '13 at 22:10
  • 1
    @NeilSlater Not really. [`Math::Decimal`](https://metacpan.org/module/Math::Decimal) claims to operate on Perl strings, which should be considered as “proof-of-concept”. Also, the interface is ugly. In contrast, [`bignum`](https://metacpan.org/module/bignum) will use [`Math::BigFloat`](https://metacpan.org/module/Math::BigFloat) or something, which is object oriented, operates transparently as it overloads arithmetic operators, and can use various backends, including the GMP library (← highly optimzed C library). – amon Mar 24 '13 at 23:27
  • 1
    Cool, you're using my explanation :) "X is periodic in binary just like 1/3 is in decimal." I'm quite fond of it :) – ikegami Mar 24 '13 at 23:39