Archived

This topic is now archived and is closed to further replies.

Graham

if() returning wrong answers

Recommended Posts

Graham    166
I am working on a 3d computer game, and while rendering my map many triangles were missing. I have tracked the problem down to an if statement that might be returning true when it should be false. This is what I am doing; float T = 0.0; T = numA / numB; // numA and numB are floats if((T > 0) && (T < 1)) { //do important stuff } I have output the value of numA, numB and T to a file. numA is 12, numB is 12, and T is 1. But the if() is true. Is there anything I can do to make this work. I think that there is a precision problem somewhere in the code. Go on an Intense Rampage

Share this post


Link to post
Share on other sites
Stoffel    250
Rule of thumb: when possible, keep all values the same type. Change it to:
if ((T > 0.0f) && (T < 1.0f))

Let us know if it still misbehaves and we can look a little deeper into it.

HTTP 500 error, retry #1..

Share this post


Link to post
Share on other sites
Graham    166
According to my file output, there are other times when numA and numB are equal to each other, and T is equal to 1, but the if() was false.



Go on an Intense Rampage

Share this post


Link to post
Share on other sites
Graham    166
I want less than 1.0f
My file output says that T = 1, and if((T > 0.0f) && (T < 1.0f))
statement is true. Then i do a if(T == 1.0f) and it is false.

According to my file output T is 1, but then the first if statement is true, then the (T == 1.0f) is false.
Im very confused.

Go on an Intense Rampage

Share this post


Link to post
Share on other sites
Graham    166
There is also a time when numA is -9.53674e-007 when it should be zero. This is also causing some errors in my code. It occurs when i subtract one float from another and both floats are the same value.

Share this post


Link to post
Share on other sites
DerekSaw    243
Are you doing (T > 0) && (T < 1) or (T >= 0) && (T <= 1)?

[edited by - DerekSaw on October 2, 2002 10:50:15 PM]

err... how do you output the floating value?? 0.9999999 might output as 1 sometimes.

[edited by - DerekSaw on October 2, 2002 10:52:27 PM]

Share this post


Link to post
Share on other sites
Sneftel    1788
The reason this occurs is because of the inaccuracy of floating point numbers. Because of how they''re stored, something like 12.0/12.0 can turn out to be something odd, like 1.00000017623 or something.

Recognize when to use equalities/inequalities with floats and when not to. You should consider two floats to be equal if they are within a certain small value, called "epsilon", of each other.
For instance, don''t do:
if((a > b)

instead, do:

if((a-b) > 1.0e-4)

Don''t do:
if(a == b)

instead, do:

if(abs(a-b) < 1.0e-5)

or something like that. Libraries exist to make epsilon calculations easier and more reliable; look in Boost for stuff like that.


Don''t listen to me. I''ve had too much coffee.

Share this post


Link to post
Share on other sites
scaught    122
quote:
Original post by hpolloni
maybe changing the T for int T?

quote:
Original post by Anonymous Poster
try (t<=0) or (t>=1)

Are you guys even looking at the same thread?

Please stick to answering the question at hand and not some imaginary one that your answer would be correct for.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Pull your head in scaught, they may have missunderstood the question or simly had limmited understanding or experience with the problem. It would have been much more useful to explain why this would be incorrect, as Sneftel has.

Share this post


Link to post
Share on other sites
scaught    122
quote:
Original post by Anonymous Poster
they may have missunderstood the question or simly had limmited understanding or experience with the problem.

And were they required to answer? Generally, if I''m asking a question, I appreciate it when I''m not fed misinformation.
quote:
It would have been much more useful to explain why this would be incorrect, as Sneftel has.

I did not provide additional information because Sneftel''s answer was way more than sufficient. I also did not provide any additional misinformation. My post was merely to discourage further "attempts" (if you can even call them that) at answering the question by people who don''t know why they''re posting.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Just do this to get around float incosistancies:

#define epsilon 1.0e-4f

if ( ( T > ( 0.0f - epsilon ) ) && ( T < ( 1.0f + epsilon ) ) )

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:
Original post by Sneftel
For instance, don''t do:
if((a > b)

instead, do:

if((a-b) > 1.0e-4)

What''s the use of the 1.0e-4 here? In both cases you get slightly wrong results anyway. Just a bit different kind of wrong results.

Share this post


Link to post
Share on other sites
Sneftel    1788
quote:
Original post by Anonymous Poster
What''s the use of the 1.0e-4 here? In both cases you get slightly wrong results anyway. Just a bit different kind of wrong results.

Because in almost all cases, 0.0001 is a small enough difference that the values mayas well be equal. For instance, a millimeter one way or the other won''t really matter in computing a headshot. Comparing floating point numbers directly, except in extremely controlled and mathematically verified conditions, is a bad idea.


Don''t listen to me. I''ve had too much coffee.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Informatic, !!!if you don''t know about programming!!!!

Share this post


Link to post
Share on other sites
Stoffel    250
You''re not giving us the whole picture, here. Somewhere you''re converting things. The example you give works perfectly:

  
#include <iostream>

using namespace std;

void foo (float a, float b)
{
float t = a / b;
if (t > 0.0f && t < 1.0f)
cout << "t is " << t << endl;
}

int main ()
{
foo (12.0f, 12.0f);
return 0;
}

The if conditional is not true since t == 1.0f exactly, so the statement is not printed.

I have a feeling that the way you are looking at the numbers is not telling you everything. Here was a telling quote by you:
quote:

There is also a time when numA is -9.53674e-007 when it should be zero. This is also causing some errors in my code. It occurs when i subtract one float from another and both floats are the same value.


If both floats are the same value, you get exactly 0 when you subtract the two. Most likely, the floats were slightly different values, but the way you were printing them you couldn''t tell because of printing precision.

The only sure way to tell if two floats are precisely the same is to look at their binary representation. You can do this by either looking at the memory at their address, or by dropping code like this into your watch window:
*((int*)&t)

If there''s even a single bit of difference between two floats, you will not get 0.0f when you subtract them.

I don''t know whether scaught''s solution is the best here because I don''t know enough about the problem at hand. As he said, direct comparison of floats can be tricky in situations that aren''t strictly controlled; that''s why I strictly control all of my situations.

I''m guessing that when you say "numA and numB are the same", that you''re looking at a rounded or imprecise version of those variables but you''re passing the floats into your function directly.

I would suggest changing your logging function from something like this:
printf ("%f %f %f\n", numA, numB, T);
to..
printf ("%.20e %.20e %.20e\n", numA, numB, T);

That should give you a lot of precision and you should be able to see any slight difference between numbers.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:
Original post by Sneftel
Because in almost all cases, 0.0001 is a small enough difference that the values mayas well be equal. For instance, a millimeter one way or the other won''t really matter in computing a headshot.
Isn''t that a reason why you should *not* bother with if(a-b>0.0001)? Giving arguments against yourself, eh? Maybe you''ve just had too much coffee

I can''t think of a single case where using if(a-b>0.0001) instead of if(a>b) would benefit anyone. Surely there will be error with floating point arithmetics, and it may be + or -. The error may be 0.0001, it may be even 100. You might even be working with so small numbers that the error (and values themselves) is considerably less than 0.0001, so your solution will only make things a lot worse, possibly even making all tests fail. And when you change from float to double, the error decreases considerably.

And in simulations, games, or other possible floating point applications, it should never matter whether two values are *exactly* the same or not. Feel free to show me a counterexample though.

Share this post


Link to post
Share on other sites
Graham    166
I am not using printf() for my output. I am using a ofstream variable. What can i use to show the exact value of numA and numB.



Go on an Intense Rampage

Share this post


Link to post
Share on other sites
Stoffel    250
Use the precision stream modifier (in iostream because it''s part ios_base) or the setprecision manipulator (have to include iomanip).

ex1:
cout.precision (20);
cout << 5.0f/12.0f << endl;

ex2:
#include <iomanip>
cout << setprecision (20) << 5.0f/12.0f << endl;

HTTP 500 retry #1..#2..

Share this post


Link to post
Share on other sites
Graham    166
I implemented doubles everywhere in my program and now there is only one triagle that is missing from my map. I am not sure if i should use epsilon values because it could create false positives. The reason T must be bigger than 0 and below 1 is because I am using parametric equations to find the intersections of planes and triagnles for my bsp renderer.

Go on an Intense Rampage


[edited by - Graham on October 3, 2002 8:21:25 PM]

Share this post


Link to post
Share on other sites
DerekSaw    243
Many times, if you are using floats, and you force the output with > 6 or 7 precision, you might get unpredictable result beyond that float''s precision.

Share this post


Link to post
Share on other sites