简体   繁体   English

如何比较catch2中的浮点数

[英]How to compare floating point in catch2

I am using Catch v2.13.1我正在使用 Catch v2.13.1

What is the correct way to compare float values.比较浮点值的正确方法是什么。 I thought the below would fail, but both pass.我认为下面会失败,但都通过了。

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

However this fails as expected然而,这如预期的那样失败

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

I don't understand why the first two statements wouldn't work我不明白为什么前两个语句不起作用

There are a couple of things to consider in the posted example.在发布的示例中有几件事情需要考虑。

REQUIRE(1147332687.7189338 == Approx(1147332688.4281545));

This will pass, "unexpectedly".这将通过,“出乎意料”。 The reason can be found in the documentation ( assertions - floating point comparisons ).原因可以在文档中找到( 断言 - 浮点比较)。

Approx is constructed with defaults that should cover most simple cases. Approx是用默认值构建的,应该涵盖最简单的情况。 For the more complex cases, Approx provides 3 customization points:对于更复杂的情况,Approx 提供了 3 个定制点:

  • epsilon - epsilon serves to set the coefficient by which a result can differ from Approx 's value before it is rejected. epsilon - epsilon 用于设置一个系数,通过该系数,结果在被拒绝之前可以与Approx的值不同。 By default set to std::numeric_limits<float>::epsilon()*100 .默认设置为std::numeric_limits<float>::epsilon()*100
  • [...] [...]

In the posted example, the two numbers differ by a cofficient near 6.2e-10, while the default is (given a 32-bit float) near 1.2e-5.在发布的示例中,两个数字的不同系数接近 6.2e-10,而默认值(给定 32 位浮点数)接近 1.2e-5。

The following test wouldn't pass.下面的测试不会通过。

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

The other tests involve margin , which is described in the documentation as其他测试涉及margin ,在文档中描述为

  • margin - margin serves to set the the absolute value by which a result can differ from Approx's value before it is rejected.边距- 边距用于设置结果在被拒绝之前与 Approx 值不同的绝对值。 By default set to 0.0.默认设置为 0.0。

The caveat, though, can be found in issue#1507 .但是,可以在issue#1507 中找到警告。

This is because of the default value for epsilon in the Approx class and the fact that Approx::equalityComparisonImpl will pass if the value is in the range of the margin OR the epsilon values.这是因为 Approx 类中 epsilon 的默认值以及如果该值在边距epsilon 值的范围内 Approx::equalityComparisonImpl 将通过的事实。

So, this test wouldn't pass:所以,这个测试不会通过:

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

Note that this "issue" seems to be marked as resolved - not a bug:请注意,这个“问题”似乎被标记为已解决- 不是错误:

So, I don't think this is a bug.所以,我不认为这是一个错误。

The reason for this is that it is very hard (well, impossible), to determine the user's intent, thus it is better to assume that the user has set up both checks correctly -- after all, if the user does not want a relative comparison, they can always set the epsilon to zero.这样做的原因是很难(好吧,不可能)确定用户的意图,因此最好假设用户已正确设置了两个检查——毕竟,如果用户不想要一个亲戚比较,他们总是可以将 epsilon 设置为零。 In fact, I think that using both tolerances and taking the most forgiving one is the superior option to implement things like the Approx Matcher ( #1499 ).事实上,我认为同时使用容差并采用最宽容的容差是实现 Approx Matcher ( #1499 ) 之类的最佳选择。

I think I found out why this happens, but I don't know how to make it work in Catch.我想我找到了为什么会发生这种情况,但我不知道如何让它在 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;
}

Outputs this:输出这个:

1147332687.7189338
1147332688.4281545
1.14733274e+09
1.14733274e+09

So clearly floats are not good enough to distinguish these numbers but doubles are.很明显,浮点数不足以区分这些数字,但双精度数是。 It seems that Catch uses floats internally; Catch 内部似乎使用了浮点数; the test passes even when I try to force it to use doubles.即使我试图强制它使用双打,测试也通过了。 But maybe there is something I missed?但也许我错过了什么?

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

So no fix, but at least you now know why you get those strange results.所以没有修复,但至少你现在知道为什么会得到那些奇怪的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM