summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/rtl/math.h8
-rw-r--r--include/rtl/math.hxx14
-rw-r--r--libreofficekit/source/gtk/lokdocview.cxx22
-rw-r--r--sal/rtl/math.cxx39
-rw-r--r--sal/util/sal.map1
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 {