Comparing Floats Without ==

Sage
Posts: 1,066
Joined: 2004.07
Post: #1
akb825 Wrote:BTW, I noticed in your source that you're using ==. Don't. With floats, you want to subtract them, take the absolute value and see if the result is < some epsilon.

I noticed that in another thread and wondered if anyone could elaborate on what exactly he's talking about. I'm not sure I understand.

What I think is going on is this:

Code:
float a = 5.3423043f;
float b = 23.432532f;
float epsilon = .002f;

if(fabs(a-b) < epsilon)
     //do stuff

Is that correct?

Edit: Subquestion: why do this instead of ==?
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #2
Yes, that's correct. The epsilon I've been using lately is 1e-5.

The reason why this is necessary is because you aren't guaranteed to have exactly the same number in the smallest parts of your precision due to rounding. Say you have 2 numbers that you've calculated: 2.948000021 and 2.948000342. You may want those to be equal, but they won't show as equal with a == check. No matter how careful you are, if you do any operations on a number that change it, it's almost always going to have a small rounding error at the end.

If you google the subject, you'll find plenty of information about it. You'll also find a more general rounding case for numbers that aren't close to 0, but for numbers that are relatively close to 0, the subtract and check is pretty much the easiest way to do it. (and you don't have to worry about a special case when one of them is 0)
Quote this message in a reply
DoG
Moderator
Posts: 869
Joined: 2003.01
Post: #3
Just be aware that using an unjustified epsilon is detrimental to precision. Ideally, your epsilon should reflect the maximally expected numerical error in your algorithm.
Quote this message in a reply
Jones
Unregistered
 
Post: #4
This might be compiler specific, but it's not ok to do this:

Code:
#define MY_EPSILON 1e-5

Is it?

Almost wrote that in before I realized the possible mistake and calculated 1e-5.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #5
Why would that not be OK?
Quote this message in a reply
Member
Posts: 446
Joined: 2002.09
Post: #6
To expand on DoG's post, check out the EPSILON is NOT 0.00001! presentation from GDC 2005 (unfortunately it's power point but works OK in OpenOffice).
Quote this message in a reply
Jones
Unregistered
 
Post: #7
OneSadCookie Wrote:Why would that not be OK?

Because I've never defined a formula in scientific notation like that, didn't think it was possible. *shrug* Smile
Quote this message in a reply
Member
Posts: 567
Joined: 2004.07
Post: #8
it is.
I believe there's a pre-defined epsilon buried in libc somewhere.. it might be too small for you purposes; float might be inaccurate enough to falsely pass the test...

Ahh yes, the constant is FLT_EPSILON, found in float.h

It's not magic, it's Ruby.
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #9
Actually, you've got it backwards: it would be inaccurate enough to falsely fail the test. Rasp
Quote this message in a reply
DoG
Moderator
Posts: 869
Joined: 2003.01
Post: #10
Nayr Wrote:it is.
I believe there's a pre-defined epsilon buried in libc somewhere.. it might be too small for you purposes; float might be inaccurate enough to falsely pass the test...

Ahh yes, the constant is FLT_EPSILON, found in float.h

FLT_EPSILON is the smallest machine number (of a 32-bit float) that, when added to one results in a number greater than one. eg:
1+EPS > 1
1+0.9*EPS == 1

If you are just randomly doing "if (foo-bar < MYEPS)" you are most likely doing it wrong. The machine epsilon is usually meant to be used as a relative number. Machine numbers can be hard to deal with, and a badly chosen eps will very likely screw up things and introduce more degenerate cases than it fixes. Ideally, you should choose the eps mathematically to match your algorithm, in the worst case at least by lots of testing and deliberation.
Quote this message in a reply
Member
Posts: 567
Joined: 2004.07
Post: #11
out of interest, why are you comparing floats?

It's not magic, it's Ruby.
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #12
I don't know about other people, but the main reason for me to compare floats in this way has been to eliminate equivalent vertices when optimizing my mesh. (that was also the context of my original statement)
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #13
akb825 Wrote:I don't know about other people, but the main reason for me to compare floats in this way has been to eliminate equivalent vertices when optimizing my mesh. (that was also the context of my original statement)

When I was doing similar work ( in my case, I wrote an API to let me declare meshes similarly to how you draw in immediate mode by drawing triangles and quads, and the backend would merge redundant vertices ) I collapsed similar vertices by ( expensively ) checking the squared distance between them, and collapsing if it was "close enough". In my case, "close enough" was defined on a per-situation basis... but admittedly, my models are simple. That being said, it worked beautifully for me.
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #14
I think you said before that you just used display lists with your demo program. Is all of your drawing going to be done with immediate mode/display lists? (since, if so, using something like bone-based animations would be... difficult without transitioning to vertex arrays/VBOs)
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  f suffix on floats revisited AnotherJake 2 2,799 Dec 22, 2008 11:11 PM
Last Post: Wowbagger
  Help with Floats clapton541 1 2,053 Apr 26, 2007 09:56 PM
Last Post: PowerMacX