#ifndef ALMOST_H #define ALMOST_H #include #include #include class Almost { public: /* return 1 if x is between x1 and x2, including almost equality, else 0 */ static int between (double x, double x1, double x2) { return (Almost::cmp (x, x1) * Almost::cmp (x, x2) <= 0) ? 1 : 0; } /* return 0 if between x1 and x2, -1 if outside and closer to x1, * 1 if outside and closer to x2 */ static int outside (double x, double x1, double x2) { /* return 0 if between x1 and x2, -1 if outside and closer to x1, * 1 if outside and closer to x2 */ int i; if (Almost::between (x, x1, x2)) i = 0; else if (Almost::between (x1, x, x2)) i = -1; else if (Almost::between (x2, x, x1)) i = 1; return i; } /* return 1 if looks like a legitimate float, else 0 */ static int is_a_float (float r) { return ((fabs (r) < FLT_MAX) && (fabs (r) > FLT_MIN || Almost::zero (r))) ? 1 : 0; } /* return 1 if zero or very close to zero, for float precision */ static int zero (double r) { return (fabs (r) < 10. * FLT_MIN) ? 1 : 0; } /* return 1 if these are close to being equal for float precision, else 0 */ static int equal (double r1, double r2) { return (!Almost::cmp (r1, r2)) ? 1 : 0; } /* return 1 if r1>r2, -1 if r10)" for a strict r1>r2 */ static int cmp (double r1, double r2) { if (Almost::zero (r1) && Almost::zero (r2)) return 0; if (r1 - (10. * FLT_EPSILON) * fabs (r1) > r2 + (10. * FLT_EPSILON) * fabs (r2)) return 1; if (r1 + (10. * FLT_EPSILON) * fabs (r1) < r2 - (10. * FLT_EPSILON) * fabs (r2)) return -1; return 0; } /* take reciprocal and return large number if dividing by zero */ static double reciprocal (double a) { if (!Almost::zero (a)) a = 1. / a; else a = (a >= 0.) ? 0.1 * FLT_MAX : -0.1 * FLT_MAX; return a; } /* divide top by bottom, with clipping of overflow; 0/0 = 1 */ static double divide (double top, double bottom) { double sign; if ((top > 0. && bottom < 0.) || (top < 0. && bottom > 0.)) sign = -1.; else sign = 1.; top = fabs (top); // remove signs to simplify if's bottom = fabs (bottom); if (bottom >= 1. // Might underflow, but don't care. || top < bottom * 0.1 * FLT_MAX) // (bottom<1) and won't overflow return sign * top / bottom; // safe else if (Almost::equal (top, bottom)) { if (Almost::zero (top)) /* define 0/0 = 1 */ return 1.; else return sign; /* ratio is within precision of unity */ } else /* now top >= bottom*0.1*FLT_MAX, clip overflow */ return sign * 0.1 * FLT_MAX; } /* pseudo random number, idum is a seed */ static double ran0 (long *idum) { long k; double ans; static long IA = 16807, IM = 2147483647, IQ = 127773, IR = 2836, MASK = 123459876; static double AM = (1.0 / (IM)); *idum ^= MASK; k = (*idum) / IQ; *idum = IA * (*idum - k * IQ) - IR * k; if (*idum < 0) *idum += IM; ans = AM * ((double) (*idum)); *idum ^= MASK; return ans; } /* pseudo random number, keeps own static seed */ static double ran (void) { static long iseed = 294257; return Almost::ran0 (&iseed); } /* one plus a small number, detectable within float precision */ static double one_plus_epsilon (void) { return (1. + 15. * FLT_EPSILON); } /* a small number, detectable within float precision */ static double epsilon (void) { return (15. * FLT_MIN); } /* return 1 if corresponding entries are almost equal, else 0 */ static int equal_arrays (float *a1, float *a2, long n) { int same; long i; for (i = 0, same = 1; i < n && same; i++) { same = (same && Almost::equal (a1[i], a2[i])) ? 1 : 0; } return same; } /* return 1 if all appear to be floats */ static int float_arrays (float *a, long n) { int good; long i; for (i = 0, good = 1; i < n && good; i++) { good = (good && Almost::is_a_float (a[i])) ? 1 : 0; } return good; } }; #endif