diff options
-rw-r--r-- | include/rtl/math.h | 8 | ||||
-rw-r--r-- | include/rtl/math.hxx | 14 | ||||
-rw-r--r-- | libreofficekit/source/gtk/lokdocview.cxx | 22 | ||||
-rw-r--r-- | sal/rtl/math.cxx | 39 | ||||
-rw-r--r-- | sal/util/sal.map | 1 |
5 files changed, 72 insertions, 12 deletions
diff --git a/include/rtl/math.h b/include/rtl/math.h index 41047e139d01..1217e65adb20 100644 --- a/include/rtl/math.h +++ b/include/rtl/math.h @@ -422,6 +422,14 @@ SAL_DLLPUBLIC double SAL_CALL rtl_math_pow10Exp(double fValue, int nExp) SAL_THR */ SAL_DLLPUBLIC double SAL_CALL rtl_math_approxValue(double fValue) SAL_THROW_EXTERN_C(); +/** Test equality of two values with an accuracy of the magnitude of the + given values scaled by 2^-48 (4 bits roundoff stripped). + + @attention + approxEqual( value!=0.0, 0.0 ) _never_ yields true. + */ +SAL_DLLPUBLIC bool SAL_CALL rtl_math_approxEqual(double a, double b) SAL_THROW_EXTERN_C(); + /** Returns more accurate e^x-1 for x near 0 than calculating directly. expm1 is part of the C99 standard, but not provided by some compilers. diff --git a/include/rtl/math.hxx b/include/rtl/math.hxx index 642763dfc2d7..fed674fdd210 100644 --- a/include/rtl/math.hxx +++ b/include/rtl/math.hxx @@ -239,20 +239,11 @@ inline double acosh(double fValue) return rtl_math_acosh(fValue); } - -/** Test equality of two values with an accuracy of the magnitude of the - given values scaled by 2^-48 (4 bits roundoff stripped). - - @attention - approxEqual( value!=0.0, 0.0 ) _never_ yields true. +/** A wrapper around rtl_math_approxEqual. */ inline bool approxEqual(double a, double b) { - if ( a == b ) - return true; - double x = a - b; - return (x < 0.0 ? -x : x) - < ((a < 0.0 ? -a : a) * (1.0 / (16777216.0 * 16777216.0))); + return rtl_math_approxEqual( a, b ); } /** Test equality of two values with an accuracy defined by nPrec @@ -268,6 +259,7 @@ inline bool approxEqual(double a, double b, sal_Int16 nPrec) return (x < 0.0 ? -x : x) < ((a < 0.0 ? -a : a) * (1.0 / (pow(static_cast<double>(2.0), nPrec)))); } + /** Add two values. If signs differ and the absolute values are equal according to approxEqual() diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx index 0362d256db6b..4d34428a3312 100644 --- a/libreofficekit/source/gtk/lokdocview.cxx +++ b/libreofficekit/source/gtk/lokdocview.cxx @@ -3179,6 +3179,26 @@ lok_doc_view_set_visible_area (LOKDocView* pDocView, GdkRectangle* pVisibleArea) priv->m_bVisibleAreaSet = true; } +namespace { +// This used to be rtl::math::approxEqual() but since that isn't inline anymore +// in rtl/math.hxx and was moved into libuno_sal as rtl_math_approxEqual() to +// cater for representable integer cases and we don't want to link against +// libuno_sal, we'll have to have an own implementation. The special large +// integer cases seems not be needed here. +inline bool lok_approxEqual(double a, double b) +{ + static const double e48 = 1.0 / (16777216.0 * 16777216.0); + // XXX loplugin:fpcomparison complains about floating-point comparison for + // a==b, though we actually want this here. + if (!(a<b) && !(a>b)) + return true; + if (a == 0.0 || b == 0.0) + return false; + const double d = fabs(a - b); + return (d < fabs(a) * e48 && d < fabs(b) * e48); +} +} + SAL_DLLPUBLIC_EXPORT void lok_doc_view_set_zoom (LOKDocView* pDocView, float fZoom) { @@ -3192,7 +3212,7 @@ lok_doc_view_set_zoom (LOKDocView* pDocView, float fZoom) fZoom = fZoom < MIN_ZOOM ? MIN_ZOOM : fZoom; fZoom = fZoom > MAX_ZOOM ? MAX_ZOOM : fZoom; - if (rtl::math::approxEqual(fZoom, priv->m_fZoom)) + if (lok_approxEqual(fZoom, priv->m_fZoom)) return; priv->m_fZoom = fZoom; diff --git a/sal/rtl/math.cxx b/sal/rtl/math.cxx index b8a1cd2b2962..1df123bb095c 100644 --- a/sal/rtl/math.cxx +++ b/sal/rtl/math.cxx @@ -149,6 +149,27 @@ struct UStringTraits } }; +/** If value (passed as absolute value) is an integer representable as double, + which we handle explicitly at some places. + */ +bool isRepresentableInteger(double fAbsValue) +{ + const sal_Int64 kMaxInt = (static_cast<sal_Int64>(1) << 53) - 1; + if (fAbsValue <= static_cast<double>(kMaxInt)) + { + sal_Int64 nInt = static_cast<sal_Int64>(fAbsValue); + // Check the integer range again because double comparison may yield + // true within the precision range. + // XXX loplugin:fpcomparison complains about floating-point comparison + // for static_cast<double>(nInt) == fAbsValue, though we actually want + // this here. + double fInt; + return (nInt <= kMaxInt && + (!((fInt = static_cast<double>(nInt)) < fAbsValue) && !(fInt > fAbsValue))); + } + return false; +} + // Solaris C++ 5.2 compiler has problems when "StringT ** pResult" is // "typename T::String ** pResult" instead: template< typename T, typename StringT > @@ -1064,6 +1085,24 @@ double SAL_CALL rtl_math_approxValue( double fValue ) SAL_THROW_EXTERN_C() return bSign ? -fValue : fValue; } +bool SAL_CALL rtl_math_approxEqual(double a, double b) SAL_THROW_EXTERN_C() +{ + static const double e48 = 1.0 / (16777216.0 * 16777216.0); + static const double e44 = e48 * 16.0; + // XXX loplugin:fpcomparison complains about floating-point comparison for + // a==b, though we actually want this here. + if (!(a<b) && !(a>b)) + return true; + if (a == 0.0 || b == 0.0) + return false; + const double d = fabs(a - b); + if (d > ((a = fabs(a)) * e44) || d > ((b = fabs(b)) * e44)) + return false; + if (isRepresentableInteger(d) && isRepresentableInteger(a) && isRepresentableInteger(b)) + return false; // special case for representable integers. + return (d < a * e48 && d < b * e48); +} + double SAL_CALL rtl_math_expm1( double fValue ) SAL_THROW_EXTERN_C() { return expm1(fValue); diff --git a/sal/util/sal.map b/sal/util/sal.map index d9995e1e4cae..d50752ce31ae 100644 --- a/sal/util/sal.map +++ b/sal/util/sal.map @@ -704,6 +704,7 @@ LIBO_UDK_5.3 { # symbols available in >= LibO 5.3 rtl_uString_newReplaceFirstAsciiLUtf16L; rtl_uString_newReplaceFirstUtf16LAsciiL; rtl_uString_newReplaceFirstUtf16LUtf16L; + rtl_math_approxEqual; } LIBO_UDK_5.2; PRIVATE_1.0 { |