现代 C++ 中比较 double/float 是否相等的现代实践

Bru*_*ice 4 c++ floating-point c++11

if (std::abs(double1 - double2) < std::numeric_limits<double>::epsilon())
  std::cout<<"Equal";
else
  std::cout<<"Not equal";
Run Code Online (Sandbox Code Playgroud)

这段代码与现代 C++11/14/17/21 仍然是我们比较 float 和 double 的方式吗,或者现在只需编写就可以了

if (double1 == double2)
Run Code Online (Sandbox Code Playgroud)

编译器会为我们处理 epsilon 问题吗?

顺便说一句:在检查 epsilon 时,写 < 或 <= 更好吗?

Dre*_*ann 7

现代 C++11/14/17/21 的这段代码仍然是我们比较浮点型和双精度型的方式吗?或者现在只需编写就可以了,if (double1 == double2) 编译器将为我们处理 epsilon 问题?

这两种方法在现代 C++ 中的功能与在早期 C++ 中的功能相同。

这两种方法也都有缺陷。

  • 使用==假设您的代码已经考虑了任何浮点舍入错误,并且代码很少/很难做到这一点。

  • 与 epsilon 进行比较假设合理的舍入误差量将小于常数epsilon,这很可能是错误的假设!

    • 如果你的数字的大小大于2.0,你的 epsilon 技巧将与直接比较没有什么不同,并且具有相同的缺陷。无论您使用<还是<=.
    • 如果您的数字具有相同的符号且大小小于 epsilon,则您的 epsilon 技巧会说它们始终相等,即使一个比另一个大数百倍。它们也都等于零。

明智的方法可能是避免编写依赖于浮点数是否相等的代码。相反,通过某种因素测试它们是否相对接近。

下面的代码将测试两个数字是否彼此相差在 0.01% 左右。无论其规模如何。

const auto relative_difference_factor = 0.0001.    // 0.01%
const auto greater_magnitude = std::max(std::abs(double1),std::abs(double2));

if ( std::abs(double1-double2) < relative_difference_factor * greater_magnitude )
  std::cout<<"Relatively close";
else
  std::cout<<"Not relatively close";
Run Code Online (Sandbox Code Playgroud)