J
jacob navia
Thomas said:Hi everyone,
To determine equality of two doubles a and b the following is often
done:
bool isEqual ( double a, double b ) {
return ( fabs (a-b) < THRESHOLD );
}
But this a approach usually fails if comparing doubles of different
magnitude since it's hard or not possible to find a suitable threshold
value. Since an double consists of mantissa, exponent and sign I
assume that the "best" way in this case would be to just "ignore" the
last few (e.g. 4-8 bits) of the mantissa to check for equality (at
least for the x86 architecture, which follow IEEE 754). Have someone
here ever tried to implement a similar approach? If yes, which
experiences have been made?
However my first approach to implement this failed. Can anyone tell
what I might have done wrong?
union IEEErepresentation {
long long man : 52;
int exp : 11;
int sign : 1;
};
union IEEEdouble {
double d;
IEEErepresentation c;
};
const int number_of_bits_to_ignore = 8;
bool isEqual (double a, double b) {
IEEEdouble aa, bb;
aa.d = a;
bb.d = b;
return ((aa.c.man << number_of_bits_to_ignore) == (bb.c.man <<
number_of_bits_to_ignore));
}
int main() {
string a = isEqual (1324.5678901234, 1324.5678901256 ) ? "true" :
"false";
string b = isEqual (134.5678901234, 134.5678901256 ) ? "true" :
"false";
string c = isEqual (.5678901234, .5678901256 ) ? "true" : "false";
string d = isEqual (1324.5678901234, 124.5678901256 ) ? "true" :
"false";
string e = isEqual (134.5678901234, 134.5178901256 ) ? "true" :
"false";
string f = isEqual (.5678901234, .3678901256 ) ? "true" : "false";
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
cout << "d = " << d << endl;
cout << "e = " << e << endl;
cout << "f = " << f << endl;
return 0;
}
Thanks in advance,
Thomas Kowalski
The lcc-win32 compiler system provides fcmp:
--------------------------------------------------------cut here
/*
fcmp
Copyright (c) 1998-2000 Theodore C. Belding
University of Michigan Center for the Study of Complex Systems
<mailto:[email protected]>
<http://www-personal.umich.edu/~streak/>
This file is part of the fcmp distribution. fcmp is free software;
you can redistribute and modify it under the terms of the GNU Library
General Public License (LGPL), version 2 or later. This software
comes with absolutely no warranty. See the file COPYING for details
and terms of copying.
File: fcmp.c
Description: see fcmp.h and README files.
Knuth's floating point comparison operators, from:
Knuth, D. E. (1998). The Art of Computer Programming.
Volume 2: Seminumerical Algorithms. 3rd ed. Addison-Wesley.
Section 4.2.2, p. 233. ISBN 0-201-89684-2.
Input parameters:
x1, x2: numbers to be compared
epsilon: determines tolerance
epsilon should be carefully chosen based on the machine's precision,
the observed magnitude of error, the desired precision, and the
magnitude of the numbers to be compared. See the fcmp README file for
more information.
This routine may be used for both single-precision (float) and
double-precision (double) floating-point numbers.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "fcmp.h"
#include <math.h>
int EXPORT fcmp(double x1, double x2, double epsilon) {
int exponent;
double delta;
double difference;
/* Get exponent(max(fabs(x1), fabs(x2))) and store it in exponent. */
/* If neither x1 nor x2 is 0, */
/* this is equivalent to max(exponent(x1), exponent(x2)). */
/* If either x1 or x2 is 0, its exponent returned by frexp would be 0, */
/* which is much larger than the exponents of numbers close to 0 in */
/* magnitude. But the exponent of 0 should be less than any number */
/* whose magnitude is greater than 0. */
/* So we only want to set exponent to 0 if both x1 and */
/* x2 are 0. Hence, the following works for all x1 and x2. */
frexp(fabs(x1) > fabs(x2) ? x1 : x2, &exponent);
/* Do the comparison. */
/* delta = epsilon * pow(2, exponent) */
/* Form a neighborhood around x2 of size delta in either direction. */
/* If x1 is within this delta neighborhood of x2, x1 == x2. */
/* Otherwise x1 > x2 or x1 < x2, depending on which side of */
/* the neighborhood x1 is on. */
delta = ldexp(epsilon, exponent);
difference = x1 - x2;
if (difference > delta)
return 1; /* x1 > x2 */
else if (difference < -delta)
return -1; /* x1 < x2 */
else /* -delta <= difference <= delta */
return 0; /* x1 == x2 */
}
#ifdef TEST
#include <float.h>
#include <stdio.h>
#define ASSERT assert
#include <assert.h>
int main() {
int result;
ASSERT ( fcmp (1234567890123456, 1234567890123457 ,DBL_EPSILON) );
ASSERT ( fcmp (1.234567890123456, 1.234567890123457 ,DBL_EPSILON) );
ASSERT ( fcmp (0.000001234567890123456,
0.000001234567890123457,DBL_EPSILON ) );
return 0;
}
#endif
---------------------------------------------------------end of fcmp.c