text: /**
   * 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."
   *
   * @file nearly_zero.h
   * @author drose
   * @date 2000-03-08
   */
  
  #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
  