Browse Source

Math: better isNormalized() implementation.

Comparing squared length to 1 is not sufficient to compare within range
[1 - epsilon, 1 + epsilon], as e.g. Quaternion with dot() = 1 + 1e-7
when converted to matrix has column vectors with dot() = 1 + 1e-6, which
is just above 1 + epsilon. Thus it's needed to compare sqrt(dot()) in
range [1 - epsilon, 1 + epsilon] or dot() in range [1 - 2*epsilon +
epsilon^2, 1 + 2*epsilon + epsilon^2]. Because epsilon^2 is way off
machine precision, it's omitted, thus dot() in all isNormalized()
implementations is now compared this way:

    abs(dot() - 1) < 2*epsilon;
pull/278/head
Vladimír Vondruš 13 years ago
parent
commit
ce6f999904
  1. 2
      src/Math/Complex.h
  2. 2
      src/Math/DualComplex.h
  3. 6
      src/Math/DualQuaternion.h
  4. 2
      src/Math/Quaternion.h
  5. 13
      src/Math/TypeTraits.h
  6. 2
      src/Math/Vector.h

2
src/Math/Complex.h

@ -156,7 +156,7 @@ template<class T> class Complex {
* @see dot(), normalized()
*/
inline bool isNormalized() const {
return TypeTraits<T>::equals(dot(), T(1));
return Implementation::isNormalizedSquared(dot());
}
/** @brief Real part */

2
src/Math/DualComplex.h

@ -135,7 +135,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see Complex::dot(), normalized()
*/
inline bool isNormalized() const {
return TypeTraits<T>::equals(this->real().dot(), T(1));
return Implementation::isNormalizedSquared(lengthSquared());
}
/**

6
src/Math/DualQuaternion.h

@ -141,7 +141,11 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @see lengthSquared(), normalized()
*/
inline bool isNormalized() const {
return lengthSquared() == Dual<T>(1);
/* Comparing dual part classically, as comparing sqrt() of it would
lead to overly strict precision */
Dual<T> a = lengthSquared();
return Implementation::isNormalizedSquared(a.real()) &&
TypeTraits<T>::equals(a.dual(), T(0));
}
/**

2
src/Math/Quaternion.h

@ -232,7 +232,7 @@ template<class T> class Quaternion {
* @see dot(), normalized()
*/
inline bool isNormalized() const {
return TypeTraits<T>::equals(dot(), T(1));
return Implementation::isNormalizedSquared(dot());
}
/** @brief %Vector part */

13
src/Math/TypeTraits.h

@ -174,6 +174,19 @@ template<> struct TypeTraits<long double>: Implementation::TypeTraitsFloatingPoi
inline constexpr static long double epsilon() { return LONG_DOUBLE_EQUALITY_PRECISION; }
};
/* Comparing squared length to 1 is not sufficient to compare within range
[1 - epsilon, 1 + epsilon], as e.g. Quaternion with dot() = 1 + 1e-7 when
converted to matrix has column vectors with dot() = 1 + 1e-6, which is just
above 1 + epsilon. Thus it's needed to compare sqrt(dot()) in range
[1 - epsilon, 1 + epsilon] or dot() in range [1 - 2*epsilon + epsilon^2,
1 + 2*epsilon + epsilon^2]. Because epsilon^2 is way off machine precision,
it's omitted. */
namespace Implementation {
template<class T> inline bool isNormalizedSquared(T lengthSquared) {
return std::abs(lengthSquared - T(1)) < T(2)*TypeTraits<T>::epsilon();
}
}
#endif
}}

2
src/Math/Vector.h

@ -254,7 +254,7 @@ template<std::size_t size, class T> class Vector {
* @see dot(), normalized()
*/
inline bool isNormalized() const {
return TypeTraits<T>::equals(dot(), T(1));
return Implementation::isNormalizedSquared(dot());
}
/**

Loading…
Cancel
Save