Skip to main content
GameDev.net gamedev.net
🔒 Locked

Comparing floats.

Started by LilBudyWizer Dec 4, 2002 at 10:07 AM 15 replies 700+ views
Original Post
LilBudyWizer
LilBudyWizer
Ok, you have the basic |a-b| < e to check if two numbers are equal within some margin of error. That is the only way I can think of to do it. I saw a post here once where someone said they hated epsilons and never use them. So is there a practical alternative and if so what is it/are they? [edited by - LilBudyWizer on December 4, 2002 11:08:16 AM]
Keys to success: Ability, ambition and opportunity.
timiscool999
timiscool999
I think float''s (or maybe double''s, I forgot now , but this is still a good method) are accurate to 6 decimal places so you could do:

|a-b| < 0.000001

I just don''t remember now if float''s or double''s are accurate to 6 decimal places, but this works.

-timiscool999
"I like waffles. Especially with syrup." -me

XBox controller v2.0

click for bigger picture
-timiscool999"I like waffles. Especially with syrup." -me
XBox controller v2.0

click for bigger picture
davidsporn
davidsporn
quote:
Original post by LilBudyWizer
Ok, you have the basic |a-b| < e to check if two numbers are equal within some margin of error. That is the only way I can think of to do it. I saw a post here once where someone said they hated epsilons and never use them. So is there a practical alternative and if so what is it/are they?



Nope, there are no alternative to epsilon with float. Simply because binary representation of a float is often inaccurate, for instance a simple number like 0.1 (or 0.2 or 0.3,... I don''t remember well)





----
David Sporn AKA Sporniket
johnb
johnb
> |a - b| < e

This often works fine but occasionally it''s not good enough, usually when dealing with small or large numbers. E.g. if a and b are relatively large you will need to increase e otherwise you will almost never satisfy the condition. And if a and b are too small the converse applies: the condition will always be true unless e is made smaller.

There''s no hard and fast rule for this as what margin of error is acceptable, and how ''large'' or ''small'' you can go before it stops working, is very subjective, i.e. is largely a matter of opinion. One solution is to set it up in your game and have it print out |a - b| every time it does the test, then use this as a guidline to your value(s) of e.

> I guess you could divide them and see if you come close to 1...

As long as they are not too close to zero, as dividing by a small number tends to magnify errors, while dividing by zero gives an error.
John BlackburneProgrammer, The Pitbull Syndicate
LilBudyWizer
LilBudyWizer
With the division how do you then compare the result to one? Another division? Or |1-a/b| < e?
Keys to success: Ability, ambition and opportunity.
Thrump
Thrump
I can''t think of any practical/better way than using an epsilon. Did the person who mentioned that know what they were talking about? jk...

Basically, you want operations such as 5/5==10/10 to be equal, but it probably won''t be on most FPU hardware.

One problem I run into is, even with an epsilon, getting to the same number by a different way will sometimes be true, and sometimes false.

For example:
Suppose you''re seeing if 2 circles overlap.
epsilon = 0.1
distance = 1.0
radius = 0.51

These circles overlap and our function returns true. Then, another programmer learns of a faster way to compute the distance.
This function returns distance = 1.2
Now the circles don''t overlap.

The numbers are exaggerated, but sometimes logic can get messed up when something is both true and false.

FPU''s should have an epsilon right in their == operation (user-defined of course), although this doesn''t solve the problem above.

You could express your (semi-)real numbers as 2 integers.
Example: 4.5 is stored as 9 and 5 (9 / 5). All real numbers are converted to this format before any multiplications are done. After any mathematical operation the fractions are reduced. Comparison would then be perfect, but this solution is far from ideal. I''ll cut myself off here... look at the time, gotta go.

I''m thinking of changing my sig to "The world would be a better place without floats".

LilBudyWizer
LilBudyWizer
Well, hopefully that would be 9/2 for 4.5, not 9/5, but I get the point. Sounds simple, but gets pretty nasty in practice. That is for a day I''m feeling a bit more ambiteous than just trying to compare two floating point numbers
Keys to success: Ability, ambition and opportunity.
Thrump
Thrump
quote:
Original post by LilBudyWizer
Sounds simple, but gets pretty nasty in practice. That is for a day I''m feeling a bit more ambiteous than just trying to compare two floating point numbers

Oh, you wanted a PRACTICAL solution... my mistake
davidsporn
davidsporn
quote:
Original post by johnb
> |a - b| < e

This often works fine but occasionally it''s not good enough, usually when dealing with small or large numbers. E.g. if a and b are relatively large you will need to increase e otherwise you will almost never satisfy the condition. And if a and b are too small the converse applies: the condition will always be true unless e is made smaller.

There''s no hard and fast rule for this as what margin of error is acceptable, and how ''large'' or ''small'' you can go before it stops working, is very subjective, i.e. is largely a matter of opinion. One solution is to set it up in your game and have it print out |a - b| every time it does the test, then use this as a guidline to your value(s) of e.




[note : the following is a rememberance of my sci. computation curses. Some details may be erroneous.]

Ah yes, I forgot that. In fact, float number are stored using scientifical notation, i.e a value between 0 (inclusive) and 1 (exclusive) and the power of 10.
e.g: 1 = 0.1e1.

Thus the |a - b| = X e N, hence epsilon is compared to _X_.

But I cannot remember the function to get the X value from a float.


----
David Sporn AKA Sporniket
johnb
johnb
> But I cannot remember the function to get the X value from a
> float.

I think it''s the lowest 23 bits of the float, with the other bits being sign and exponent.

You could examine the appropriate bits to get the exponent, then divide by 2^n (as it''s a binary exponent) to adjust a and b before testing |a = b| < e. But this still has problems if a and/or b can be close to zero, as then the exponent grabbed from the numbers may be to small and so dividing by 2^n may generate too big errors.
John BlackburneProgrammer, The Pitbull Syndicate
Tangh
Tangh
>Thus the |a - b| = X e N, hence epsilon is compared to _X_.

How can you be sure that your computer will store |a-b| so that _X_ can be compared to epsilon ?

Let''s say |a-b| = 1.0
then you can have |a-b| = 0.1 * 10^1 ("big") or = 0.00000000001 * 10^10 ("small") .


Tang
davidsporn
davidsporn
quote:
Original post by Tangh
>Thus the |a - b| = X e N, hence epsilon is compared to _X_.

How can you be sure that your computer will store |a-b| so that _X_ can be compared to epsilon ?

Let''s say |a-b| = 1.0
then you can have |a-b| = 0.1 * 10^1 ("big") or = 0.00000000001 * 10^10 ("small") .


Tang



Again I forgot something important : the first digit after the decimal separator is not 0, thus 0.1 in is garanteed to be coded as 0.1E1 .


----
David Sporn AKA Sporniket
Tangh
Tangh
ok, I see... but I suppose you actually compare the exponent of (a-b) with the smaller of the expo of a and b (instead of comparing X).

Tang
davidsporn
davidsporn
Oh my god !!! the stuff about comparing the X part of |a - b| is just nonsense !!!!!!!

I apologize for writing such ****STUPID**** thing !!

=========================================================
Ok, I restart from the beginning :

let's say that 'a' is the reference, non zero value, then :

abs(a - b) is called "absolute error" and depends of the magnitude of a and b, thus so do epsilon.

abs((a - b)/a) is the "relative error" (relative to a) and it is independant from the magnitude of a and b, thus epsilon too.


[Edit] Ah, and if the reference is zero, well, obviously, we cannot use the relative error, of course.

----
David Sporn AKA Sporniket

[edited by - davidsporn on December 6, 2002 1:31:44 PM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.