29

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?

kebs
  • 6,387
  • 4
  • 41
  • 70
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510

4 Answers4

35

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).

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
16

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));
marcin
  • 3,351
  • 1
  • 29
  • 33
1

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)); 
}
Jmbryan10
  • 79
  • 5
0

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()));
    }
gg99
  • 445
  • 6
  • 12