PDA

View Full Version : unexact decrementing GLfloat



elvin
11-28-2000, 11:03 PM
Hi all!

Although my question is not 100% OpenGL related, I stumbled across this problem when modifying example code from NeHe's tutorials.

Using Visual C++ 6 (SP4) I decremented a GLfloat variable (initialized with 1.0f) by 0.1f until it is 0.0f. When the variable was 0.2f and then was decremented by 0.1f, the result was 0.999999f (and not 0.1f as it should have been).

Has anyone a hint or a workaround for this? Should I round the result (how?).

Thanks in advance,

elvin

elvin
11-28-2000, 11:10 PM
One other thing:

I multiplied every value by 10.0f so that I don't subtract 0.1f but 1.0f. Now it works!

elvin

Nutty
11-29-2000, 02:20 AM
When dealing with floating point numbers you should NEVER do equality tests (==). Always use <= or >= . eg. if(f_vlaue <= 0.0f)

Because floats store values in binary, any non power of 2 number representation is only an approximation, so comparing it to a precise value like 0 is bound to fail lots.

Happy coding,
Nutty

Bob
11-29-2000, 02:42 AM
>> any non power of 2 number representation is only an approximation

What I know, this isn't entirely correct. Consider the number 0.75f. This one is not a power of two, but it is a sum of 0.5f and 0.25f, which in turn is, all of them, a power of two. So this number CAN be represented exactly, even though it isn't a power of two. But the number 0.1f, howerver, is an approximation. 0.1f can't be split up in only power-of-two-components, and therefore isn't exact. This has probably something to to with why elvin's program "fails". Because of roundoff errors or whatever. When it comes to comparsions, it's always a good habit to do what Nutty says, by as often as possible comparig with a >= or <=, whatever datatype you are using.

Nutty
11-29-2000, 04:31 AM
Well.. you know what I meant. Just did a little test program, and even though .75 can be expressed exactly, .5 and .25 cannot.

This program also proved that doing == 0.0f is bad. Here it is if you wanna see.

#include <stdio.h>

void main(void)
{
float f = 0.75f;
int i;

for(i=0; i<20; i++)
{
printf("\n%.05f %X", f, *((int*)&f) );

f -= 0.05f;

if(f == 0.0f)
{
printf("Wehay\n");
}
}
}

P.S. Sorry the formatting went all Pete Tong!

[This message has been edited by Nutty (edited 11-29-2000).]

Bob
11-29-2000, 05:04 AM
Hmm, not sure about what that code is supposed to do/prove. Maybe it sounds strange, but can you explain in case I misunderstood the whole thing?

Note: Not trying to be rude or anything. And I do understand what you meant. Hope you understand me correct aswell.

First, when running the code, I can see that 0.75 (=3F000000), 0.5 (=3F400000) and 0.25 (=3E800000) is represented as exact numbers (and you said they couldn't), and I get these numbers by altering the startnumber to 0.5 and 0.25 respectively, and recompile and run the program. However, when running it with 0.75 as startnumber, 0.5 and 0.25 (the theoretical values) is not exact represented. And this is becaues 0.05 isn't representable exatly, and therfore you get roundoff errors while decrementing, and you never get an exact zero because the error gets too large.

Michael Steinberg
11-29-2000, 07:27 AM
Consider 0.000001f to be your precision.
You can't use a == for floats because of the said reasons.

So do something like this

a first float
b second float

#define precision 0.000001f

if( (a-b)<precisoion && (a-b)>-precision ) {
its equal
}

Bob
11-29-2000, 12:00 PM
Erm, nice tip http://www.opengl.org/discussion_boards/ubb/biggrin.gif

Never thought of that one...

Nutty
11-29-2000, 11:18 PM
Ooops you're right Bob. For some reason I thought .5 and .25 couldn't be exact. (probably cos I wasn't subtracting exactly 0.05)

Anyway it was proving that the Wehay message never got printed (not on mine anyway).

cheers,
Nutty