Печать значений с плавающей точкой с полной точностью с Catch2 - PullRequest
1 голос
/ 26 апреля 2019

У меня есть некоторый тестовый код, использующий , который проверяет, если некоторые вычисления возвращают нулевое значение с плавающей запятой.

CHECK( someFunc() == 0. );

Проблема заключается в том, что когда тест завершается неудачно из-заочень маленькое ненулевое значение (скажем, 1.234E-16), значения печатаются с печатью «по умолчанию», и я вижу:

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

, что в значительной степени бесполезно.То, что я хотел бы видеть:

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

Я пытался стримировать std::scientific в std::cout непосредственно перед тестом, но, очевидно, Catch, используя другой метод печати. ​​

Есть идеи?

Примечание: На самом деле я использую предоставленный класс Approx, но это не связано с моей проблемой

Редактировать : Проблема здесь не о самом сравнении (я знаю все зло о значениях с плавающей запятой), только о том, как я могу сказать Catch печатать обработанные значения.

1 Ответ

3 голосов
/ 26 апреля 2019

Обновление : Вы можете теперь указать точность в Catch2 .Следующее применимо к более старым версиям Catch2.

Похоже, что точность жестко задана в самом Catch2:

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

Есть два варианта, чтобы это исправить:

Вариант 1: Изменить Catch2

Если вы измените это, вы можете заставить его показывать то, что вы хотите (примечание: <limits> уже включен в catch, поэтому я буду использовать 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);
}

Можно сделать более изощренный подход, чтобы этот параметр мог быть задан пользователем, а не жестко задано его другое полупроизвольное значение, но это только вопросы и ответы,не тянуть запрос.; -)

Вариант 2: зарегистрируйте себя с более высокой точностью

Если вы добавите INFO( FullPrecision(d) ); перед вызовом REQUIRE(), вы получите полную точностьпечатать, но только в случае неудачи контрольного примера.(См. Определение FullPrecision() ниже.)

Оба эти изменения продемонстрированы здесь:

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

, который печатает:

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

Изменение Catch2 вызывает расширение0.0 == 0.00000000000000022, и добавление INFO() вызывает сообщение 2.2204460492503131e-16.

Посмотреть вживую на Wandbox .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...