0

How to compare two different floats, to a certain degree of accuracy. I know that there are very slight imprecisions while using floats or doubles in any programming language, but which may however, be enough to cause this comparison of floats a < b to return a different value than it actually should.

I was solving a problem from the UVa Online Judge which gave me a Wrong Answer many times. It took few float values as input, albeit, to 2 decimal places. I figured out the makeshift solution, which was by splitting the input and converting it to ints, but I wouldn't prefer to use that always.

So my question is, what's the best way to compare whether a float a is lesser (or greater) than a float b, provided that the inputs of a and b are given correct to n decimal places, in this case, 2?

The language I prefer is C++.

SinByCos
  • 613
  • 1
  • 10
  • 22
  • [how-should-i-do-floating-point-comparison](https://stackoverflow.com/questions/4915462/how-should-i-do-floating-point-comparison) – HDJEMAI Mar 31 '17 at 02:57
  • 1
    I haven't experienced errors caused by float precisions so far (I don't think questions will push it to the precision limit). Your code is somewhat buggy in anywhere else. – Tatsuyuki Ishi Mar 31 '17 at 02:59
  • @TatsuyukiIshi I don't really think so. I just changed the floats to ints, and split the input to convert it to ints, and it miraculously gave an AC verdict. :/ – SinByCos Mar 31 '17 at 03:09
  • 1
    `a < b` returns **exactly** the result that it should; it tells you whether the value of `a` is less than the value of `b` (unless you've got a NaN somewhere, but that's not what you're asking). The issue with floating-point comparisons is that the value that your code computed for `a` might not be the value that you expected because of rounding errors along the way. – Pete Becker Mar 31 '17 at 11:32

4 Answers4

0

Use std::numeric_limits<T>::epsilon() to check whether two numbers are almost equal. If you want to know whether one is greater/less you should also take into account the relative tolerance.

#include <cmath>
#include <limits>

template < typename T >
bool fuzzy_compare(T a, T b)
{
  return std::abs(a - b) < std::numeric_limits<T>::epsilon();
};
Henri Menke
  • 10,705
  • 1
  • 24
  • 42
  • 2
    The value of `epsilon()` is the smallest number that you can add to 1.0 and get a different value. When you're dealing with numbers significantly larger than 1.0 it's effectively 0 (because it gets lost in rounding), and when you're dealing with numbers significantly smaller than 1.0 it's effectively infinite (because it's much larger than the values you're looking at, so your values get lost in rounding). – Pete Becker Mar 31 '17 at 11:36
0

Just use math:

#define PREC 0.01                 //(1/pow(10,n)), n = 2
float c = a-b;
if (abs(c) < PREC) {
    printf("a equals b");
} else if(c < 0){
    printf("b is grater than a");
} else 
    printf("a is grater than b");
}
nopasara
  • 538
  • 3
  • 10
  • Your sample does not take numerical limits in consideration (by the way it's a C and not a C++ solution ;-) : printf, no namespaces, use of macro) – Semjon Mössinger Mar 31 '17 at 06:39
0

Use the setprecison() operator. The number you put in between the parentheses will determine how many numbers pass the decimal will be included in the output. Be sure to include the iomanip library.

Rod
  • 1
0

Comparing floats is alway a tricky Here is a more complicated example, showing why you should use std::numeric_limits<T>::epsilon().

  • The first line returns true, but the second returns false (on my machine).

    float64_t CalculateEpsilon ()
    {
        float64_t l_AllowedInaccuray = 1; // 1.1, 0.9
        int32_t significantDecimalPlaces = 2;
    
        return ( l_AllowedInaccuray * pow ( 0.1, significantDecimalPlaces ) );
    }
    
    bool IsEqual ( float64_t lhs, float64_t rhs )
    {
        float64_t l_Epsilon = CalculateEpsilon ();
    
        float64_t l_Delta = std::abs ( lhs - rhs );
        return l_Delta <= l_Epsilon;
    }
    
    int32_t main ()
    {
        std::cout << IsEqual ( 107.35999999999999, 107.350 );  //returns true
        std::cout << IsEqual ( 107.359999999999999, 107.350 ); //returns false
    
        return 0;
    }
    
Semjon Mössinger
  • 1,798
  • 3
  • 22
  • 32
  • "Nearly equal" can cause significant problems because it is not transitive. That is, if `a` "nearly equals" `b` and `b` "nearly equals" `c`, it does not follow that `a` "nearly equals" `c`. – Pete Becker Mar 31 '17 at 11:40