C++98 中的浮点数比较

Float comparison in C++98

我需要写一个float比较函数(equal/not equal)但是我最多只能用C++98和boost库。我知道浮点数比较应该包括 epsilon,但我不知道如何在不使用 C++11 的情况下编写此类代码。

一个 C++98 示例:

#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 取决于您的问题域,使用 std::numeric_limits<float>::epsilon 很少是足够的,请参阅 this 了解更多详细信息。

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

您可以使用 std::numeric_limits<float>::epsilon() 获得 "machine" epsilon。

然而,浮点数相等与公差的比较并不像直接将绝对差与机器 epsilon 进行比较那么简单。任何小的 epsilon 都会将比较转化为大值的相等比较,这使您的容错度为零。

有意义的容忍比较,要求您知道您期望什么样的值、它们的大小、它们的符号、您希望容忍的预期误差。

blog 详细解释了这个问题。它建议跟随,这可能是合理的 "generic" 比较

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;
}

示例是用 C 语言编写的,但翻译成 C++ 习语很简单。文章中还有一个基于ULP的函数,但是它的实现依赖于C++中不允许的联合类型双关。