better fix for transitive principle

This commit is contained in:
David Rose 2002-06-06 16:57:58 +00:00
parent c27920c40f
commit 84cc0a8010
6 changed files with 20 additions and 27 deletions

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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)