diff options
| author | Edward Welbourne <edward.welbourne@qt.io> | 2025-12-10 15:18:24 +0100 |
|---|---|---|
| committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2025-12-12 16:45:21 +0000 |
| commit | 06e42bc08be6f43c8257b3c6667e52a1269a6220 (patch) | |
| tree | e468279e0b5925816af2d9a5ed125b9f8390f334 | |
| parent | 95c7df09dc122402c2d28c670818f307c1f64668 (diff) | |
Deploy qHypot() to eliminate sqrt(sum of squares)6.10
Applies to QDoubleMatrix4x4, QDoubleVector2D, QDoubleVector3D.
Summing squares and then taking the square root has some
{ov,und}erflow failures when the squares are logarithmically beyond
about half way to the bounds of the representable values of the type.
A hypot() implementation - such as qHypot(), which copes with
arbitrarily many parameters - takes care to avoid those failures,
thereby producing finite non-zero answers for a broader range of
vectors. Using hypot() also preserves precision better, for related
reasons, and handles infinities and NaN more coherently, should they
arise.
In the process, reverse some qFuzzyCompare() || qFuzzyIsNull() checks
so that the is-null check is done first, satisfying the precondition
of the comparison (neither argument should be zero) before it is
reached.
Task-number: QTBUG-142020
Pick-to: 6.8 6.5
Change-Id: I34eb88a5e518155ab7c4584ec07a20404a1c0eb5
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Reviewed-by: Matthias Rauter <matthias.rauter@qt.io>
(cherry picked from commit 7e81c07241c3cd65e1f8890de24b99ba4d272e5c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 5c6e3435c052b5d6278fa42e16dfbbd67929c49f)
| -rw-r--r-- | src/positioning/qdoublematrix4x4.cpp | 27 | ||||
| -rw-r--r-- | src/positioning/qdoublevector2d.cpp | 14 | ||||
| -rw-r--r-- | src/positioning/qdoublevector3d.cpp | 18 |
3 files changed, 20 insertions, 39 deletions
diff --git a/src/positioning/qdoublematrix4x4.cpp b/src/positioning/qdoublematrix4x4.cpp index 23f5229d..d82c19a3 100644 --- a/src/positioning/qdoublematrix4x4.cpp +++ b/src/positioning/qdoublematrix4x4.cpp @@ -529,14 +529,11 @@ void QDoubleMatrix4x4::rotate(double angle, double x, double y, double z) return; } - double len = double(x) * double(x) + - double(y) * double(y) + - double(z) * double(z); - if (!qFuzzyCompare(len, 1.0) && !qFuzzyIsNull(len)) { - len = std::sqrt(len); - x = double(double(x) / len); - y = double(double(y) / len); - z = double(double(z) / len); + if (double len = qHypot(x, y, z); + !qFuzzyIsNull(len) && !qFuzzyCompare(len, 1.0)) { + x /= len; + y /= len; + z /= len; } double ic = 1.0 - c; QDoubleMatrix4x4 rot(1); // The "1" says to not load the identity. @@ -629,14 +626,12 @@ void QDoubleMatrix4x4::projectedRotate(double angle, double x, double y, double flagBits = General; return; } - double len = double(x) * double(x) + - double(y) * double(y) + - double(z) * double(z); - if (!qFuzzyCompare(len, 1.0) && !qFuzzyIsNull(len)) { - len = std::sqrt(len); - x = double(double(x) / len); - y = double(double(y) / len); - z = double(double(z) / len); + + if (const double len = qHypot(x, y, z); + !qFuzzyIsNull(len) && !qFuzzyCompare(len, 1.0)) { + x /= len; + y /= len; + z /= len; } double ic = 1.0 - c; QDoubleMatrix4x4 rot(1); // The "1" says to not load the identity. diff --git a/src/positioning/qdoublevector2d.cpp b/src/positioning/qdoublevector2d.cpp index 59d3b536..95a9c3d6 100644 --- a/src/positioning/qdoublevector2d.cpp +++ b/src/positioning/qdoublevector2d.cpp @@ -16,32 +16,26 @@ QDoubleVector2D::QDoubleVector2D(const QDoubleVector3D &vector) : double QDoubleVector2D::length() const { - return qSqrt(xp * xp + yp * yp); + return qHypot(xp, yp); } QDoubleVector2D QDoubleVector2D::normalized() const { - // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp); + const double len = length(); if (qFuzzyIsNull(len - 1.0)) return *this; else if (!qFuzzyIsNull(len)) - return *this / (double)qSqrt(len); + return *this / len; else return QDoubleVector2D(); } void QDoubleVector2D::normalize() { - // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp); + double len = length(); if (qFuzzyIsNull(len - 1.0) || qFuzzyIsNull(len)) return; - len = qSqrt(len); - xp /= len; yp /= len; } diff --git a/src/positioning/qdoublevector3d.cpp b/src/positioning/qdoublevector3d.cpp index 92ae8bcb..6b3a1b8f 100644 --- a/src/positioning/qdoublevector3d.cpp +++ b/src/positioning/qdoublevector3d.cpp @@ -10,29 +10,21 @@ QT_BEGIN_NAMESPACE QDoubleVector3D QDoubleVector3D::normalized() const { - // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp) + - double(zp) * double(zp); + const double len = length(); if (qFuzzyIsNull(len - 1.0)) return *this; else if (!qFuzzyIsNull(len)) - return *this / (double)qSqrt(len); + return *this / len; else return QDoubleVector3D(); } void QDoubleVector3D::normalize() { - // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp) + - double(zp) * double(zp); - if (qFuzzyIsNull(len - 1.0) || qFuzzyIsNull(len)) + double len = length(); + if (qFuzzyIsNull(len) || qFuzzyIsNull(len - 1.0)) return; - len = qSqrt(len); - xp /= len; yp /= len; zp /= len; @@ -67,7 +59,7 @@ double QDoubleVector3D::distanceToLine double QDoubleVector3D::length() const { - return qSqrt(xp * xp + yp * yp + zp * zp); + return qHypot(xp, yp, zp); } #ifndef QT_NO_DEBUG_STREAM |
