EagleOne
EagleOne

Reputation: 571

Float comparison in C++98

I need to write a float comparison function (equal/not equal) but I have to use C++98 and boost libraries at most. I know that float comparison should include epsilon but I don't know how to write such code without using C++11.

Upvotes: 0

Views: 274

Answers (2)

eerorika
eerorika

Reputation: 238461

I know that float comparison should include epsilon but I don't know how

You could use std::numeric_limits<float>::epsilon() to get the "machine" epsilon.

However, floating point equality comparison with tolerance is not quite as simple as directly comparing absolute difference to machine epsilon. Any small epsilon is going to devolve the comparison into an equality comparison for large values, which leaves you with zero error tolerance.

Meaningful tolerant comparison, requires that you know what sort of values you're expecting, their magnitude, their sign, expected error that you wish to tolerate.

This blog explains the problem in intricate detail. It suggests following, which may be reasonable for "generic" comparison

bool AlmostEqualRelativeAndAbs(float A, float B,
            float maxDiff, float maxRelDiff = FLT_EPSILON)
{
    // Check if the numbers are really close -- needed
    // when comparing numbers near zero.
    float diff = fabs(A - B);
    if (diff <= maxDiff)
        return true;

    A = fabs(A);
    B = fabs(B);
    float largest = (B > A) ? B : A;

    if (diff <= largest * maxRelDiff)
        return true;
    return false;
}

The example is in C, but trivial to translate to C++ idioms. There is also an ULP based function in the article, but its implementation relies on union type punning that is not allowed in C++.

Upvotes: 1

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136515

One C++98 example:

#include <cmath>
#include <limits>
#include <iostream>

inline bool equal_with_tolerance(float a, float b, float tolerance = std::numeric_limits<float>::epsilon()) {
    return std::abs(a - b) < tolerance;
}

int main() {
    float a = 0.1f;
    float b = 0.1000001f;
    std::cout << (a == b) << '\n';                    // Outputs 0.
    std::cout << equal_with_tolerance(a, b) << '\n';  // Outputs 1.
}

tolerance depends on your problem domain, using std::numeric_limits<float>::epsilon is rarely adequate, see this for more details.

Upvotes: 1

Related Questions