开发者

How to use floating point tolerances in the Catch framework?

开发者 https://www.devze.com 2023-03-21 05:21 出处:网络
I\'m using the Catch test framework. In the introductory blog post the author mentions the following feature:

I'm using the Catch test framework.

In the introductory blog post the author mentions the following feature:

  • Floating point tolerances supported in an easy to use way
开发者_运维知识库

I couldn't find any documentation on how to do this. How is this done in Catch?


It's simple. There is a class called Approx that lets you do this test in a very readable manner:

#include <limits>
TEST_CASE("demo/approx", "Approx demo") {
    double a = 1.0;
    double b = a + std::numeric_limits<double>::epsilon();
    REQUIRE_FALSE(b == a);
    REQUIRE(b == Approx(a));
}

The tolerance can be changed by using the member functions epsilon() and scale() of the Approx object, like so: Approx(a).epsilon(e).


The tolerance is has been customizable since Apr 2011. Approx has two member functions for this: epsilon() and scale(). For example:

REQUIRE(a == Approx(b).epsilon(my_eps));

The tolerance is ε × (scale+max(|a|, |b|)), where scale defaults to 1, so this will pass:

REQUIRE((2+2) == Approx(5).epsilon(0.17));


I know this is an old question, but I just stumbled upon the same problem and found a simple solution. In the Catch.hpp header file where the Approx class is defined (line 2045 at the time of writing), just add the following constructor:

class Approx {
public:
    explicit Approx( double value )
    :   m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
        m_scale( 1.0 ),
        m_value( value )
    {}

    explicit Approx( double value, double epsilon ) // <- New constructor
    :   m_epsilon( epsilon ),
        m_scale( 1.0 ),
        m_value( value )
    {}

Now you can do this:

TEST_CASE("demo/approx", "Approx demo") {
    double myTol = 0.1;
    double a = 1.0;
    double b = a + myTol;
    REQUIRE_FALSE(a == b);
    REQUIRE(a == Approx(b, myTol)); 
}


It is important to note that Approx is now considered deprecated [source]:

The downside to Approx is that it has a couple of issues that we cannot fix without breaking backwards compatibility. Because Catch2 also provides complete set of matchers that implement different floating point comparison methods, Approx is left as-is, is considered deprecated, and should not be used in new code.

As of version 2.10, one should switch to using Matchers.

    #include <limits>
    #include <catch2/matchers/catch_matchers_floating_point.hpp>

    TEST_CASE("demo/matchers", "Matchers demo") {
        double a = 1.0;
        double b = a + std::numeric_limits<double>::epsilon();
        REQUIRE_FALSE(b == a);
        REQUIRE_THAT(b, Catch::Matchers::WithinRel(a, std::numeric_limits<double>::epsilon()));
    }
0

精彩评论

暂无评论...
验证码 换一张
取 消