Floating-point compares can be more expensive than plain integer compares, especially if you have no dedicated floating-point hardware.
Fortunately, you can utilize integer comparison when comparing floating-point numbers, under some cases:
1) This only works when using the IEEE754 floating-point format.
2) It does not work for NaN:s.
Accessing the underlying representation is underfined behaviour, as the C language does not specify which floating-point format it uses.
Anyway, the trick is that it only works as long as the floating-point numbers have the same sign. And, in that case, comparing the integer representation of two negative floating-point number is the inverse of comparing the floating-point numbers themselves.
I haven't performance measured the code below, but chances are that it is faster than your original code. Please let me know the performance gain, if any!
int compareAB(float a_orig, float b_orig)
{
/* Get the underlying representation of A and B. */
long a = *(unsigned long *)&a_orig;
long b = *(unsigned long *)&b_orig;
if (a < 0)
{
if (b < 0)
{
/* Both are negative. The order of the integer representation is
* the OPPOSITE of the order of the floating-point value. */
if (a > b)
{
return -1;
}
else if (a < b)
{
return 1;
}
else
{
return 0;
}
}
else
{
/* A is negative, B isn't => A is smaller. */
return -1;
}
}
else if (b < 0)
{
/* B is negative, A isn't => B is smaller. */
return 1;
}
else
{
/* Both are positive. */
if (a > b)
{
return 1;
}
else if (a < b)
{
return -1;
}
else
{
return 0;
}
}
}
You can test this with:
#include <stdio.h>
float values[] = {-100.0F,
-50.0F,
0.0F,
50.0F,
100.0F };
void test(float a, float b)
{
const char * p = 0;
printf("%f is ", a);
switch (compareAB(a, b))
{
case -1: p = "smaller than"; break;
case 0: p = "equal to"; break;
case 1: p = "greater than"; break;
}
printf("%s %f\n", p, b);
}
int main(void)
{
int i;
for (i = 0; i < sizeof(values)/sizeof(values[0]); ++i)
{
int j;
for (j = 0; j < sizeof(values)/sizeof(values[0]); ++j)
{
test(values[i], values[j]);
}
}
}
It gives the same output as when using your original code, namely:
-100.000000 is equal to -100.000000
-100.000000 is smaller than -50.000000
-100.000000 is smaller than 0.000000
-100.000000 is smaller than 50.000000
-100.000000 is smaller than 100.000000
-50.000000 is greater than -100.000000
-50.000000 is equal to -50.000000
-50.000000 is smaller than 0.000000
-50.000000 is smaller than 50.000000
-50.000000 is smaller than 100.000000
0.000000 is greater than -100.000000
0.000000 is greater than -50.000000
0.000000 is equal to 0.000000
0.000000 is smaller than 50.000000
0.000000 is smaller than 100.000000
50.000000 is greater than -100.000000
50.000000 is greater than -50.000000
50.000000 is greater than 0.000000
50.000000 is equal to 50.000000
50.000000 is smaller than 100.000000
100.000000 is greater than -100.000000
100.000000 is greater than -50.000000
100.000000 is greater than 0.000000
100.000000 is greater than 50.000000
100.000000 is equal to 100.000000