Amiga.org

Operating System Specific Discussions => Amiga OS => Amiga OS -- Development => Topic started by: kas1e on February 17, 2006, 11:33:09 AM

Title: while() with float ?
Post by: kas1e on February 17, 2006, 11:33:09 AM
hi all. here is question:

#include

main()
{
  float aa=0.0f;

  while(aa<1)
  {
     aa=aa+0.01;
     printf("%f\n",aa);
  }

}  

so, for sasc after 83.000 i have 83.9999 , for vbcc after 58.000 i have 58.9999. in other words, this float value added not exactly per 0.01. So, how i can anyway use float value but which will works exactly as i need ? Becouse tons of loops buggy over it .. i can of course do if > or if < , but i want to use !=aa.

any help ? thanks.
Title: Re: while() with float ?
Post by: STeADi on February 17, 2006, 12:04:41 PM
Hello

First of all you're mixing types.

aa is a float
but you're comparison is against an integer
and you're adding 0.01 which is a double (on a pc at least IIRC)

You get what you want if you change your float to a double (increased accuracy) and your comparison to 1.0.

Hope that helps

STeADi
Title: Re: while() with float ?
Post by: Piru on February 17, 2006, 12:06:09 PM
You can't use explicit == or != with floats/doubles since the float / double presentation might never actually match the comparision value. This is a fact you need to live with. It can be worked around by adding "precision" to the compare.

Example:
Code: [Select]
#include <stdio.h>
#include <math.h>

#define FCMP(a,b,p) (fabs((a) - (b)) < p)

int main(void)
{
  float aa = 0.0f;

  while(!FCMP(aa, 1.0, 0.001))
  {
    aa = aa + 0.01;
    printf(&quot;%f\n&quot;, aa);
  }

  return 0;
}


So instead of matching exact value, you are in fact matching some value range.

Making the type double won't help, nor having it work by luck on one particular system make it work on another processor family. Exact matching is a no-no.
Title: Re: while() with float ?
Post by: kas1e on February 17, 2006, 12:23:11 PM
Piru, thanks for help, will use fabs().
btw, what will be better (for speed), your example, or this:
while (fabs(a - 1) > 0.001) ?
Title: Re: while() with float ?
Post by: Piru on February 17, 2006, 12:43:24 PM
@ kas1e

[EDIT]Yes. Removed that brainfart. Sorry[/EDIT]

There is no speed difference. Macros have no speed penalty.

However, if you know specifics about the condition you're testing you can possibly remove fabs() (if you for example know that the subtraction result can't get negative). This fabs() stuff is there to make it generic and work when approaching from both below and above the target value.
Title: Re: while() with float ?
Post by: kas1e on February 17, 2006, 02:04:54 PM
hm, btw. with while (aa<1) i have on exit from while : 1.009999 (so, not exactly 1.00) but with fabs() i have 0.99999 (so, not exactly 1.00 agayn).

if both case i will have problems, i need exactly 1.00000 as last think. it is possible ?

becouse with fabs, of without, i need to do somethink after while for 1.0000 rezult.
Title: Re: while() with float ?
Post by: Cymric on February 17, 2006, 03:06:07 PM
It is very important that you realise what goes on. There's two issues to come to terms with.

First, when you write something like 'if (some_val==(float)1.0))' then what happens is that the bit pattern of some_val is compared to the bit pattern representing (float)1.0. If they are off by just one bit, the entire comparison breaks down.

Second, floating point arithmetic is not exact. To us humans, the outcome of a calculation like 1.0 - 0.001 is clear: 0.999. But not so in computer terms, which have to represent such numbers with the sum of certain fractions (1/2, 1/4, 1/8, and so forth). In other words, the answer of the above calculation might very well be 0.998999999. That may not look like a major difference, but if you count on it being 0.999 exactly, you have a problem.

The moral of the story is (and trust me, I've learned this the very hard way) that you must NEVER do straightforward compares to floating point numbers unless you are using exact or adaptive arithmetic. In other words: you must rewrite your loop so it doesn't rely on a comparison to (float)1.0. Either use Piru's tactic to add a small 'fudge factor', or rewrite the routine so it uses exact or adaptive arithmetic, or don't use floating points at all. Those are your options. And no, switching to double, or even double double will not help.

Yes, that probably sucks. Welcome to the wonderful world of approximate mathematics.
Title: Re: while() with float ?
Post by: Piru on February 17, 2006, 03:26:09 PM
And here is a simple example to show how it can be handled using integers. The multiplier depends on the precision required (1000 is used here for clarity).

Code: [Select]

#include <stdio.h>

int main(void)
{
  int aa_i = 0 * 1000;

  while(aa_i != 1 * 1000)
  {
    float aa;

    aa_i = aa_i + 10; /* 0.0010 */
    aa = aa_i / 1000.0;

    printf(&quot;%f\n&quot;, aa);
  }

  return 0;
}
Title: Re: while() with float ?
Post by: kas1e on February 17, 2006, 04:03:35 PM
thanks Cymric, Piru. Really good answers :)
Title: Re: while() with float ?
Post by: ChaosLord on February 18, 2006, 02:44:24 AM
I have always used the integer method with a scale factor of 32768 or 65536 in all my code for many years.  It works great and is super fast.  I work with only positive numbers so I can use bitshifts instead of slow multiply & divide.
This is called fixed point arithmetic.  It roxx0rizes my code. :-D

----------------------------------------------------
btw: If for some strange reason you wanted to,
you could store all your decimal numbers in decimal
and do all your math in decimal with your own functions.  That is how banks do it.

You could use EBCDIC packed decimal or 1 byte per digit or however you wanted to store your numbers.  Hell you could store them as ASCII strings if you wanted to.

But doing decimal arithmetic on a binary computer using above method will be both extremely accurate and extremely slow.:-o  
Title: Re: while() with float ?
Post by: Karlos on February 18, 2006, 02:50:02 AM
Quote

kas1e wrote:
hm, btw. with while (aa<1) i have on exit from while : 1.009999 (so, not exactly 1.00) but with fabs() i have 0.99999 (so, not exactly 1.00 agayn).

if both case i will have problems, i need exactly 1.00000 as last think. it is possible ?

becouse with fabs, of without, i need to do somethink after while for 1.0000 rezult.


Work in integer and have a scale factor to convert the integer to your required float at any time. For instance

Code: [Select]

float scaleF = 0.01;
int i;
for(i=0; i<=100; i++) {
  float aa = scaleF*i;
  /* do whatever with a here */
}

This will ensure that on each iteration your value of a is as close to ideal as possible.

If you can do without actual floating point, try fixed point using integers as chaoslord suggests.