Canoe
Comprehensive Atmosphere N' Ocean Engine
fcmp.c
Go to the documentation of this file.
1 #include <float.h>
2 #include <math.h>
3 
4 /*
5  * Derived from fcmp(), version 1.2.2,
6  * Copyright (c) 1998-2000 Theodore C. Belding
7  * University of Michigan Center for the Study of Complex Systems
8  * <mailto:Ted.Belding@umich.edu>
9  * <http://fcmp.sourceforge.net>
10  *
11  * The major modification we have made is to remove the "epsilon" argument
12  * and set epsilon inside the fcmp() function.
13  *
14  * Description:
15  * It is generally not wise to compare two floating-point values for
16  * exact equality, for example using the C == operator. The function
17  * fcmp() implements Knuth's suggestions for safer floating-point
18  * comparison operators, from:
19  * Knuth, D. E. (1998). The Art of Computer Programming.
20  * Volume 2: Seminumerical Algorithms. 3rd ed. Addison-Wesley.
21  * Section 4.2.2, p. 233. ISBN 0-201-89684-2.
22  *
23  * Input parameters:
24  * x1, x2: numbers to be compared
25  *
26  * This routine may be used for both single and double precision.
27  *
28  * Returns:
29  * -1 if x1 < x2
30  * 0 if x1 == x2
31  * 1 if x1 > x2
32  */
33 
34 int fcmp(double x1, double x2) {
35  int exponent;
36  double delta, difference;
37  const double epsilon = DBL_EPSILON;
38 
39  /*
40  * Get exponent(max(fabs(x1),fabs(x2))) and store it in exponent.
41  *
42  * If neither x1 nor x2 is 0,
43  * this is equivalent to max(exponent(x1),exponent(x2)).
44  *
45  * If either x1 or x2 is 0, its exponent returned by frexp would be 0,
46  * which is much larger than the exponents of numbers close to 0 in
47  * magnitude. But the exponent of 0 should be less than any number
48  * whose magnitude is greater than 0.
49  *
50  * So we only want to set exponent to 0 if both x1 and x2 are 0.
51  * Hence, the following works for all x1 and x2.
52  */
53  frexp(fabs(x1) > fabs(x2) ? x1 : x2, &exponent);
54 
55  /*
56  * Do the comparison.
57  *
58  * delta = epsilon*pow(2,exponent)
59  *
60  * Form a neighborhood around x2 of size delta in either direction.
61  * If x1 is within this delta neighborhood of x2, x1 == x2.
62  * Otherwise x1 > x2 or x1 < x2, depending on which side of
63  * the neighborhood x1 is on.
64  */
65  delta = ldexp(epsilon, exponent);
66  difference = x1 - x2;
67 
68  if (difference > delta) {
69  /* x1 > x2 */
70  return 1;
71  } else if (difference < -delta) {
72  /* x1 < x2 */
73  return -1;
74  } else {
75  /* -delta <= difference <= delta */
76  return 0; /* x1 == x2 */
77  }
78 }
int fcmp(double x1, double x2)
Definition: fcmp.c:34