// Filename: nearly_zero.h // Created by: drose (08Mar00) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) Carnegie Mellon University. All rights reserved. // // All use of this software is subject to the terms of the revised BSD // license. You should have received a copy of this license along // with this source code in a file named "LICENSE." // //////////////////////////////////////////////////////////////////// #ifndef NEARLY_ZERO_H #define NEARLY_ZERO_H #include "dtoolbase.h" // The following two functions are defined just to make the // NEARLY_ZERO() macro work. They each return a suitable nearly-zero // value for their corresponding numeric type. // Note that declaring these small numeric values first as a static // const identifier, and then returning the value of that identifier, // seems to lead to compilation errors (at least in VC7) in which // sometimes IS_THRESHOLD_COMPEQ(a, a, get_nearly_zero_value(a)) != 0. CONSTEXPR double get_nearly_zero_value(double) { return 1.0e-12; } CONSTEXPR float get_nearly_zero_value(float) { return 1.0e-6f; } CONSTEXPR int get_nearly_zero_value(int) { // This is a bit silly, but we should nevertheless define it in // case it is called for an integer type. return 0; } // IS_THRESHOLD_ZERO(value, threshold) returns true if the value is // within threshold of zero. #define IS_THRESHOLD_ZERO(value, threshold) \ ((value) < (threshold) && (value) > -(threshold)) // IS_THRESHOLD_EQUAL(value1, value2, threshold) returns true if the // two values are within threshold of each other. #define IS_THRESHOLD_EQUAL(value1, value2, threshold) \ (IS_THRESHOLD_ZERO((value1) - (value2), threshold)) // IS_THRESHOLD_COMPEQ(value1, value2, threshold) returns true if // the two values are equal within threshold tolerance. Unlike // IS_THRESHOLD_EQUAL, the transitive principle is guaranteed: // IS_THRESHOLD_COMPEQ(a, b, t) && IS_THRESHOLD_COMPEQ(b, c, t) // implies IS_THRESHOLD_COMPEQ(a, c, t). #define IS_THRESHOLD_COMPEQ(value1, value2, threshold) \ (cfloor(value1 / threshold + 0.5f) == cfloor(value2 / threshold + 0.5f)) // NEARLY_ZERO(float) returns a number that is considered to be so // close to zero as not to matter for a float. NEARLY_ZERO(double) // returns a similar, smaller number for a double. #define NEARLY_ZERO(FLOATTYPE) (get_nearly_zero_value((FLOATTYPE)0)) // IS_NEARLY_ZERO(value) returns true if the value is very close to // zero. #define IS_NEARLY_ZERO(value) \ (IS_THRESHOLD_ZERO(value, get_nearly_zero_value(value))) // IS_NEARLY_EQUAL(value1, value2) returns true if the two values are // very close to each other. #define IS_NEARLY_EQUAL(value1, value2) \ (IS_THRESHOLD_EQUAL(value1, value2, get_nearly_zero_value(value1))) // MAYBE_ZERO(value) returns 0 if the value is nearly zero, and the // value itself otherwise. #define MAYBE_ZERO(value) \ (IS_NEARLY_ZERO(value) ? 0 : (value)) #endif