Panda3D
 All Classes Functions Variables Enumerations
nearly_zero.h
1 // Filename: nearly_zero.h
2 // Created by: drose (08Mar00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #ifndef NEARLY_ZERO_H
16 #define NEARLY_ZERO_H
17 
18 #include "dtoolbase.h"
19 
20 // The following two functions are defined just to make the
21 // NEARLY_ZERO() macro work. They each return a suitable nearly-zero
22 // value for their corresponding numeric type.
23 
24 // Note that declaring these small numeric values first as a static
25 // const identifier, and then returning the value of that identifier,
26 // seems to lead to compilation errors (at least in VC7) in which
27 // sometimes IS_THRESHOLD_COMPEQ(a, a, get_nearly_zero_value(a)) != 0.
28 CONSTEXPR double
29 get_nearly_zero_value(double) {
30  return 1.0e-12;
31 }
32 
33 CONSTEXPR float
34 get_nearly_zero_value(float) {
35  return 1.0e-6f;
36 }
37 
38 CONSTEXPR int
39 get_nearly_zero_value(int) {
40  // This is a bit silly, but we should nevertheless define it in
41  // case it is called for an integer type.
42  return 0;
43 }
44 
45 
46 // IS_THRESHOLD_ZERO(value, threshold) returns true if the value is
47 // within threshold of zero.
48 #define IS_THRESHOLD_ZERO(value, threshold) \
49  ((value) < (threshold) && (value) > -(threshold))
50 
51 // IS_THRESHOLD_EQUAL(value1, value2, threshold) returns true if the
52 // two values are within threshold of each other.
53 #define IS_THRESHOLD_EQUAL(value1, value2, threshold) \
54  (IS_THRESHOLD_ZERO((value1) - (value2), threshold))
55 
56 // IS_THRESHOLD_COMPEQ(value1, value2, threshold) returns true if
57 // the two values are equal within threshold tolerance. Unlike
58 // IS_THRESHOLD_EQUAL, the transitive principle is guaranteed:
59 // IS_THRESHOLD_COMPEQ(a, b, t) && IS_THRESHOLD_COMPEQ(b, c, t)
60 // implies IS_THRESHOLD_COMPEQ(a, c, t).
61 #define IS_THRESHOLD_COMPEQ(value1, value2, threshold) \
62  (cfloor(value1 / threshold + 0.5f) == cfloor(value2 / threshold + 0.5f))
63 
64 // NEARLY_ZERO(float) returns a number that is considered to be so
65 // close to zero as not to matter for a float. NEARLY_ZERO(double)
66 // returns a similar, smaller number for a double.
67 #define NEARLY_ZERO(FLOATTYPE) (get_nearly_zero_value((FLOATTYPE)0))
68 
69 // IS_NEARLY_ZERO(value) returns true if the value is very close to
70 // zero.
71 #define IS_NEARLY_ZERO(value) \
72  (IS_THRESHOLD_ZERO(value, get_nearly_zero_value(value)))
73 
74 // IS_NEARLY_EQUAL(value1, value2) returns true if the two values are
75 // very close to each other.
76 #define IS_NEARLY_EQUAL(value1, value2) \
77  (IS_THRESHOLD_EQUAL(value1, value2, get_nearly_zero_value(value1)))
78 
79 
80 // MAYBE_ZERO(value) returns 0 if the value is nearly zero, and the
81 // value itself otherwise.
82 #define MAYBE_ZERO(value) \
83  (IS_NEARLY_ZERO(value) ? 0 : (value))
84 
85 
86 #endif
87