Search code examples
c++floating-pointdoubleprecision

What is correct way to compare 2 doubles values?


There are a lot of articles, PhD publications, books and question here on this topic, still my question will be pretty straightforward.

How can we improve this or workaround without writing dozens of ifs?

Suppose I have 2 doubles;

double d1 = ..;
double d2 = ..;

The most naïve think we can try to do is to try if(d1==d2) // baaaad!!!, as we know we can fail on precision mismatches on very close values.

Second naïve thing can be if(std::abs(d1-d2) < std::numeric_limits<double>::epsilon())
This still fails for relatively big doubles as std::numeric_limits<double>::epsilon() described as follows:

Returns the machine epsilon, that is, the difference between 1.0 and the next value representable by the floating-point type T

Which for double is 0.00000000000000022204

So I came up with this:

double epsilon = std::max(d1,d2)/1E14; // I am ok with precision mismatch after 14th digit, regardless how big the number is.

The problem here is that for small numbers this fails, for instance this prints 0.00..00

double d = 1E-7;  
std::cout<<std::fixed<<std::setprecision(20)<< d/1E14;

So the question will be is there a generic solution/workaround for this, or I should write dozens of ifs to decide my denomination properly in order not to overkill the precicion?


Solution

  • So the question will be is there a generic solution/workaround for this

    There will not be a universal solution for finite precision floating point that would apply to all use cases. There cannot be, because the correct threshold is specific to each calculation, and cannot generally be known automatically.

    You have to know what you are comparing and what you are expecting from the comparison. Full explanation won't fit in this answer, but you can find most information from this blog: https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ (not mine).


    There is however a generic solution/workaround that side-steps the issue: Use infinite precision arithmetic. The C++ standard library does not provide an implementation of infinite precision arithmetic.