Jump to content
  • Advertisement
Sign in to follow this  
Daniel Miller

float/double epsilon

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

If you intended to correct an error in the post then please contact us.

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 this post


Link to post
Share on other sites
Advertisement
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 this post


Link to post
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 this post


Link to post
Share on other sites
Quote:
Original post by Daniel Miller
How 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 this post


Link to post
Share on other sites
Quote:
Original post by GodlyGamr
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


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,

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!