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 <er...@redhat.com> AuthorDate: Tue Jan 8 23:40:51 2019 +0100 Commit: Eike Rathke <er...@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 <er...@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 _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits