[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c

is it a bad idea to index a for loop with a float?

lloyd

3/18/2011 6:09:00 PM

I find this odd:

===========================
#include <stdio.h>

int main(int argc, char *argv[])
{
float phi, phi_start, phi_end, phi_step;

phi_start = 0.0;
phi_end = 3.0;
phi_step = 0.2;

for (phi = phi_start; phi<= phi_end; phi=phi+phi_step)
printf("phi = %.15f\n",phi);

return 0;
}
============================

>./test
phi = 0.000000000000000
phi = 0.200000002980232
phi = 0.400000005960464
phi = 0.600000023841858
phi = 0.800000011920929
phi = 1.000000000000000
phi = 1.200000047683716
phi = 1.400000095367432
phi = 1.600000143051147
phi = 1.800000190734863
phi = 2.000000238418579
phi = 2.200000286102295
phi = 2.400000333786011
phi = 2.600000381469727
phi = 2.800000429153442
>

What the heck is up? It's fine if I set phi_step to 0.25 (I mean you
get the expected values of phi.) The bad digits are further away from
the decimal point if I use doubles instead, but they still are enough
to break a test of "if (phi==floor(phi))" which I want to use so I can
flag cases where phi is an integer. Currently I'm using "if (phi -
floor(phi) < epsilon)" to catch those cases, and I've had to change my
loop condition to "phi<=phi_end+epsilon". What's the usual practice?
19 Answers

Ben Bacarisse

3/18/2011 6:20:00 PM

0

lloyd <lloyd.houghton@gmail.com> writes:

> I find this odd:
>
> ===========================
> #include <stdio.h>
>
> int main(int argc, char *argv[])
> {
> float phi, phi_start, phi_end, phi_step;
>
> phi_start = 0.0;
> phi_end = 3.0;
> phi_step = 0.2;
>
> for (phi = phi_start; phi<= phi_end; phi=phi+phi_step)
> printf("phi = %.15f\n",phi);
>
> return 0;
> }
> ============================
>
>>./test
> phi = 0.000000000000000
> phi = 0.200000002980232
> phi = 0.400000005960464
> phi = 0.600000023841858
> phi = 0.800000011920929
> phi = 1.000000000000000
> phi = 1.200000047683716
> phi = 1.400000095367432
> phi = 1.600000143051147
> phi = 1.800000190734863
> phi = 2.000000238418579
> phi = 2.200000286102295
> phi = 2.400000333786011
> phi = 2.600000381469727
> phi = 2.800000429153442
>>
>
> What the heck is up? It's fine if I set phi_step to 0.25 (I mean you
> get the expected values of phi.) The bad digits are further away from
> the decimal point if I use doubles instead, but they still are enough
> to break a test of "if (phi==floor(phi))" which I want to use so I can
> flag cases where phi is an integer. Currently I'm using "if (phi -
> floor(phi) < epsilon)" to catch those cases, and I've had to change my
> loop condition to "phi<=phi_end+epsilon". What's the usual practice?

Float variables usually only have a digits of precision, but one thing
is certain: if they use base 2 (thay almost always do these days),
neither they nor doubles can represent the step you are using (0.2)
without error so you will have to cope with that.

The usual practise for for loops is to use integers and to calculate phi
from the integer loop count. If the loops is not really a counted loop,
use a while loop. You'll have to decide based on the problem domain
when the loops stops.

You will have a lot of trouble detecting an integer except under very
favourable conditions.

You might like to have a read of http://cr.yp.to/2005-590/go...

--
Ben.

Kenneth Brody

3/18/2011 6:27:00 PM

0

On 3/18/2011 2:09 PM, lloyd wrote:
> I find this odd:
>
> ===========================
> #include<stdio.h>
>
> int main(int argc, char *argv[])
> {
> float phi, phi_start, phi_end, phi_step;
>
> phi_start = 0.0;
> phi_end = 3.0;
> phi_step = 0.2;
>
> for (phi = phi_start; phi<= phi_end; phi=phi+phi_step)
> printf("phi = %.15f\n",phi);
>
> return 0;
> }
> ============================
>
>> ./test
> phi = 0.000000000000000
> phi = 0.200000002980232
> phi = 0.400000005960464
[...]
> phi = 2.600000381469727
> phi = 2.800000429153442
>>
>
> What the heck is up? It's fine if I set phi_step to 0.25 (I mean you
> get the expected values of phi.) The bad digits are further away from
> the decimal point if I use doubles instead, but they still are enough
> to break a test of "if (phi==floor(phi))" which I want to use so I can
> flag cases where phi is an integer. Currently I'm using "if (phi -
> floor(phi)< epsilon)" to catch those cases, and I've had to change my
> loop condition to "phi<=phi_end+epsilon". What's the usual practice?

Just like there are some numbers, such as 1/3, which cannot be represented
exactly in decimal, there are numbers which cannot be represented exactly in
binary.

The number 1/5 (0.2 in decimal) is one such number. On your particular
implementation, the value given is approximately 0.200000002980232 instead
of exactly 0.2. The number 1/4 (0.25 in decimal) can be represented exactly
in binary, which is why you don't run into any issues here with it.

You can either continue using floating point along with an epsilon, or you
can use integer values for the loop control, if you are in charge of the values.

Perhaps, calculate the number of iterations that "should" be done with the
floating point numbers, and then use that as an integer counter. Perhaps
something like this (untested) calculation:

int iterations = floor( (phi_end-phi_start) / phi_step + epsilon );

--
Kenneth Brody

Willem

3/18/2011 6:41:00 PM

0

lloyd wrote:
) What the heck is up? It's fine if I set phi_step to 0.25 (I mean you
) get the expected values of phi.) The bad digits are further away from
) the decimal point if I use doubles instead, but they still are enough
) to break a test of "if (phi==floor(phi))" which I want to use so I can
) flag cases where phi is an integer. Currently I'm using "if (phi -
) floor(phi) < epsilon)" to catch those cases, and I've had to change my
) loop condition to "phi<=phi_end+epsilon". What's the usual practice?

The usual practise is to try to not rely on equality with floats,
and to use epsilon when you do want to check for equality.

What you did, basically.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT

Tim Prince

3/18/2011 6:58:00 PM

0

On 3/18/2011 11:09 AM, lloyd wrote:
> I find this odd:
>
> ===========================
> #include<stdio.h>
>
> int main(int argc, char *argv[])
> {
> float phi, phi_start, phi_end, phi_step;
>
> phi_start = 0.0;
> phi_end = 3.0;
> phi_step = 0.2;
>
> for (phi = phi_start; phi<= phi_end; phi=phi+phi_step)
> printf("phi = %.15f\n",phi);
>
> return 0;
> }
> ============================
>
>> ./test
> phi = 0.000000000000000
> phi = 0.200000002980232


Besides exposing the issues of mixing float and double, this is likely
to stop optimizations which depend on a counted loop. You shouldn't
consider this as odd, but as a natural consequence.


--
Tim Prince

Tim Prince

3/18/2011 6:58:00 PM

0

On 3/18/2011 11:09 AM, lloyd wrote:
> I find this odd:
>
> ===========================
> #include<stdio.h>
>
> int main(int argc, char *argv[])
> {
> float phi, phi_start, phi_end, phi_step;
>
> phi_start = 0.0;
> phi_end = 3.0;
> phi_step = 0.2;
>
> for (phi = phi_start; phi<= phi_end; phi=phi+phi_step)
> printf("phi = %.15f\n",phi);
>
> return 0;
> }
> ============================
>
>> ./test
> phi = 0.000000000000000
> phi = 0.200000002980232


Besides exposing the issues of mixing float and double, this is likely
to stop optimizations which depend on a counted loop. You shouldn't
consider this as odd, but as a natural consequence.


--
Tim Prince

lloyd

3/18/2011 7:53:00 PM

0

Willem wrote:

> The usual practise is to try to not rely on equality with floats,
> and to use epsilon when you do want to check for equality.

Thanks Willem, and Ben for the link to the impressively thorough
document, and everyone else. If I continue to check integerness with
epsilon, can I rely on the inaccuracy being on the positive side, so
that I just need to check whether phi - floor(phi) < epsilon, and not
abs(phi-floor(phi))<epsilon ?

Tim Prince

3/18/2011 8:07:00 PM

0

On 3/18/2011 12:53 PM, lloyd wrote:
> Willem wrote:
>
>> The usual practise is to try to not rely on equality with floats,
>> and to use epsilon when you do want to check for equality.
>
> Thanks Willem, and Ben for the link to the impressively thorough
> document, and everyone else. If I continue to check integerness with
> epsilon, can I rely on the inaccuracy being on the positive side, so
> that I just need to check whether phi - floor(phi)< epsilon, and not
> abs(phi-floor(phi))<epsilon ?
>
The rounding from double to float should be IEEE nearest, so whether it
is up or down depends on the value.

--
Tim Prince

Keith Thompson

3/18/2011 8:31:00 PM

0

lloyd <lloyd.houghton@gmail.com> writes:
> I find this odd:
>
> ===========================
> #include <stdio.h>
>
> int main(int argc, char *argv[])
> {
> float phi, phi_start, phi_end, phi_step;
>
> phi_start = 0.0;
> phi_end = 3.0;
> phi_step = 0.2;
>
> for (phi = phi_start; phi<= phi_end; phi=phi+phi_step)
> printf("phi = %.15f\n",phi);
>
> return 0;
> }
> ============================
[...]

http://www.c-faq.com/fp/..., section 14.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.ne...
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Ben Bacarisse

3/18/2011 8:54:00 PM

0

Tim Prince <tprince@computer.org> writes:

> On 3/18/2011 12:53 PM, lloyd wrote:
>> Willem wrote:
>>
>>> The usual practise is to try to not rely on equality with floats,
>>> and to use epsilon when you do want to check for equality.
>>
>> Thanks Willem, and Ben for the link to the impressively thorough
>> document, and everyone else. If I continue to check integerness with
>> epsilon, can I rely on the inaccuracy being on the positive side, so
>> that I just need to check whether phi - floor(phi)< epsilon, and not
>> abs(phi-floor(phi))<epsilon ?
>>
> The rounding from double to float should be IEEE nearest, so whether
> it is up or down depends on the value.

Also, the OP calculated phi in a loop. In general the errors will
accumulate. That's why I suggested using an int for the loop control:
calculating phi from that can ensure you get the best rounding.
However, I suspect the simple loop was an example and a more complex one
is envisaged.

--
Ben.

Keith Thompson

3/18/2011 9:28:00 PM

0

Tim Prince <tprince@computer.org> writes:
> On 3/18/2011 12:53 PM, lloyd wrote:
>> Willem wrote:
>>
>>> The usual practise is to try to not rely on equality with floats,
>>> and to use epsilon when you do want to check for equality.
>>
>> Thanks Willem, and Ben for the link to the impressively thorough
>> document, and everyone else. If I continue to check integerness with
>> epsilon, can I rely on the inaccuracy being on the positive side, so
>> that I just need to check whether phi - floor(phi)< epsilon, and not
>> abs(phi-floor(phi))<epsilon ?
>>
> The rounding from double to float should be IEEE nearest, so whether it
> is up or down depends on the value.

Whether the implementation uses IEEE or not is implementation-specific
(possibly implementation-defined).

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.ne...
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"