[Libreoffice-commits] core.git: sc/inc sc/Library_sc.mk sc/source solenv/clang-format

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Thu Jan 10 10:56:15 UTC 2019


 sc/Library_sc.mk                 |    1 
 sc/inc/math.hxx                  |    8 ++++
 sc/source/core/tool/interpr5.cxx |   13 -------
 sc/source/core/tool/math.cxx     |   64 +++++++++++++++++++++++++++++++++++++++
 solenv/clang-format/blacklist    |    1 
 5 files changed, 75 insertions(+), 12 deletions(-)

New commits:
commit 559758a35216c0cb852de65d129154947a4d91e8
Author:     Eike Rathke <erack at redhat.com>
AuthorDate: Tue Jan 8 23:40:51 2019 +0100
Commit:     Eike Rathke <erack at redhat.com>
CommitDate: Thu Jan 10 11:55:49 2019 +0100

    Related: tdf#44076 do not leave cast to int to undefined behaviour
    
    ... if the double is an out-of-int-range value.
    
    Also catch domain and pole and range errors.
    
    Move this to it's own sc::power() function that can be reused for
    example by ScMatrix::PowOp() to be congruent.
    
    Change-Id: I88331e02e6cdfb5e1dcbf81622d3fc7ce4510478
    Reviewed-on: https://gerrit.libreoffice.org/65986
    Tested-by: Jenkins
    Reviewed-by: Eike Rathke <erack at redhat.com>

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 3ef18fa8723b..9e67772d81f2 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -251,6 +251,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
     sc/source/core/tool/jumpmatrix \
     sc/source/core/tool/listenerquery \
     sc/source/core/tool/lookupcache \
+    sc/source/core/tool/math \
     sc/source/core/tool/matrixoperators \
     sc/source/core/tool/navicfg \
     sc/source/core/tool/numformat \
diff --git a/sc/inc/math.hxx b/sc/inc/math.hxx
index c2a3b992dd00..b4a6476fb44c 100644
--- a/sc/inc/math.hxx
+++ b/sc/inc/math.hxx
@@ -21,6 +21,7 @@
 #define INCLUDED_SC_INC_MATH_HXX
 
 #include <formula/errorcodes.hxx>
+#include <rtl/math.hxx>
 
 namespace sc {
 
@@ -65,6 +66,13 @@ inline double divide( const double& fNumerator, const double& fDenominator )
     return fNumerator / fDenominator;
 }
 
+/** Return pow(fVal1,fVal2) with error handling.
+
+    If an error was detectect, a coded double error of
+    FormulaError::IllegalFPOperation is returned.
+ */
+double power( const double& fVal1, const double& fVal2 );
+
 }
 
 #endif
diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx
index a8197718fe77..aef35f1cc3a0 100644
--- a/sc/source/core/tool/interpr5.cxx
+++ b/sc/source/core/tool/interpr5.cxx
@@ -1593,18 +1593,7 @@ void ScInterpreter::ScPow()
     }
     else
     {
-        if (fVal1 < 0 && fVal2 != 0.0)
-        {
-            int i = static_cast<int>(1 / fVal2 + ((fVal2 < 0) ? -0.5 : 0.5));
-            if (i % 2 != 0 && rtl::math::approxEqual(1 / static_cast<double>(i), fVal2))
-                PushDouble(-pow(-fVal1, fVal2));
-            else
-                PushDouble(pow(fVal1, fVal2));
-        }
-        else
-        {
-            PushDouble(pow(fVal1,fVal2));
-        }
+        PushDouble( sc::power( fVal1, fVal2));
     }
 }
 
diff --git a/sc/source/core/tool/math.cxx b/sc/source/core/tool/math.cxx
new file mode 100644
index 000000000000..73fbfcc29492
--- /dev/null
+++ b/sc/source/core/tool/math.cxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <math.hxx>
+#include <cmath>
+#include <cerrno>
+#include <cfenv>
+
+namespace sc {
+
+static double err_pow( const double& fVal1, const double& fVal2 )
+{
+    // pow() is expected to set domain error or pole error or range error (or
+    // flag them via exceptions) or return NaN or Inf.
+    assert((math_errhandling & (MATH_ERRNO | MATH_ERREXCEPT)) != 0);
+    std::feclearexcept(FE_ALL_EXCEPT);
+    errno = 0;
+    return pow( fVal1, fVal2);
+}
+
+double power( const double& fVal1, const double& fVal2 )
+{
+    double fPow;
+    if (fVal1 < 0 && fVal2 != 0.0)
+    {
+        const double f = 1.0 / fVal2 + ((fVal2 < 0.0) ? -0.5 : 0.5);
+        if (f < SAL_MIN_INT64 || f > SAL_MAX_INT64)
+        {
+            // Casting to int would be undefined behaviour.
+            fPow = err_pow( fVal1, fVal2);
+        }
+        else
+        {
+            const sal_Int64 i = static_cast<sal_Int64>(f);
+            if (i % 2 != 0 && rtl::math::approxEqual(1 / static_cast<double>(i), fVal2))
+                fPow = -err_pow( -fVal1, fVal2);
+            else
+                fPow = err_pow( fVal1, fVal2);
+        }
+    }
+    else
+    {
+        fPow = err_pow( fVal1, fVal2);
+    }
+    // The pow() call must had been the most recent call to check errno or exception.
+    if ((((math_errhandling & MATH_ERRNO) != 0) && (errno == EDOM || errno == ERANGE))
+            || (((math_errhandling & MATH_ERREXCEPT) != 0)
+                && std::fetestexcept( FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW))
+            || !rtl::math::isFinite(fPow))
+    {
+        fPow = CreateDoubleError( FormulaError::IllegalFPOperation);
+    }
+    return fPow;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/solenv/clang-format/blacklist b/solenv/clang-format/blacklist
index cb825b74afef..c86246f70eb8 100644
--- a/solenv/clang-format/blacklist
+++ b/solenv/clang-format/blacklist
@@ -10399,6 +10399,7 @@ sc/source/core/tool/interpr8.cxx
 sc/source/core/tool/jumpmatrix.cxx
 sc/source/core/tool/listenerquery.cxx
 sc/source/core/tool/lookupcache.cxx
+sc/source/core/tool/math.cxx
 sc/source/core/tool/matrixoperators.cxx
 sc/source/core/tool/navicfg.cxx
 sc/source/core/tool/numformat.cxx


More information about the Libreoffice-commits mailing list