Welcome, Guest. Please login or register.

Author Topic: while() with float ?  (Read 3024 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline kas1eTopic starter

while() with float ?
« 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.
 

Offline STeADi

  • Newbie
  • *
  • Join Date: Aug 2005
  • Posts: 36
    • Show only replies by STeADi
Re: while() with float ?
« Reply #1 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
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: while() with float ?
« Reply #2 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.
 

Offline kas1eTopic starter

Re: while() with float ?
« Reply #3 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) ?
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: while() with float ?
« Reply #4 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.
 

Offline kas1eTopic starter

Re: while() with float ?
« Reply #5 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.
 

Offline Cymric

  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 1031
    • Show only replies by Cymric
Re: while() with float ?
« Reply #6 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.
Some people say that cats are sneaky, evil and cruel. True, and they have many other fine qualities as well.
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: while() with float ?
« Reply #7 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;
}
 

Offline kas1eTopic starter

Re: while() with float ?
« Reply #8 on: February 17, 2006, 04:03:35 PM »
thanks Cymric, Piru. Really good answers :)
 

Offline ChaosLord

  • Hero Member
  • *****
  • Join Date: Nov 2003
  • Posts: 2608
    • Show only replies by ChaosLord
    • http://totalchaoseng.dbv.pl/news.php
Re: while() with float ?
« Reply #9 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  
Wanna try a wonderfull strategy game with lots of handdrawn anims,
Magic Spells and Monsters, Incredible playability and lastability,
English speech, etc. Total Chaos AGA
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show only replies by Karlos
Re: while() with float ?
« Reply #10 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.
int p; // A