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