2

I've been reading this article by Bruce Dawson on how to compare floating point values. But all of his examples were checking if

  floatA == floatB. 

So I was wondering if there is a proper way to compare if either

  floatA > floatB 

or

  floatA <floatB.

Or is the < , > operator enough to consider the floating point values?

Edit: I'm not interesed in how to check for equals. I'm interested if there is a way to do checks for if one float value is smaller / greater than the other.

dwnenr
  • 443
  • 1
  • 4
  • 15
  • possible duplicate of [Most effective way for float and double comparison](http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison) – SingerOfTheFall Sep 23 '15 at 07:44
  • 2
    Less and greater work without any problems. – πάντα ῥεῖ Sep 23 '15 at 07:44
  • 1
    That page is no font of wisdom, and includes invalid code (which breaks strict aliasing rules). FWIW if you want to know if one floating pointer number is strictly less than another, yes, use '<'. – davmac Sep 23 '15 at 07:45
  • That article is _really_ old and breaks modern rules. There's a link at the very top of that article pointing to [here](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/) which is a lot better. – Mike Vine Sep 23 '15 at 09:53

3 Answers3

3

The issue with comparing floats for equality is that many number have no exact representation in binary floating point. For example 0.1 cannot be represented exactly in floating point, only a very very close approximation.

So when you take that approximation and multiply it by 10 you do not get exactly 1.0 as you might expect.

So if you write "if (0.1 * 10 == 1.0)" you won't get the result you expect, you'll get false most likely.

The same issue applies to less than and greater than.

"if (0.1 * 10 < 1.0) " - this should not be true because the values are equal. However in practice it probably will be true because 0.1 is an approximation that is very slightly smaller than 0.1 and multiplying it by 10 gives a value very slightly smaller than 1.0 making the test true when it shoulsd be false.

If your comparisons might be affected by this then you'll need to deal with it appropriately.

In may cases this is not an issue. if (distance_to_work < 10.0) // Probably not going to cause an issue But in some it might be

jcoder
  • 29,554
  • 19
  • 87
  • 130
  • Whether the answer is mathematically accurate is usually not so important with magnitude comparisons as it is with equality checks, which is why just a plain '<' or '>' is usually good enough. If you allow an epsilon for example you don't just make more right answers return true, you potentially also make more wrong answers true. The correct procedure for dealing with comparison on floats really hinges on how the numbers were derived and _why you are doing the comparison_. – davmac Sep 23 '15 at 07:56
0

Regardless of the way you compare floating point numbers for equality, make sure that other comparison operators are consistent with behavior of your equal operator.

In case of < you need to guarantee that !(a < b) && !(b < a) is the same as a == b.

Let's say, you implemented the following equal function:

const double EPSILON = 10e-8;

bool equal(double a, double b)
{
   return fabs(a - b) < EPSILON;
}

It is not always safe to use < operator, because it may get inconsistent result.

See

double a = 0.1 + 0.2;
double b = 0.3;

equal(a, b);  // true
a < b;        // false
b < a;        // TRUE

See, both b < a and equal(a, b) return true, and this is semantically incorrect.

The easiest way is to use your equal function to define less:

bool less(double a, double b)
{
   return a < b && !equal(a, b);
}

Now, it is consistent

double a = 0.1 + 0.2;
double b = 0.3;

equal(a, b);  // true
less(a, b);   // false
less(b, a);   // false

Use the same approach to define other operations (like greater, lessOrEq etc.). Such consistency will let you to avoid a bunch of subtle bugs in practice.

Stas
  • 11,571
  • 9
  • 40
  • 58
-2
bool AlmostEqual2sComplement(float A, float B, int maxUlps) 
{
// Make sure maxUlps is non-negative and small enough that the
// default NAN won't compare as equal to anything.
assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);
int aInt = *(int*)&A;
// Make aInt lexicographically ordered as a twos-complement int
if (aInt < 0)
    aInt = 0x80000000 - aInt;
// Make bInt lexicographically ordered as a twos-complement int
int bInt = *(int*)&B;
if (bInt < 0)
    bInt = 0x80000000 - bInt;
int intDiff = abs(aInt - bInt);
if (intDiff <= maxUlps)
    return true;
return false;
}
  • 4
    This code invokes undefined behavior. You're breaking the [strict aliasing rule](http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) in this line: `int aInt = *(int*)&A;` Also, this doesn't relate to the actual question, which was not about checking for near-equality. – davmac Sep 23 '15 at 07:46