如何在Catch框架中使用浮点公差

How to use floating point tolerances in the Catch framework?

本文关键字:Catch 框架      更新时间:2023-10-16

我使用的是Catch测试框架。

在介绍性的博客文章中,作者提到了以下功能:

  • 以易于使用的方式支持浮点公差

我找不到任何关于如何做到这一点的文档。Catch是如何做到这一点的?

这很简单。有一个名为Approx的类可以让你以一种可读性很强的方式进行测试:

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

可以使用Approx对象的成员函数epsilon()scale()来更改公差,如:Approx(a).epsilon(e)

自2011年4月以来,可自定义公差。Approx为此具有两个成员函数:epsilon()scale()。例如:

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

公差为ε×(scale+max(|a|,|b|((,其中scale默认为1,因此将通过:

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

我知道这是一个老问题,但我只是偶然发现了同样的问题,并找到了一个简单的解决方案。在定义Approvx类的Catch.hpp头文件中(在撰写本文时为2045行(,只需添加以下构造函数:

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 )
    {}

现在你可以这样做了:

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

需要注意的是,Approx现在被认为是不推荐使用的[来源]:

Approvx的缺点是它有几个问题在不破坏向后兼容性的情况下无法修复。因为Catch2还提供了一套完整的匹配器,用于实现不同的考虑了浮点比较方法,近似值保持原样已弃用,不应在新代码中使用。

从2.10版本开始,应该切换到使用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()));
    }