diff --git a/panda/src/linmath/lmatrix3_src.cxx b/panda/src/linmath/lmatrix3_src.cxx index 400037c749..bd1d1822df 100644 --- a/panda/src/linmath/lmatrix3_src.cxx +++ b/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; } } diff --git a/panda/src/linmath/lmatrix4_src.cxx b/panda/src/linmath/lmatrix4_src.cxx index bb09dbbbbb..0bb19e1ab3 100644 --- a/panda/src/linmath/lmatrix4_src.cxx +++ b/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; } } diff --git a/panda/src/linmath/lvecBase2_src.I b/panda/src/linmath/lvecBase2_src.I index 11888aea7b..7c89775f1a 100644 --- a/panda/src/linmath/lvecBase2_src.I +++ b/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; diff --git a/panda/src/linmath/lvecBase3_src.I b/panda/src/linmath/lvecBase3_src.I index bd2ab62ce1..d726ddb27c 100644 --- a/panda/src/linmath/lvecBase3_src.I +++ b/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; diff --git a/panda/src/linmath/lvecBase4_src.I b/panda/src/linmath/lvecBase4_src.I index 72d4d3e5cf..d1ff210145 100644 --- a/panda/src/linmath/lvecBase4_src.I +++ b/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; diff --git a/panda/src/linmath/nearly_zero.h b/panda/src/linmath/nearly_zero.h index c394ffa662..a97b0bd9f2 100644 --- a/panda/src/linmath/nearly_zero.h +++ b/panda/src/linmath/nearly_zero.h @@ -40,17 +40,17 @@ 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) \ - (cfloor(value1 / threshold + 0.5f) == cfloor(value2 / threshold + 0.5f)) + (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)