From cebac1ae2f09abaca12cb6a052dd2043d09e0ae5 Mon Sep 17 00:00:00 2001 From: Bernd Weimer Date: Thu, 18 Jul 2013 14:32:20 +0200 Subject: Avoided zero devision in cube root approximation Halley's method to get a better approximation is omitted, if it would include a devision by zero (INFINITY/NaN is worse). Change-Id: Ida09326e2b5892d7cb21bcb956631c289e5b56ba Reviewed-by: Thiago Macieira --- src/corelib/tools/qeasingcurve.cpp | 10 ++++++---- tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp | 14 +++++++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp index bc0a14ea72..67e0711796 100644 --- a/src/corelib/tools/qeasingcurve.cpp +++ b/src/corelib/tools/qeasingcurve.cpp @@ -608,14 +608,16 @@ struct BezierEase : public QEasingCurveFunction sign = -1; d = d * sign; - qreal t_i = _fast_cbrt(d); + qreal t = _fast_cbrt(d); //one step of Halley's Method to get a better approximation - const qreal t_i_cubic = t_i * t_i * t_i; - qreal t = t_i * (t_i_cubic + d + d) / (t_i_cubic + t_i_cubic + d); + const qreal t_cubic = t * t * t; + const qreal f = t_cubic + t_cubic + d; + if (f != qreal(0.0)) + t = t * (t_cubic + d + d) / f; //another step - /*t_i = t; + /*qreal t_i = t; t_i_cubic = pow(t_i, 3); t = t_i * (t_i_cubic + d + d) / (t_i_cubic + t_i_cubic + d);*/ diff --git a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp index fa747b3c18..3348b49110 100644 --- a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp +++ b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp @@ -730,14 +730,16 @@ double static inline _fast_cbrt(double d) void tst_QEasingCurve::testCbrtDouble() { - const qreal errorBound = 0.0001; + const double errorBound = 0.0001; for (int i = 0; i < 100000; i++) { double d = double(i) / 1000.0; double t = _fast_cbrt(d); const double t_cubic = t * t * t; - t = t * (t_cubic + d + d) / (t_cubic + t_cubic + d); + const double f = t_cubic + t_cubic + d; + if (f != 0.0) + t = t * (t_cubic + d + d) / f; double expected = pow(d, 1.0/3.0); @@ -754,14 +756,16 @@ void tst_QEasingCurve::testCbrtDouble() void tst_QEasingCurve::testCbrtFloat() { - const qreal errorBound = 0.0005; + const float errorBound = 0.0005; - for (int i = 1; i < 100000; i++) { + for (int i = 0; i < 100000; i++) { float f = float(i) / 1000.0f; float t = _fast_cbrt(f); const float t_cubic = t * t * t; - t = t * (t_cubic + f + f) / (t_cubic + t_cubic + f); + const float fac = t_cubic + t_cubic + f; + if (fac != 0.0f) + t = t * (t_cubic + f + f) / fac; float expected = pow(f, float(1.0/3.0)); -- cgit v1.2.3