首页 > 解决方案 > 如何比较catch2中的浮点数

问题描述

我正在使用 Catch v2.13.1

比较浮点值的正确方法是什么。我认为下面会失败,但都通过了。

REQUIRE(1147332687.7189338 == Approx(1147332688.4281545).margin(0.0001));
REQUIRE(1147332687.7189338 == Approx(1147332688.4281545));

然而,这如预期的那样失败

REQUIRE(abs(1147332687.7189338 - 1147332688.4281545) <= Approx(0).margin(0.0001));

我不明白为什么前两个语句不起作用

标签: c++catch-unit-testcatch2

解决方案


在发布的示例中有几件事需要考虑。

REQUIRE(1147332687.7189338 == Approx(1147332688.4281545));

这会“出乎意料地”过去。原因可以在文档中找到(断言 - 浮点比较)。

Approx使用应涵盖大多数简单情况的默认值构造。对于更复杂的情况,Approx 提供了 3 个自定义点:

  • epsilon - epsilon 用于设置结果Approx在被拒绝之前与 ' 值不同的系数。默认设置为std::numeric_limits<float>::epsilon()*100.
  • [...]

在发布的示例中,这两个数字的系数相差接近 6.2e-10,而默认值(给定 32 位浮点数)接近 1.2e-5。

以下测试不会通过。

CHECK( a == Approx(b).epsilon(1e-12) );

其他测试涉及margin,在文档中描述为

  • 边距- 边距用于设置结果在被拒绝之前可能与 Approx 的值不同的绝对值。默认设置为 0.0。

但是,可以在issue#1507中找到警告。

这是因为 Approx 类中 epsilon 的默认值以及 Approx::equalityComparisonImpl 如果值在边距epsilon 值的范围内将通过的事实。

所以,这个测试不会通过:

CHECK( a == Approx(b).margin(0.0001).epsilon(1e-12) );

请注意,这个“问题”似乎被标记为已解决——不是错误:

所以,我不认为这是一个错误。

这样做的原因是很难(嗯,不可能)确定用户的意图,因此最好假设用户已经正确设置了两个检查——毕竟,如果用户不想要一个亲戚相比之下,他们总是可以将 epsilon 设置为零。事实上,我认为同时使用容差并采用最宽容的容差是实现 Approx Matcher ( #1499 ) 之类的最佳选择。


推荐阅读