C++ Compare float values


Foreword

We want to compare two obviously equal floating point values (something like 3.456) in C++ but we sometimes get wrong results. For example, we want to find out if a floating point number is equal to zero:

float f = sqrt(9.0f) - 3.0f; // 9²-3
if (f == 0.0f) // works only sometimes
{
    // equal
}

Sometimes the variable f isn't equal to 0.0f, but due to the floating point precision it's something like 0.0000000000001f and the comparing fails.

Problem Explanation

The first thing that we need to know is that this problem would never appear with integer values. If we have "int 3" and subtract "int 3" from it, it will always be exactly "0".

The problem only happens with floating point numbers (float and double in C++), because of the way they are saved in memory. There is a lot of information about this around the web, for us it's enough if we know that this happens and what we can do about it.

Solution

To solve this problem we need a small epsilon value that defines a tolerance when comparing floating point values. There are many different versions of this algorithm, with dynamic epsilon values depending on how big the numbers are that you want to compare, or with constant epsilon values of many different sizes.

The epsilon in the following algorithm is what we came to after several years of struggling with this problem. So far it worked great, but everyone is free to choose different variations of this.

Implementation

bool cmpf(float A, float B, float epsilon = 0.005f)
{
    return (fabs(A - B) < epsilon);
}

Epsilon means how far they can be different from each other, while still being detected as equal. Epsilon is automatically set to 0.005f if you only pass two parameters to the function, which means you can use it like this:

cmpf(1.0f, 2.0f);

Or like this if you want to set the epsilon manually:

cmpf(1.0f, 2.0f, 0.0001f);

We use the absolute value of A - B (fabs function) because A - B can be either positive or negative, which means that we would have to compare it to a positive and a negative epsilon. By using fabs, we get the absolute value which is always positive, that saves us comparing it with a negative epsilon.

Note: fabs means float absolute.

Example

Let's see what happens if we use our cmpf function with the previously discussed example:

float f = sqrt(9.0f) - 3.0f;
if (cmpf(f, 0.0f))
{
    // equal
}

It works, even when trying it out hundreds of times. That's what we wanted.

Summary

A small function with an incredibly huge impact. Always use this method to compare float or double values, otherwise your game will have random bugs in it because of the floating point precision.

Please note that this is one of the most important problems to know about C++. A good float compare function can be found in the tool-set of every good programmer.


文章作者: sfc9982
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 sfc9982 !
  目录