sc/source/core/tool/interpr2.cxx |   17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

New commits:
commit 397d12997a604730ad11316faa34cefd470ee0ff
Author:     Eike Rathke <er...@redhat.com>
AuthorDate: Sat Apr 15 01:01:58 2023 +0200
Commit:     Eike Rathke <er...@redhat.com>
CommitDate: Sat Apr 15 03:40:24 2023 +0200

    ROUNDSIG() Avoid inaccuracy of pow(10,negative) tdf#138220, tdf#105931 
follow
    
    https://bugs.documentfoundation.org/show_bug.cgi?id=138220#c6
    (otherwise unrelated) has an example of
    =RAWSUBTRACT(ROUNDSIG(-999.13;12);-999.13)
    resulting in -0,00000000000011368684 instead of 0, due to these
    0.1 ... inexact negative power of 10 values.
    
    Change-Id: I82429f0871f1de35a7f2092708fc6b9c2e902999
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150438
    Reviewed-by: Eike Rathke <er...@redhat.com>
    Tested-by: Jenkins

diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx
index b8fe537ef3f9..58b3008319ca 100644
--- a/sc/source/core/tool/interpr2.cxx
+++ b/sc/source/core/tool/interpr2.cxx
@@ -1002,8 +1002,21 @@ void ScInterpreter::ScRoundUp()
 
 void ScInterpreter::RoundSignificant( double fX, double fDigits, double &fRes )
 {
-    double fTemp = ::rtl::math::approxFloor( log10( std::abs(fX) ) ) + 1.0 - 
fDigits;
-    fRes = ::rtl::math::round( pow(10.0, -fTemp ) * fX ) * pow( 10.0, fTemp );
+    double fTemp = floor( log10( std::abs(fX) ) ) + 1.0 - fDigits;
+    double fIn = fX;
+    // Avoid inaccuracy of negative powers of 10.
+    if (fTemp < 0.0)
+        fIn *= pow(10.0, -fTemp);
+    else
+        fIn /= pow(10.0, fTemp);
+    // For very large fX there might be an overflow in fIn resulting in
+    // non-finite. rtl::math::round() handles that and it will be propagated as
+    // usual.
+    fRes = ::rtl::math::round(fIn);
+    if (fTemp < 0.0)
+        fRes /= pow(10.0, -fTemp);
+    else
+        fRes *= pow(10.0, fTemp);
 }
 
 // tdf#105931

Reply via email to