【问题标题】:How to compare floating point in catch2如何比较catch2中的浮点数
【发布时间】:2020-09-29 13:57:45
【问题描述】:

我正在使用 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-test catch2


【解决方案1】:

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

REQUIRE(1147332687.7189338 == Approx(1147332688.4281545));

这会“出乎意料地”通过。原因可以在文档中找到(assertions - floating point comparisons)。

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

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

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

以下测试不会通过。

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

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

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

不过,可以在 issue#1507 中找到警告。

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

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

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

请注意,这个“问题”似乎被标记为resolved - 不是错误:

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

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

【讨论】:

  • 谢谢,如果根据设置的 epsilon 有不正确的行为,我不明白为什么会存在保证金。
  • @Inquisitor 是的,这是一个值得商榷的设计选择,恕我直言。不过,稳健的浮点比较是一种深奥的艺术,请参见例如stackoverflow.com/questions/5595425/… 和那里的链接。
【解决方案2】:

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

This:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 2017-02-15
    • 2011-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多