Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

limit of for loop!!

by sagar123 (Novice)
on Jan 01, 2012 at 18:41 UTC ( #945800=perlquestion: print w/replies, xml ) Need Help??
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 (Sage) 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:


    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

      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

      thanks all for quick reply. but my problem is not solved

      >> And if you just want to display it nice, use printf >>"%.3f\n", $a;

      So this mean actually number is 22.430000001 which will be used for actual calculations but printf just prints 22.43 just for "nice display". So it will give wrong calculation results because number used will be 22.4300001. should I install PERL6, no solution in PERL5.*?

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

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://945800]
Approved by moritz
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (5)
As of 2018-08-19 20:50 GMT
Find Nodes?
    Voting Booth?
    Asked to put a square peg in a round hole, I would:

    Results (187 votes). Check out past polls.