简体   繁体   中英

Printing floating-point values with full precision with Catch2

I have some test code using , that does check wether some computation returns a floating-point null value.

CHECK( someFunc() == 0. );

The problem is that when the test fails because of very small non-null value (say 1.234E-16), the values are printed with "default" printing, and I see:

my_test.cpp:351: FAILED:
  CHECK( someFunc() == 0.0 )
with expansion:
  0.0 == 0.0

which is pretty much useless. What I would like to see is:

my_test.cpp:351: FAILED:
  CHECK( someFunc() == 0.0 )
with expansion:
  1.234E-16 == 0.0

I tried streaming std::scientific in std::cout just before the test but apparently Catch using another printing method.

Any idea ?

Side note: Actually, I use the provided Approx class but this is not related to my problem

Edit : The problem here is not about the comparison itself (I know all the evil things about floating-point values), it is only about how I can tell Catch to print the handled values.

Update : You can now specify precision in Catch2 . The following applies for older versions of Catch2.

It looks like the precision is hard-coded within Catch2 itself:

std::string StringMaker<float>::convert(float value) {
    return fpToString(value, 5) + 'f';
}
std::string StringMaker<double>::convert(double value) {
    return fpToString(value, 10);
}

There are two options to fix this:

Option 1: Modify Catch2

If you modify that, you can make it show what you want (note: <limits> is already included within catch, so I'll use std::numeric_limits ):

std::string StringMaker<float>::convert(float value) {
    return fpToString(value, std::numeric_limits<float>::max_digits10) + 'f';
}
std::string StringMaker<double>::convert(double value) {
    return fpToString(value, std::numeric_limits<double>::max_digits10);
}

A more sophisticated approach could be made to have this be a parameter the user can set rather than hard-coding it to a different semi-arbitrary value, but this is only a Q&A, not a pull request. ;-)

Option 2: Log it yourself in higher precision

If you add INFO( FullPrecision(d) ); before the REQUIRE() call, you'll get a full precision print, but only when the test case fails. (See definition of FullPrecision() below.)

Both of these changes are demonstrated here:

#define CATCH_CONFIG_MAIN  // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"
#include <limits>
#include <sstream>
#include <iomanip>

double GetDouble() { return std::numeric_limits<double>::epsilon(); }

std::string FullPrecision( double d )
{
    auto s = std::ostringstream{};
    s << std::setprecision( std::numeric_limits<double>::max_digits10 ) << d;
    return s.str();
}

TEST_CASE( "Double, double, toil and trouble", "[double]" ) 
{
    const auto d = GetDouble();
    INFO( FullPrecision(d) );
    REQUIRE( 0.0 == d );
}

which prints:

prog.cc:20: FAILED:
  REQUIRE( 0.0 == d )
with expansion:
  0.0 == 0.00000000000000022
with message:
  2.2204460492503131e-16

Modifying Catch2 causes the expansion 0.0 == 0.00000000000000022 , and adding the INFO() causes the message 2.2204460492503131e-16 .

See it live on Wandbox .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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