RajSanpui
RajSanpui

Reputation: 12094

C: Why fabs giving weird result while comparing floating point numbers?

I have a small simple code to compare 2 floating point numbers:

I tried using fabs but it gives wrong weird result. What is the mistake, and what is the correct form?

#include <stdio.h>
#include <stdlib.h>
#include <float.h>

void compareFloat(double a1, double a2)
{
   if(fabs(a1 - a2) < DBL_EPSILON)
       printf("a1 is smaller\n");
   else
       printf("a1 is larger\n");
}

int main()
{
 float a1=0.0000004f, a2=0.0005f;
 compareFloat(a1, a2);
}

What is the mistake in this code? It always prints a1 is smaller even if i set a1=0.004f and a2=0.0005f

Upvotes: 0

Views: 2270

Answers (3)

chux
chux

Reputation: 154208

fabs(a1 - a2) < DBL_EPSILON takes the "floating" out of floating point numbers (FP).

FP numbers are logarithmically distributed. fabs(a1 - a2) < DBL_EPSILON will always be false for large different numbers, even if a1,a2 are adjacent FP values. fabs(a1 - a2) < DBL_EPSILON is always true for small FP numbers, even when they differ by many magnitudes of value.

Instead, scale the epsilon.

Compare the 2 numbers into 5 results

void compareFloat(double a1, double a2) {
  if(a1 == a2) // Typically not performed is applications, but here for illustration.
   printf("a1 is exactly equal to a2\n");
  else if(fabs(a1 - a2) <= (DBL_EPSILON *fabs(a1)) )
   printf("a1 is nearly equal to a2\n");
  else if(a1 < a2)
   printf("a1 is smaller than a2\n");
  else if(a1 > a2)
    printf("a1 is larger than a2\n");
  else 
    printf("a1 is not comparable to a2, at least one of them is a Not-a-Number\n");
}

As others have said, be sure to use fabs() instead of abs().

Upvotes: 3

Kiril Kirov
Kiril Kirov

Reputation: 38173

That is mathematically wrong. You're actually trying to compare if both floats are equal, not larger/smaller.

To compare which one is larger, just use the operator<, for example like this:

if( abs(a1 - a2) > DBL_EPSILON && a1 < a2 )
// ....

Suppose: a1 == 1. and a2 == 5.. Then fabs( a1 - a2 ) will be larger than DBL_EPSILON, BUT this does not mean, that a1 > a2.


And the other error is already mentioned - abs is for integers, you need fabs.



EDIT: I'd create an additional function for comparing floating point numbers, for example:

bool areEqual( double x, double y )
{
     return ( fabs( x - y ) < DBL_EPSILON );
}

and then use it directly - will make your code more readable. Example usage:

if( areEqual( a1, a2 ) )
    // equal
else if( a1 < a2 )  // here, it's guaranteed, that a1 != a2, so it's safe now
    // a1 is smaller
else
    // a2 is smaller

Upvotes: 3

Bathsheba
Bathsheba

Reputation: 234865

The prototype for abs is an integer!

int abs (int number);

You want fabs for floating point

double fabs (double number);

Upvotes: 4

Related Questions