# float/double epsilon

This topic is 4964 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm trying to correctly test for equality with floats. I found this tutorial, which says the "normal way" is bad:
Quote:
 #define EPSILON 1.0e-7 #define flt_equals(a, b) (fabs((a)-(b)) < EPSILON) People usually call this distance EPSILON, even though it is not the epsilon of the FP representation. I'll use EPSILON (all caps) to refer to such a constant, and epsilon (lower case) to refer to the actual epsilon of FP numbers. This technique sometimes works, so it has caught on and become idiomatic. In reality this method can be very bad, and you should be aware of whether it is appropriate for your application or not. The problem is that it does not take the exponents of the two numbers into account; it assumes that the exponents are close to zero. How is that? It is because the precision of a float is not determined by magnitude ("On this CPU, results are always within 1.0e-7 of the answer!") but by the number of correct bits. The EPSILON above is a tolerance; it is a statement of how much precision you expect in your results. And precision is measured in significant digits, not in magnitude; it makes no sense to talk of "1.0e-7 of precision". A quick example makes this obvious: say we have the numbers 1.25e-20 and 2.25e-20. Their difference is 1e-20, much less than EPSILON, but clearly we do not mean them to be equal. If, however, the numbers were 1.2500000e-20 and 1.2500001e-20, then we might intend to call them equal.
How should I test for epsilon? Using the scary method found in that tutorial?
#include <ieee754.h>

int flt_equals(float a, float b, int sigfigs)
{
union ieee754_float *pa, *pb;
unsigned int aexp, bexp;
float sig_mag;

if (a == b)
return 1;
pa = (union ieee754_float*)&a;
pb = (union ieee754_float*)&b;
aexp = pa->ieee.exponent;
bexp = pb->ieee.exponent;
if (aexp != bexp || pa->ieee.negative != pb->ieee.negative)
return 0;
pa->ieee.exponent = pb->ieee.exponent = IEEE754_FLOAT_BIAS;
sig_mag = pow(10, -(float)sigfigs);
if (fabs(a-b) < sig_mag/2)
return 1;
return 0;
}



##### Share on other sites
That tutorial does have a lot to say, and after reading it, I agree that the original "BAD" method can, at some times, not be enough. However, you have to ask yourself, "What range of numbers am I going to be dealing with?" I have not, ever, had to deal with numbers with exponents down into the -20s and -25s like in that tutorial. What I got out of the tutorial is basically that as long as you're not working with those kinds of numbers, the "BAD" method will continue to work just fine.

If, in fact, you are working with exceptionally small numbers for whatever reason, then by all means you can use their method, as I'm sure it will work, but for normal terms, I think it's a bit overkill.

-Jeff

##### Share on other sites
I was looking over my code, trying to avoid using some union-hack in C#, when I realized that I actually didn't even need to compare for equality. Instead of comparing if a number equaled one, I tested if that number was less, which works fine.

##### Share on other sites
Quote:
 Original post by Daniel MillerHow should I test for epsilon? Using the scary method found in that tutorial?*** Source Snippet Removed ***

I know you've solved the problem, but I'm going to throw this out there anyhow. I like the looks of the relative error comparison, although I've never used it myself. Its closer to what we do in real life with tolerances and such.

CM

##### Share on other sites
Thanks, I will certainly need that later. [smile]

##### Share on other sites
Quote:
 Original post by GodlyGamrThat tutorial does have a lot to say, and after reading it, I agree that the original "BAD" method can, at some times, not be enough. However, you have to ask yourself, "What range of numbers am I going to be dealing with?" I have not, ever, had to deal with numbers with exponents down into the -20s and -25s like in that tutorial. What I got out of the tutorial is basically that as long as you're not working with those kinds of numbers, the "BAD" method will continue to work just fine.If, in fact, you are working with exceptionally small numbers for whatever reason, then by all means you can use their method, as I'm sure it will work, but for normal terms, I think it's a bit overkill.-Jeff

I concur. One might even say that if you are working with very small numbers, then maybe your epsilon can be very small too.

Another method, which works when numbers are not 0, is to do:
static bool are_equal(float a, float b){  if (b == 0.0f) return (a == 0.0f);  const float EPSILON = 0.0000001f;  return (fabs((a/b)-1.0f)<EPSILON);}

It is supposed to work even with great numbers and small numbers, and has some kind of meaning for both.

Regards,

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 15
• 9
• 11
• 9
• 9
• ### Forum Statistics

• Total Topics
634134
• Total Posts
3015751
×