2

我正在使用 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));

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

4

2 回答 2

2

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

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 ) 之类的最佳选择。

于 2020-09-30T15:36:55.577 回答
0

我想我发现了为什么会发生这种情况,但我不知道如何让它在 Catch 中工作。

这个:

#include <iostream>
#include <limits>
#include <iomanip>

int main()
{
    double a = 1147332687.7189338;
    double b = 1147332688.4281545;
    float c = 1147332687.7189338;
    float d = 1147332688.4281545;

    std::cout << std::setprecision(std::numeric_limits<decltype(a)>::max_digits10) << a << std::endl;
    std::cout << std::setprecision(std::numeric_limits<decltype(b)>::max_digits10) << b << std::endl;
    std::cout << std::setprecision(std::numeric_limits<decltype(c)>::max_digits10) << c << std::endl;
    std::cout << std::setprecision(std::numeric_limits<decltype(d)>::max_digits10) << d << std::endl;
}

输出这个:

1147332687.7189338
1147332688.4281545
1.14733274e+09
1.14733274e+09

很明显,浮点数不足以区分这些数字,但双精度数可以。似乎 Catch 在内部使用了浮点数;即使我试图强迫它使用双打,测试也通过了。但也许我错过了什么?

TEST_CASE("Test1")
{
    double d1 = 1147332687.7189338;
    double d2 = 1147332688.4281545;
    REQUIRE(d1 == Approx(d2));
}

所以没有解决办法,但至少你现在知道为什么会得到这些奇怪的结果。

于 2020-09-30T06:41:14.120 回答