Использование сравнения Boost с плавающей запятой для получения возвращаемого значения bool

После просмотра нескольких статей здесь и поиска было найдено много хороших решений для сравнения чисел с плавающей запятой.

Например, библиотека Boost: http://www.boost.org/doc/libs/1_34_0/libs/test/doc/components/test_tools/floating_point_comparison.html

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

Например, они показывают такие примеры: http://www.boost.org/doc/libs/1_50_0/libs/test/doc/html/utf/testing-tools/reference.html

Но это не возвращает логическое значение.

Пример псевдокода:

double a = 1.0;
double b = 0.5+0.5;
double percentage = 0.00001; //0.001 %
//Now I want to use the boost library to do something like this:
bool isClose = check_is_close(a, b, percentage);

У меня просто проблемы с поиском, как получить bool обратно.

Несколько лет я работал в основном с Java, Python и Matlab, поэтому C++ сейчас для меня как иностранный язык.

Пожалуйста помоги!


person user3325798    schedule 19.02.2014    source источник


Ответы (3)


Вы должны понимать, что то, на что вы указали, является вспомогательными инструментами модульного тестирования Boost, поэтому, возможно, не стоит полагаться на него за пределами домена тестирования.

И в качестве примечания, во многих случаях достаточно просто сравнить числа с плавающей запятой, чтобы они находились в пределах эпсилон абсолютного расстояния (например, 1e-6). В противном случае, конечно, необходимо относительное расстояние по отношению к величине сравниваемых величин - когда требуется большая точность.

Но это не возвращает логическое значение

Да, он возвращает boost::test_tools::predicate_result, но вы можете оценить и преобразовать его в логическое значение.

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

#include <iostream>
#include <boost/test/floating_point_comparison.hpp>

int main() {
    bool b = boost::test_tools::check_is_close(
        0.01, 0.015, boost::test_tools::percent_tolerance(49.0));
    std::cout << std::boolalpha << b << std::endl; // false

    b = boost::test_tools::check_is_close(
        0.01, 0.015, boost::test_tools::percent_tolerance(51.0));
    std::cout << std::boolalpha << b << std::endl; // true, 51% tolerance is enough to ignore the difference
}

И если вам нужно реализовать более простое сравнение, вы всегда можете выполнить собственное сравнение, например:

#include <cmath>
bool is_close(double a, double b, double epsilon = 1e-5) { 
    return std::fabs(a - b) < epsilon; 
}
person mockinterface    schedule 19.02.2014
comment
(редактировать: извините за формат, двойной пробел не вставляет разрыв строки) Спасибо, я был так близок; Я не улавливал тип перцетажа и пытался передать его как двойной. Для второго примера я нашел лучшее уравнение в своих поисках: bool isEqualDouble(double a, double b) { static double DBL_EPSILON = std::numeric_limits‹double›::epsilon(); return fabs(a - b) ‹= 16 * DBL_EPSILON * fmax(fabs(a), fabs(b)); } - person user3325798; 20.02.2014
comment
@user3325798 user3325798 Второй пример - это было бы правильно, но в основном только в том случае, если вам нужна такая значительная точность сравнения (около |a,b|*2e-1000). Вот почему я использовал в своем ответе как 1e-6, так и 1e-5 - чтобы показать, что вам нужно определиться с точностью среди возможных точностей, которая подходит для вашего случая. - person mockinterface; 21.02.2014
comment
Примечание: это больше не работает с Boost 1.59. Мне пришлось использовать boost::math::fpc::percent_tolerance. - person BenC; 12.11.2015

Можно сделать без зависимости от библиотеки/заголовка:

inline bool is_close(double a, double b, double tolerance = 1e-5)
{ 
    return (a - b) * (a - b) < tolerance * tolerance;
}

Вот как я это делаю вне тестового домена. Он легкий и эффективный, а также простой в реализации и использовании.

person polonium    schedule 24.02.2015

ответ полония можно улучшить, чтобы получить полезную диагностику, когда сравнение не удается:

template <typename Number>
inline boost::test_tools::predicate_result isClose(Number a, Number b, Number tolerance = Number(1e-5))
{
    if ((a-b)*(a-b) < tolerance*tolerance)
    {
        return true;
    }

    boost::test_tools::predicate_result result(false);
    result.message() << a << " != " << b << " within " << tolerance;
    return result;
}
person legalize    schedule 01.04.2016