Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Strange loop!! why???

Status
Not open for further replies.

grimbys

Programmer
Dec 19, 2002
34
ES
Hi! we have a problem with decimal numbers.
When we have next loops, we don't get the result expected
for ($i = 0.001; $i <= 0.01 ;$i += 0.001)
{
print $i.&quot; &quot;;
}
print &quot;\n&quot;;
# OUT: 0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009 WITHOUT 0.01!!!
for ($i = 0.01; $i <= 0.1 ; $i += 0.01)
{
print $i.&quot; &quot;;
}
print &quot;\n&quot;;
# OUT: 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 WITH 0.1 ¡OK!
for ($i = 0.01; $i < 0.1 ; $i += 0.01)
{
print $i.&quot; &quot;;
}
# OUT: 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 WITH 0.1!!!!! (look at ¡¡¡¡<!!!)

Where is the problem???? We don't know
Thanks!
 
Weird, I tried the first for loop and got the same result but if I change the for statement to

for ($i = 0.001; $i < 0.011 ;$i += 0.001)

then 0.01 does appear at the end of the output.

I wonder if somehow 0.009 + 0.001 somehow ends up 'becoming' 0.010000001 (or something like that) which causes the for loop to terminate.
 
We think that this success because of the internal representation of numbers of perl. I read about the imposibility of save 0'9 on a variable becouse its representation is 0.111000111000...

Are there any way (casting numbers how C, for example) for this loop can run?
Sorry for my poor english
 
This problem isn't specific to Perl, all computer languages that represent floating point numbers in binary are plagued by it. As a programmer you must be aware of it.

One work-around is to change the test statement as varocho suggested so that you are testing strictly less-than (and not equal to) an upperbound.

Another method would be to set up the list of loop values explicitly.
For example
Code:
for $i ( map { $_ / 1000 } 1..10 )
{
    print $i.&quot; &quot;;
}
jaa
 
Testing says it ends up being 0.01000000000000001, but printing $i just after the loop still just prints 0.01

Lesson: always increment with integers (generally faster, too). ----------------------------------------------------------------------------------
...but I'm just a C man trying to see the light
 
Yeah, integers sounds like the way to go. Try something like this...

Code:
for ($i = 1; $i <= 10; $i++)
{
    print $i/1000 . &quot; &quot;;
}

I haven't tried it, but I think it should accomplish what you need.
Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
 
Thanks you. When you are working with variables is hard know if you have to divide by 1000, 10000, 100000 or other quantity.

you have to do this:
$divisor = find_divisor ($step);
$start = find_start ($start);
$finish = find_finish ($finish);
for $i ( map { $_ / $divisor } $start..$finish )
{ ... }

and if you have a code with 3000 line-codes and you have which for loops have this problem, I don't know it's bore.
Apart, what about third loop for?
Remember (it is with < ) :
for ($i = 0.01; $i < 0.1 ; $i += 0.01)
{
print $i.&quot; &quot;;
}
# OUT: 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 WITH 0.1!!!!!


Sorry for my bad english

 
I'm not sure exactly what you were saying in the last post or exactly what those functions accomplished, but try something like this:
Code:
my $divisor = find_divisor ($step);
$start = find_start ($start) / $divisor;
$finish = find_finish ($finish) / $divisor;

my $multiplier = 1 / $start;
$start = $start * $multiplier;
$finish = $finish * $multiplier;

for (my $i = $start; $i < $finish; $i++)
{
    print $i/$multiplier . &quot; &quot;;
}
Sincerely,

Tom Anderson
CEO, Order amid Chaos, Inc.
 
Thanks, don't worry. Now I know that this for loop too fails in C++. The thing is only use integer on loops.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top