sagar123 has asked for the wisdom of the Perl Monks concerning the following question:

Hi all;

I am facing a silly error. here is a simple script but its not working beyond for (1..42) that is for (1..43) or more.

$a = 22.400; for (1..43) { $a = $a + 0.001; } print "$a\n";

it should give me 22.443, but I am getting 22.4430000000001. It works fine if I use for (1..42) or less than 42 then I get correct value e.g. for (1..42) I get 22.442 So is there limit to run loop? but I never faced such problem before as I run loop many times.

Replies are listed 'Best First'.
Re: limit of for loop!!
by moritz (Cardinal) on Jan 01, 2012 at 18:55 UTC

    The problem is that 0.001 cannot be exactly stored as a floating-point number, just as you cannot store 1/3 exactly as a decimal number. See What Every Computer Scientist Should Know About Floating-Point Arithmetic for details, or search for floating point here on perlmonks.

    A way around is to start $a as 22400, add 1 to it at each iteration, and remember to divide by 1000 in the end before using the result (or never divide by 1000, but use the result in a way that accounts for the additional factor)

    Note that Perl 6 solves the problem by storing 0.001 as a rational number by default.

    use v6; my $a = 22.400; for (1..43) { $a = $a + 0.001; } print "$a\n";

    produces 22.443 as output with Rakudo and Niecza.

Re: limit of for loop!!
by toolic (Bishop) on Jan 01, 2012 at 19:00 UTC
Re: limit of for loop!!
by GrandFather (Saint) on Jan 01, 2012 at 21:41 UTC

    What are you actually trying to do? What precision (how many digits) do you really need? Moritz provided a good solution (work with integer values then scale as the last step) - what is wrong with that solution?

    As an exercise try writing 1/3 as a decimal fraction in full. Let me get you started:

    0.33333333333333333333333333333

    Have you figured out that you can't exactly represent 1/3 as a finite decimal fraction? In the same way you can't exactly represent 1/10 (base 10) as a finite binary fraction. This seems like a problem, but for almost all real applications for arithmetic it is not an issue. You seldom need more than a few digits of precision for an answer (although for some calculations you may need more precision for intermediate answers).

    So the key questions are: what are you trying to do and how much precision do you really need? There are many possible ways to solve your problem, but a solution depends very much on what you are trying to achieve.

    True laziness is hard work
      HI,

      I need some value upto 3 decimal places and want to use that in calculations. But actually the value becomes 22.430000001 like that. in summary I want that value remains 22.43 just not "nice value" to be 'printed'. yes 22.43 and 22.43000001 are almost same. but I need to extract some data from million number of values (which are three decimal place) from text file. So I need exact decimal place or it will be ignored to be extracted.

      As suggested I will divide 22430 by 1000, that will be a good option

Re: limit of for loop!!
by Anonymous Monk on Jan 01, 2012 at 19:00 UTC

    And if you just want to display it nice, use printf "%.3f\n", $a;. This is covered in perlfaq4

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: limit of for loop!!
by flexvault (Monsignor) on Jan 02, 2012 at 17:11 UTC

    You could use 'sprintf' as part of the loop. Adds some time, but maintains your 3 digits of precision.

    perl -e '$n=22.4; for(1..99) { $n = sprintf("%.3f", $n+0.001 ); } prin +t "Result: $n\n";'

    Hint: Try to think of your numbers as '$n' or '$s' and not '$a'. You'll understand in the future.

    Good Luck

    "Well done is better than well said." - Benjamin Franklin