瀏覽代碼

better fix for transitive principle

David Rose 23 年之前
父節點
當前提交
84cc0a8010

+ 1 - 1
panda/src/linmath/lmatrix3_src.cxx

@@ -139,7 +139,7 @@ fill(FLOATTYPE fill_value) {
 int FLOATNAME(LMatrix3)::
 compare_to(const FLOATNAME(LMatrix3) &other, FLOATTYPE threshold) const {
   for (int i = 0; i < 9; i++) {
-    if (!IS_THRESHOLD_EQUAL(_m.data[i], other._m.data[i], threshold)) {
+    if (!IS_THRESHOLD_COMPEQ(_m.data[i], other._m.data[i], threshold)) {
       return (_m.data[i] < other._m.data[i]) ? -1 : 1;
     }
   }

+ 1 - 8
panda/src/linmath/lmatrix4_src.cxx

@@ -129,17 +129,10 @@ convert_mat(CoordinateSystem from, CoordinateSystem to) {
 ////////////////////////////////////////////////////////////////////
 int FLOATNAME(LMatrix4)::
 compare_to(const FLOATNAME(LMatrix4) &other, FLOATTYPE threshold) const {
-  FLOATTYPE scale = 1.0f / threshold;
-
   // We compare values in reverse order, since the last row of the
   // matrix is most likely to be different between different matrices.
   for (int i = 15; i >= 0; i--) {
-    // We scale both elements into the same range and truncate, rather
-    // than comparing the absolute values of their differences with
-    // IS_THRESHOLD_EQUAL.  This prevents a slippery-slope effect
-    // where a == b and b == c but a != c.
-    if (cfloor(_m.data[i] * scale + 0.5) != 
-        cfloor(other._m.data[i] * scale + 0.5)) {
+    if (!IS_THRESHOLD_COMPEQ(_m.data[i], other._m.data[i], threshold)) {
       return (_m.data[i] < other._m.data[i]) ? -1 : 1;
     }
   }

+ 2 - 2
panda/src/linmath/lvecBase2_src.I

@@ -375,10 +375,10 @@ compare_to(const FLOATNAME(LVecBase2) &other) const {
 ////////////////////////////////////////////////////////////////////
 INLINE_LINMATH int FLOATNAME(LVecBase2)::
 compare_to(const FLOATNAME(LVecBase2) &other, FLOATTYPE threshold) const {
-  if (!IS_THRESHOLD_EQUAL(_v.v._0, other._v.v._0, threshold)) {
+  if (!IS_THRESHOLD_COMPEQ(_v.v._0, other._v.v._0, threshold)) {
     return (_v.v._0 < other._v.v._0) ? -1 : 1;
   }
-  if (!IS_THRESHOLD_EQUAL(_v.v._1, other._v.v._1, threshold)) {
+  if (!IS_THRESHOLD_COMPEQ(_v.v._1, other._v.v._1, threshold)) {
     return (_v.v._1 < other._v.v._1) ? -1 : 1;
   }
   return 0;

+ 3 - 3
panda/src/linmath/lvecBase3_src.I

@@ -422,13 +422,13 @@ compare_to(const FLOATNAME(LVecBase3) &other) const {
 ////////////////////////////////////////////////////////////////////
 INLINE_LINMATH int FLOATNAME(LVecBase3)::
 compare_to(const FLOATNAME(LVecBase3) &other, FLOATTYPE threshold) const {
-  if (!IS_THRESHOLD_EQUAL(_v.v._0, other._v.v._0, threshold)) {
+  if (!IS_THRESHOLD_COMPEQ(_v.v._0, other._v.v._0, threshold)) {
     return (_v.v._0 < other._v.v._0) ? -1 : 1;
   }
-  if (!IS_THRESHOLD_EQUAL(_v.v._1, other._v.v._1, threshold)) {
+  if (!IS_THRESHOLD_COMPEQ(_v.v._1, other._v.v._1, threshold)) {
     return (_v.v._1 < other._v.v._1) ? -1 : 1;
   }
-  if (!IS_THRESHOLD_EQUAL(_v.v._2, other._v.v._2, threshold)) {
+  if (!IS_THRESHOLD_COMPEQ(_v.v._2, other._v.v._2, threshold)) {
     return (_v.v._2 < other._v.v._2) ? -1 : 1;
   }
   return 0;

+ 4 - 4
panda/src/linmath/lvecBase4_src.I

@@ -449,16 +449,16 @@ compare_to(const FLOATNAME(LVecBase4) &other) const {
 ////////////////////////////////////////////////////////////////////
 INLINE_LINMATH int FLOATNAME(LVecBase4)::
 compare_to(const FLOATNAME(LVecBase4) &other, FLOATTYPE threshold) const {
-  if (!IS_THRESHOLD_EQUAL(_v.v._0, other._v.v._0, threshold)) {
+  if (!IS_THRESHOLD_COMPEQ(_v.v._0, other._v.v._0, threshold)) {
     return (_v.v._0 < other._v.v._0) ? -1 : 1;
   }
-  if (!IS_THRESHOLD_EQUAL(_v.v._1, other._v.v._1, threshold)) {
+  if (!IS_THRESHOLD_COMPEQ(_v.v._1, other._v.v._1, threshold)) {
     return (_v.v._1 < other._v.v._1) ? -1 : 1;
   }
-  if (!IS_THRESHOLD_EQUAL(_v.v._2, other._v.v._2, threshold)) {
+  if (!IS_THRESHOLD_COMPEQ(_v.v._2, other._v.v._2, threshold)) {
     return (_v.v._2 < other._v.v._2) ? -1 : 1;
   }
-  if (!IS_THRESHOLD_EQUAL(_v.v._3, other._v.v._3, threshold)) {
+  if (!IS_THRESHOLD_COMPEQ(_v.v._3, other._v.v._3, threshold)) {
     return (_v.v._3 < other._v.v._3) ? -1 : 1;
   }
   return 0;

+ 9 - 9
panda/src/linmath/nearly_zero.h

@@ -40,18 +40,18 @@ get_nearly_zero_value(float) {
   ((value) < (threshold) && (value) > -(threshold))
 
 // IS_THRESHOLD_EQUAL(value1, value2, threshold) returns true if the
-// two values are within threshold of each other.  The transitive
-// principle is guaranteed: IS_THRESHOLD_EQUAL(a, b, t) &&
-// IS_THRESHOLD_EQUAL(b, c, t) implies IS_THRESHOLD_EQUAL(a, c, t).
-
-// We could define this via IS_THRESHOLD_ZERO(a - b, t) that wouldn't
-// guarantee the transitive principle, stated above.  So we need a
-// more complex definition that rounds these to the nearest multiples
-// of threshold before comparing them.
+// 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.