for; while loop interations

  • Thread starter Jayaprakash Rudraraju
  • Start date
J

Jayaprakash Rudraraju

Hi,

The following two snippets of code are iterating the while loop same
number of times. I am not able to comprehend the reason. Thanks in advance
for your explanations.

$intv = 1.1;
while ($intv > 0.4) {
print "$intv\n";
$intv -= 0.1
}

$intv = 1.1;
while ($intv >= 0.4) {
print "$intv\n";
$intv -= 0.1
}

Prakash
 
J

John W. Krahn

Jayaprakash said:
Hi,

The following two snippets of code are iterating the while loop same
number of times. I am not able to comprehend the reason. Thanks in advance
for your explanations.

$intv = 1.1;
while ($intv > 0.4) {
print "$intv\n";
$intv -= 0.1
}

$intv = 1.1;
while ($intv >= 0.4) {
print "$intv\n";
$intv -= 0.1
}

Try changing the statement:

print "$intv\n";

To:

printf "%.20f\n", $intv;

And see what happens.

perldoc -q numbers

Found in /usr/lib/perl5/5.6.0/pod/perlfaq4.pod
Why am I getting long decimals (eg, 19.9499999999999)
instead of the numbers I should be getting (eg, 19.95)?



John
 
E

Eric Bohlman

Hi,

The following two snippets of code are iterating the while loop same
number of times. I am not able to comprehend the reason. Thanks in
advance for your explanations.

$intv = 1.1;
while ($intv > 0.4) {
print "$intv\n";
$intv -= 0.1
}

$intv = 1.1;
while ($intv >= 0.4) {
print "$intv\n";
$intv -= 0.1
}

Never use fractional floating-point values as loop counts, or in any other
case where an exact comparison is required. This is actually a basic
principle of computing, independent of what programming language you're
using. Your problem here is that 0.1 doesn't have an exact representation
as a binary fraction, just as 1/3 doesn't have an exact representation as a
(finite length) decimal fraction.

The basic rule here is that floating-point numbers are not real numbers in
the mathematical sense and cannot be expected to behave like them (for
example, floating-point addition is not always associative). There's a
whole branch of mathematics, numerical analysis, that's devoted to finding
ways to minimize the effects of this unpleasant truth.
 
L

laura fairhead

Hi,

The following two snippets of code are iterating the while loop same
number of times. I am not able to comprehend the reason. Thanks in advance
for your explanations.

$intv = 1.1;
while ($intv > 0.4) {
print "$intv\n";
$intv -= 0.1
}

$intv = 1.1;
while ($intv >= 0.4) {
print "$intv\n";
$intv -= 0.1
}

Hi,

I think you'll see what is going on easily if you try to
work out what 1/10 is in binary.

Floating point is not a precise way of dealing with values.
Whatever the number of bits used to store the FP values it
is a fixed number and so you are mapping infinite set of rational
numbers (a/b ) into a finite space and the result is that there
are "holes" (some, actually infinitely many, rationals get lost).

This ends up giving you a type of arithmetic that has some very
strange properties; rather like the moire patterns that appear
if you draw a lot of lines on a computer screen because those
lines aren't really straight they're a sequence of dots approximating
where the line would be if you could draw it. That's what you're
witnessing here, if you want 100% accuracy you have to use integer
methods eg;

(no code tested)

(i) integer scaling
~~~~~~~~~~~~~~~~~~~

$intv = 11;
while ($intv > 4) {
print $intv/10."\n"; # print approximation of intv/10
# for exact display use string splicing
$intv -= 1;
}

$intv = 11;
while ($intv >= 4) {
print $intv/10."\n"; # print approximation of intv/10
# for exact display use string splicing
$intv -= 1;
}

(ii) integer/modulus(=fixed=10)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

$intv = 1; $modv= 1;
while ($intv*10+$modv > 4) {
print $intv.".".$modv."\n";
if( ($modv -= 1) < 0)
{
$intv -= 1; $modv += 10;
}
}
}

$intv = 1; $modv = 1;
while ($intv*10+$modv >= 4) {
print $intv.".".$modv."\n";
if( $modv -= 1 < 0)
{
$intv -= 1; $modv += 10;
}
}
}

(i) & (ii) should do for most uses where you only need a fixed
precision, really you are just translating everything directly
into integers,

(iii) integer/modulus(=variable=MODU)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Just change 10 in the above for $MODU
You can even keep a seperate MODU value for each value you use
and write some functions to perform operations on these type
of values (intv,modv,MODU) == intv+modv/MODU

So this will in theory be able to deal with rational numbers
in the way we would expect them to behave.

Of course the problem is that MODU can and will grow arbitarily
large and really you need some "clean-up" function to reduce
modv/MODU (finding any common factor and dividing) just to make
sure it doesn't become unneccesarily large at a given time.

You won't be able to calculate square roots and sines, cosines, etc
in most cases because it is not possible to do that (they don't
produce rational numbers in a lot of cases so you aren't actually
calculating them when you do $a=sqrt($b); it is an approximation
of course the problem with FP is that it doesn't exactly come
screaming in your face that $a=$b/$c migth be an approximation or
that $a=$b+$c can introduce errors!)

The time to calculate an operation will increase with the complexity
of the number until eventually it takes ages and megabytes of workspace
and of course at some point the system won't have the resources to
deal with it anymore ( before that you have to write a function
or get a perl module to deal with arbitarily large integers)

Usually when people utilise floating point it is because the
loss in accuracy doesn't matter (because it is a leisure application
maybe). A thing to be wary of is belief that using some very
high precision FP will somehow increase the overall accuracy of
the math - each time you perform an operation on a value in FP
you are on average introducting more error into it, and this error
will rapidly get larger the more operations you perform, as it
propagates. If you are doing some repeated operation you can say byebye
to any hint of mathematical accuracy over time and the FP size won't
have much effect on this. If it is an application where the accuracy is of
any importance (aside from cosmetic) then either (i) calculate possible
error bounds (I don't know if there are studies on this but it seems
very difficult because you have to factor in every single operation
and often won't even know the size of the FP given that your program
may run in different environments) (ii) use integer methods

Just the other day I was using something called 'mogrify' to produce some
thumbnails for a new website gallery and I noticed that the scaling method
it uses is obviously the incorrect FP method because every other picture
was losing 1 pixel on a length and/or width; you don't get that if you
use integer methods but of course it's a bit more work to code it.

very funny :)

seeyafrom
l
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top