4

After having gone through several articles on here and searching, there are many good solutions to comparing floating point numbers.

Such as the Boost library: http://www.boost.org/doc/libs/1_34_0/libs/test/doc/components/test_tools/floating_point_comparison.html

I have the Boost library available to me and so I want to use it. However, I am having trouble getting a simple example to show me how to get a boolean return value when comparing two floating point numbers.

For instance, they show examples like so: http://www.boost.org/doc/libs/1_50_0/libs/test/doc/html/utf/testing-tools/reference.html

But that doesn't return a boolean.

Psuedo code example:

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

I'm just having trouble finding out how to get a bool back.

I had been working mostly in Java, Python, and Matlab for a few years, so C++ is kind of like a foreign language to me right now.

Please help!

user3325798
  • 63
  • 1
  • 6

3 Answers3

3

You have to understand that what you have pointed to are boost unit test helper tools, so it may not be a good idea to rely on it outside of the testing domain.

And as a side note, in many cases simply comparing the floating point numbers to be within an epsilon of absolute distance (eg 1e-6) suffices. Otherwise, sure, the relative distance with respect to the magnitude of the comparands is necessary – when more precision is required.

But that doesn't return a boolean

Yes it returns boost::test_tools::predicate_result but you can evaluate and convert it to a boolean.

Notwithstanding the comment on boost test tools, if you do prefer to use the test library in the way you mentioned, here’s an example for you:

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

And if you need to implement the simpler comparison, you can always roll your own, along the lines of:

#include <cmath>
bool is_close(double a, double b, double epsilon = 1e-5) { 
    return std::fabs(a - b) < epsilon; 
}
mockinterface
  • 14,452
  • 5
  • 28
  • 49
  • (edit: Sorry for format, double space doesn't insert a line break) Thanks, I was so close; I wasn't picking up on the percetage type and was trying to pass it as a double. For the second example, I found a better equation in my searches: bool isEqualDouble(double a, double b) { static double DBL_EPSILON = std::numeric_limits::epsilon(); return fabs(a - b) <= 16 * DBL_EPSILON * fmax(fabs(a), fabs(b)); } – user3325798 Feb 20 '14 at 17:53
  • @user3325798 Re second example - that'd be correct, but largely only if you need this significant precision of comparison (it is around |a,b|*2e-1000). That's why I used both 1e-6 and 1e-5 in my answer - to show that you need to decide on the precision among possible precisions that suits your case. – mockinterface Feb 20 '14 at 20:36
  • Note: this no longer works with Boost 1.59. I had to use `boost::math::fpc::percent_tolerance`. – BenC Nov 12 '15 at 07:27
2

Can be done with no library/header dependency:

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

This is how I do it outside the test domain. It is lightweight and efficient as well as easy to implement and use.

misoboute
  • 298
  • 3
  • 4
1

polonium's answer can be improved so that you get a useful diagnostic when the comparison fails:

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;
}
legalize
  • 2,214
  • 18
  • 25