Question 14.5 in c-faq

A

Albert

Is there a reason for not mentioning FLT_EPSILON and DBL_EPSILON in
Question 14.5 in the c faq?
 
U

user923005

Is there a reason for not mentioning FLT_EPSILON and DBL_EPSILON in
Question 14.5 in the c faq?

You can use floating point epsilon for the comparison if you like,
such as:

#include <float.h>
#include <math.h>

int double_compare (double d1, double d2)
{
if (d1 > d2)
if ((d1 - d2) < fabs (d1 * DBL_EPSILON))
return 0;
else
return 1;
if (d1 < d2)
if ((d2 - d1) < fabs (d2 * DBL_EPSILON))
return 0;
else
return -1;
return 0;
}

int float_compare (float d1, float d2)
{
if (d1 > d2)
if ((d1 - d2) < fabsf (d1 * FLT_EPSILON))
return 0;
else
return 1;
if (d1 < d2)
if ((d2 - d1) < fabsf (d2 * FLT_EPSILON))
return 0;
else
return -1;
return 0;
}

#ifdef UNIT_TEST

#include <stdio.h>

int main ()
{
double u = 1.0;
double v = u + 1e-14;
double big = 1.0;
double a = 1.0, b = 0.99999999999999999999999999;
printf ("compare(%.*g, %.*g) = %d.\n", DBL_DIG+5, a, DBL_DIG+5, b,
double_compare (a, b));
a *= -1;
b *= -1;
printf ("compare(%.*g, %.*g) = %d.\n", DBL_DIG+5, a, DBL_DIG+5, b,
double_compare (a, b));

big *= 1 << 16;
big *= 1 << 16;
big *= 1 << 16;
big *= 1 << 16;


printf ("compare(%.*g, %.*g) = %d.\n", DBL_DIG+5, u, DBL_DIG+5, v,
double_compare (u, v));


u *= big;
v *= big;

printf ("compare(%.*g, %.*g) = %d.\n", DBL_DIG+5, u, DBL_DIG+5, v,
double_compare (u, v));

u = DBL_EPSILON;
v = -DBL_MAX;
printf ("compare(%.*g, %.*g) = %d.\n", DBL_DIG+5, u, DBL_DIG+5, v,
double_compare (u, v));

return 0;
}
/* One possible output:
compare(1, 1) = 0.
compare(-1, -1) = 0.
compare(1, 1.00000000000001) = -1.
compare(18446744073709552000, 18446744073709736000) = -1.
compare(2.2204460492503131e-016, -1.7976931348623157e+308) = 1.
*/
#endif


But you might prefer something like this also:

int double_compare(double d1, double d2)
{
if (d1 > d2)
if ((d1 - d2) < fabs(d1 * .000000000000001))
return 0;
else
return 1;
if (d1 < d2)
if ((d2 - d1) < fabs(d2 * .000000000000001))
return 0;
else
return -1;
return 0;
}

int float_compare(float d1, float d2)
{
if (d1 > d2)
if ((d1 - d2) < fabsf(d1 * .000001))
return 0;
else
return 1;
if (d1 < d2)
if ((d2 - d1) < fabsf(d2 * .000001))
return 0;
else
return -1;
return 0;
}

Or some other unit that you deem "small enough" to distinguish.

I don't have the book handy. He may have gone into more detail there,
I can't recall.
 
A

Albert

<snip>
I don't have the book handy.  He may have gone into more detail there,
I can't recall.

I'm referring to the online version, but 14.5 is probably in both
mediums.
 
L

ld

I'm referring to the online version, but 14.5 is probably in both
mediums.

A more general solution taking into account the two remarks would also
be useful:

int double_equal(double x, double y)
{
// absolute difference
double d = x-y;

if (d < 0) d = -d;
if (d < 2*DBL_MIN) return 1;

// relative difference
if (x < 0) x = -x;
if (y < 0) y = -y;

return d <= (x > y ? x : y) * 2*DBL_EPSILON;
}

a+, ld.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top