-4

Possible Duplicate:
Floating point comparison

Well this is a strange one. Ordinarily the following if( 4.0 == 4.0 ){return true} will always return true. In a simple little opengl 3d 'shooter' program I have, when I am trying to add 'jumping' effects, this is not the case.

The idea is fairly simple, I have a terrain of triangle strips, as the 'character' moves/walks you move along a 2d array of heights, hence you walk up and down the various elevations in the hills/troughs.

Outside of the drawScene() function (or if you know opengl, the glutDisplayFunc()), I have an update() function which raises the character up and down as he 'jumps', this is called in drawScene(). In words, as high level as I can explain it, the jumping algorithm is below:

parameters:

double currentJumpingHeight
double maximumJumpingHeight = 4.0
double ypos;
const double jumpingIncrement = 0.1; //THE PROBLEM!!!! HAS TO BE A MULTIPLE OF 0.5!!
bool isJumping = false;
bool ascending = true;

the algorithm:

(when space is pressed) isJumping = true.

if ascending = true and isJumping = true, 
      currentJumpHeight += jumpingIncrement (and the same for ypos)

if currentJumpingHeight == maximumJumpingHeight, //THE PROBLEM
     ascending = false
     (we decrement currentJumpingHeight and start to fall until we hit the ground.)

Its very simple, BUT IT ONLY WORKS WHEN jumpingIncrement IS A MULTIPLE of 0.5!!

If jumpingIncrement is, say, 0.1, then currentJumpingHeight will never equal maximumJumpingHeight. The character takes off like a rocket and never returns to the ground. Even when the two variables are printed to the standard output and are the same, the condition is never true. This is the problem I would like to solve, it is absurd.

I don't want any feedback on the jumping algorithm - just the above paragraph please.

please help.

Community
  • 1
  • 1

2 Answers2

5

It's just a typical floating point precision problem. In particular 0.1 cannot be represented exactly using binary floating points. Numbers like 0.5 and 0.25 on the other hand can be represented exactly, and thus will probably work. I believe the compiler is still free to make it not work, even in that case.

In your case a solution is using >=:

if ascending && (currentJumpingHeight >= maximumJumpingHeight)
     ascending = false
     currentJumpingHeight = maximumJumpingHeight

You could also use epsilon comparisons, but I avoid them where possible. In your case a simple >= seems cleaner than epsilon equality.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • Yes - thank you very much for your prompt response. Yes it worked well and was a very simple solution. What is an epsilon comparison? For all other people who have a similar problem - this website may be of use: http://floating-point-gui.de/ – user1460838 Jun 16 '12 at 16:48
  • @user1460838 An epsilon comparision is something like replacing `a==b` with `Abs(a-b) <= epsilon` where `epsilon` is a small constant. The problem is that you need to choose a value for epsilon that fits the situation, and that's not trivial. – CodesInChaos Jun 16 '12 at 17:01
3

As people said, it's a typical floating precision point problem. Look at this Basically, in the same way you can't code with a finite number of digits 1/3 in base 10

1/3 = 0.3333333333.....

You can't do 1/10 in base 2. It will be

0.1 = 0x0.0001100110011001100110011001100110011001100110011...

You should never compare floats but check that there difference is smaller than a value, ex

if (fabs(a-b) < 1e-6)

instead of

if(a==b)

Of course in your case, just use '>='.

It work with your 0.5 increment, because 0.5 is 1/2 or 0.1 in binary, so it's coded properly . That will work for any power of 2 so 0.5 or 0.125, but never with 0.1.

mb14
  • 22,276
  • 7
  • 60
  • 102
  • 1
    It might be worth noting that there's nothing fundamentally weird about floating point variables. You can compare them just like any other variable, and you certainly have `0.1 == 0.1`. What is problematic is *arithmetic*: It is *not* necessarily true that `0.1 + 0.1 == 0.2`. – Kerrek SB Jun 16 '12 at 21:19
  • @KerrekSB But 0.1 is not always 0.1. An obvious case is `float f = 0.1; if (f==0.1)...` which fails because 0.1 is a double and f is a single. And sometimes, the results can be more subtle and more implementation dependent. – Mr Lister Jun 18 '12 at 18:45
  • 1
    @MrLister: That's because you're cheating, and `f` is the *result of an operation*. If you say `float f = 0.1f;`, then `f == 0.1f` will be true. You can *not* reliably predict the outcome of a floating point operation. – Kerrek SB Jun 18 '12 at 20:03