[Libreoffice-commits] core.git: 2 commits - download.lst external/dtoa external/Module_external.mk Makefile.fetch readlicense_oo/license RepositoryExternal.mk sal/Library_sal.mk sal/qa sal/rtl sc/qa sd/qa svl/Library_svl.mk svl/source

Mike Kaganski (via logerrit) logerrit at kemper.freedesktop.org
Thu Feb 27 10:02:42 UTC 2020


 Makefile.fetch                                                    |    1 
 RepositoryExternal.mk                                             |   17 
 download.lst                                                      |    2 
 external/Module_external.mk                                       |    1 
 external/dtoa/Module_dtoa.mk                                      |   17 
 external/dtoa/README                                              |   10 
 external/dtoa/StaticLibrary_dtoa.mk                               |   22 +
 external/dtoa/UnpackedTarball_dtoa.mk                             |   20 
 external/dtoa/include_header.patch                                |   37 +
 readlicense_oo/license/license.xml                                |   19 
 sal/Library_sal.mk                                                |    1 
 sal/qa/rtl/math/test-rtl-math.cxx                                 |   31 +
 sal/rtl/math.cxx                                                  |  205 +++-------
 sc/qa/unit/bugfix-test.cxx                                        |   30 +
 sc/qa/unit/data/functions/array/fods/linest.fods                  |   36 -
 sc/qa/unit/data/functions/financial/fods/amordegrc.fods           |  118 ++---
 sc/qa/unit/data/functions/financial/fods/rate.fods                |    8 
 sc/qa/unit/data/functions/statistical/fods/betadist.fods          |   64 +--
 sc/qa/unit/data/functions/statistical/fods/chiinv.fods            |    8 
 sc/qa/unit/data/functions/statistical/fods/forecast.ets.mult.fods |    2 
 sc/qa/unit/data/functions/statistical/fods/tinv.fods              |    8 
 sd/qa/unit/export-tests-ooxml2.cxx                                |    2 
 svl/Library_svl.mk                                                |    1 
 svl/source/numbers/zforfind.cxx                                   |   48 +-
 24 files changed, 428 insertions(+), 280 deletions(-)

New commits:
commit 1782810f886acd26db211d8fdd7ae8796d203c57
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Tue Feb 25 13:54:12 2020 +0300
Commit:     Mike Kaganski <mike.kaganski at collabora.com>
CommitDate: Thu Feb 27 11:02:16 2020 +0100

    Related: tdf#130725: use strtod also in rtl::math::stringToDouble
    
    Size of buffer on stack is 256 characters. Logging function usage
    in make check, of >1 100 000 invocations, the longest string was
    80 characters, average being 4.6 characters. So heap allocation
    is unlikely in scenarios with intensive function usage.
    
    Several existing unit tests had to be fixed. Usually, the change
    is either minimal or getting closer to what Excel returns (for
    Calc tests). But in case of AMORDEGRC, I had to change rate value
    passed to the function from 0.3 to 0.31. It's because the closest
    double value for 0.3 is 0.29999999999999999, which is a bit less
    than 0.3; multiplied by 1.5, this gives 0.44999999999999996, and
    then rounding the result of multiplication of the latter by cost
    gave the result 1 less than before, when 0.3 was imported as
    0.30000000000000004. Now the function returns a value 1 less than
    Excel for that set of arguments. I don't see how to fix that.
    Having rate slightly different gives consistent result between
    Calc and Excel.
    
    Change-Id: Icae5ce374fe0c31a1aa10cee815e65ef0014f382
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89422
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/sal/Library_sal.mk b/sal/Library_sal.mk
index e84ed0aaf1b5..42e3dc53e301 100644
--- a/sal/Library_sal.mk
+++ b/sal/Library_sal.mk
@@ -39,6 +39,7 @@ $(eval $(call gb_Library_use_libraries,sal,\
 ))
 
 $(eval $(call gb_Library_use_externals,sal,\
+    dtoa \
     valgrind \
 ))
 
diff --git a/sal/qa/rtl/math/test-rtl-math.cxx b/sal/qa/rtl/math/test-rtl-math.cxx
index 5038b45a13c8..5dab92b81ba8 100644
--- a/sal/qa/rtl/math/test-rtl-math.cxx
+++ b/sal/qa/rtl/math/test-rtl-math.cxx
@@ -149,6 +149,37 @@ public:
         CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
         CPPUNIT_ASSERT_EQUAL(sal_Int32(5), end);
         CPPUNIT_ASSERT_EQUAL(1234.0, res);
+
+        // Check that the value is the nearest double-precision representation of the decimal 0.0042
+        // (it was 0.0042000000000000006 instead of 0.0041999999999999997)
+        res = rtl::math::stringToDouble(OUString("0,0042"), ',', ' ', &status, &end);
+        CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
+        CPPUNIT_ASSERT_EQUAL(0.0042, res);
+
+        // "- 1" is nothing
+        res = rtl::math::stringToDouble(OUString("- 1"), '.', ',', &status, &end);
+        CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end);
+        CPPUNIT_ASSERT_EQUAL(0.0, res);
+
+        // "-1E+E" : no exponent
+        res = rtl::math::stringToDouble(OUString("-1E+E"), '.', ',', &status, &end);
+        CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(2), end);
+        CPPUNIT_ASSERT_EQUAL(-1.0, res);
+
+        // "-0" is negative zero
+        res = rtl::math::stringToDouble(OUString("-0"), '.', ',', &status, &end);
+        CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(2), end);
+        CPPUNIT_ASSERT_EQUAL(0.0, res);
+        CPPUNIT_ASSERT(rtl::math::isSignBitSet(res));
+
+        // Compensating: "0.001E311" is 1E308, not overflow/inf
+        res = rtl::math::stringToDouble(OUString("0.001E311"), '.', ',', &status, &end);
+        CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(9), end);
+        CPPUNIT_ASSERT_EQUAL(1E308, res);
     }
 
     void test_stringToDouble_bad() {
diff --git a/sal/rtl/math.cxx b/sal/rtl/math.cxx
index 9fb97d43480e..af1457eac937 100644
--- a/sal/rtl/math.cxx
+++ b/sal/rtl/math.cxx
@@ -38,8 +38,11 @@
 #include <limits>
 #include <limits.h>
 #include <math.h>
+#include <memory>
 #include <stdlib.h>
 
+#include <dtoa.h>
+
 #if !HAVE_GCC_BUILTIN_FFS && !defined _WIN32
     #include <strings.h>
 #endif
@@ -756,18 +759,6 @@ void SAL_CALL rtl_math_doubleToUString(rtl_uString ** pResult,
 
 namespace {
 
-// if nExp * 10 + nAdd would result in overflow
-bool long10Overflow( long& nExp, int nAdd )
-{
-    if ( nExp > (LONG_MAX/10)
-         || (nExp == (LONG_MAX/10) && nAdd > (LONG_MAX%10)) )
-    {
-        nExp = LONG_MAX;
-        return true;
-    }
-    return false;
-}
-
 template< typename CharT >
 double stringToDouble(CharT const * pBegin, CharT const * pEnd,
                              CharT cDecSeparator, CharT cGroupSeparator,
@@ -821,6 +812,37 @@ double stringToDouble(CharT const * pBegin, CharT const * pEnd,
 
     if (!bDone) // do not recognize e.g. NaN1.23
     {
+        std::unique_ptr<char[]> bufInHeap;
+        std::unique_ptr<const CharT * []> bufInHeapMap;
+        constexpr int bufOnStackSize = 256;
+        char bufOnStack[bufOnStackSize];
+        const CharT* bufOnStackMap[bufOnStackSize];
+        char* buf = bufOnStack;
+        const CharT** bufmap = bufOnStackMap;
+        int bufpos = 0;
+        const size_t bufsize = pEnd - p + (bSign ? 2 : 1);
+        if (bufsize > bufOnStackSize)
+        {
+            bufInHeap = std::make_unique<char[]>(bufsize);
+            bufInHeapMap = std::make_unique<const CharT*[]>(bufsize);
+            buf = bufInHeap.get();
+            bufmap = bufInHeapMap.get();
+        }
+
+        if (bSign)
+        {
+            buf[0] = '-';
+            bufmap[0] = p; // yes, this may be the same pointer as for the next mapping
+            bufpos = 1;
+        }
+        // Put first zero to buffer for strings like "-0"
+        if (p != pEnd && *p == CharT('0'))
+        {
+            buf[bufpos] = '0';
+            bufmap[bufpos] = p;
+            ++bufpos;
+            ++p;
+        }
         // Leading zeros and group separators between digits may be safely
         // ignored. p0 < p implies that there was a leading 0 already,
         // consecutive group separators may not happen as *(p+1) is checked for
@@ -831,17 +853,15 @@ double stringToDouble(CharT const * pBegin, CharT const * pEnd,
             ++p;
         }
 
-        CharT const * pFirstSignificant = ((p > pBegin && *(p-1) == CharT('0')) ? p-1 : p);
-        long nValExp = 0;       // carry along exponent of mantissa
-
         // integer part of mantissa
         for (; p != pEnd; ++p)
         {
             CharT c = *p;
             if (rtl::isAsciiDigit(c))
             {
-                fVal = fVal * 10.0 + static_cast< double >( c - CharT('0') );
-                ++nValExp;
+                buf[bufpos] = static_cast<char>(c);
+                bufmap[bufpos] = p;
+                ++bufpos;
             }
             else if (c != cGroupSeparator)
             {
@@ -858,21 +878,11 @@ double stringToDouble(CharT const * pBegin, CharT const * pEnd,
         // fraction part of mantissa
         if (p != pEnd && *p == cDecSeparator)
         {
+            buf[bufpos] = '.';
+            bufmap[bufpos] = p;
+            ++bufpos;
             ++p;
-            double fFrac = 0.0;
-            long nFracExp = 0;
-            while (p != pEnd && *p == CharT('0'))
-            {
-                --nFracExp;
-                ++p;
-            }
-
-            if (nValExp == 0)
-                nValExp = nFracExp - 1; // no integer part => fraction exponent
 
-            // one decimal digit needs ld(10) ~= 3.32 bits
-            static const int nSigs = (DBL_MANT_DIG / 3) + 1;
-            int nDigs = 0;
             for (; p != pEnd; ++p)
             {
                 CharT c = *p;
@@ -880,122 +890,38 @@ double stringToDouble(CharT const * pBegin, CharT const * pEnd,
                 {
                     break;
                 }
-                if ( nDigs < nSigs )
-                {   // further digits (more than nSigs) don't have any
-                    // significance
-                    fFrac = fFrac * 10.0 + static_cast<double>(c - CharT('0'));
-                    --nFracExp;
-                    ++nDigs;
-                }
-            }
-
-            if (fFrac != 0.0)
-            {
-                fVal += rtl::math::pow10Exp( fFrac, nFracExp );
-            }
-            else if (nValExp < 0)
-            {
-                if (pFirstSignificant + 1 == p)
-                {
-                    // No digit at all, only separator(s) without integer or
-                    // fraction part. Bail out. No number. No error.
-                    if (pStatus)
-                        *pStatus = eStatus;
-
-                    if (pParsedEnd)
-                        *pParsedEnd = pBegin;
-
-                    return fVal;
-                }
-                nValExp = 0;    // no digit other than 0 after decimal point
+                buf[bufpos] = static_cast<char>(c);
+                bufmap[bufpos] = p;
+                ++bufpos;
             }
         }
 
-        if (nValExp > 0)
-            --nValExp;  // started with offset +1 at the first mantissa digit
-
         // Exponent
         if (p != p0 && p != pEnd && (*p == CharT('E') || *p == CharT('e')))
         {
-            CharT const * const pExponent = p;
+            buf[bufpos] = 'E';
+            bufmap[bufpos] = p;
+            ++bufpos;
             ++p;
-            bool bExpSign;
             if (p != pEnd && *p == CharT('-'))
             {
-                bExpSign = true;
+                buf[bufpos] = '-';
+                bufmap[bufpos] = p;
+                ++bufpos;
                 ++p;
             }
-            else
-            {
-                bExpSign = false;
-                if (p != pEnd && *p == CharT('+'))
-                    ++p;
-            }
-            CharT const * const pFirstExpDigit = p;
-            if ( fVal == 0.0 )
-            {   // no matter what follows, zero stays zero, but carry on the
-                // offset
-                while (p != pEnd && rtl::isAsciiDigit(*p))
-                {
-                    ++p;
-                }
+            else if (p != pEnd && *p == CharT('+'))
+                ++p;
 
-                if (p == pFirstExpDigit)
-                {   // no digits in exponent, reset end of scan
-                    p = pExponent;
-                }
-            }
-            else
+            for (; p != pEnd; ++p)
             {
-                bool bOverflow = false;
-                long nExp = 0;
-                for (; p != pEnd; ++p)
-                {
-                    CharT c = *p;
-                    if (!rtl::isAsciiDigit(c))
-                        break;
-
-                    int i = c - CharT('0');
-
-                    if ( long10Overflow( nExp, i ) )
-                        bOverflow = true;
-                    else
-                        nExp = nExp * 10 + i;
-                }
+                CharT c = *p;
+                if (!rtl::isAsciiDigit(c))
+                    break;
 
-                if ( nExp )
-                {
-                    if ( bExpSign )
-                        nExp = -nExp;
-
-                    long nAllExp(0);
-                    if (!bOverflow)
-                        bOverflow = o3tl::checked_add(nExp, nValExp, nAllExp);
-                    if ( nAllExp > DBL_MAX_10_EXP || (bOverflow && !bExpSign) )
-                    {   // overflow
-                        fVal = HUGE_VAL;
-                        eStatus = rtl_math_ConversionStatus_OutOfRange;
-                    }
-                    else if ((nAllExp < DBL_MIN_10_EXP) ||
-                             (bOverflow && bExpSign) )
-                    {   // underflow
-                        fVal = 0.0;
-                        eStatus = rtl_math_ConversionStatus_OutOfRange;
-                    }
-                    else if ( nExp > DBL_MAX_10_EXP || nExp < DBL_MIN_10_EXP )
-                    {   // compensate exponents
-                        fVal = rtl::math::pow10Exp( fVal, -nValExp );
-                        fVal = rtl::math::pow10Exp( fVal, nAllExp );
-                    }
-                    else
-                    {
-                        fVal = rtl::math::pow10Exp( fVal, nExp );  // normal
-                    }
-                }
-                else if (p == pFirstExpDigit)
-                {   // no digits in exponent, reset end of scan
-                    p = pExponent;
-                }
+                buf[bufpos] = static_cast<char>(c);
+                bufmap[bufpos] = p;
+                ++bufpos;
             }
         }
         else if (p - p0 == 2 && p != pEnd && p[0] == CharT('#')
@@ -1011,6 +937,7 @@ double stringToDouble(CharT const * pBegin, CharT const * pEnd,
                 // Eat any further digits:
                 while (p != pEnd && rtl::isAsciiDigit(*p))
                     ++p;
+                bDone = true;
             }
             else if (pEnd - p >= 4 && p[1] == CharT('N') && p[2] == CharT('A')
                 && p[3] == CharT('N'))
@@ -1036,8 +963,22 @@ double stringToDouble(CharT const * pBegin, CharT const * pEnd,
                 {
                     ++p;
                 }
+                bDone = true;
             }
         }
+
+        if (!bDone)
+        {
+            buf[bufpos] = '\0';
+            bufmap[bufpos] = p;
+            char* pCharParseEnd;
+            errno = 0;
+            fVal = strtod_nolocale(buf, &pCharParseEnd);
+            if (errno == ERANGE)
+                eStatus = rtl_math_ConversionStatus_OutOfRange;
+            p = bufmap[pCharParseEnd - buf];
+            bSign = false;
+        }
     }
 
     // overflow also if more than DBL_MAX_10_EXP digits without decimal
diff --git a/sc/qa/unit/data/functions/array/fods/linest.fods b/sc/qa/unit/data/functions/array/fods/linest.fods
index 1465f7b85e13..fbf27b2053ca 100644
--- a/sc/qa/unit/data/functions/array/fods/linest.fods
+++ b/sc/qa/unit/data/functions/array/fods/linest.fods
@@ -6674,11 +6674,11 @@
      <table:table-cell table:number-columns-repeated="13"/>
     </table:table-row>
     <table:table-row table:style-name="ro2">
-     <table:table-cell table:formula="of:=[.M185]" office:value-type="float" office:value="2484916.49382742" calcext:value-type="float">
-      <text:p>2484916.49382742</text:p>
+     <table:table-cell table:formula="of:=[.M185]" office:value-type="float" office:value="2484916.49382745" calcext:value-type="float">
+      <text:p>2484916.49382745</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="2484916.49382742" calcext:value-type="float">
-      <text:p>2484916.49382742</text:p>
+     <table:table-cell office:value-type="float" office:value="2484916.49382745" calcext:value-type="float">
+      <text:p>2484916.49382745</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce15" table:formula="of:=ROUND([.A171];12)=ROUND([.B171];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
@@ -7004,8 +7004,8 @@
       <text:p>=M195</text:p>
      </table:table-cell>
      <table:table-cell table:number-columns-repeated="8"/>
-     <table:table-cell office:value-type="float" office:value="2484916.49382742" calcext:value-type="float">
-      <text:p>2484916.49382742</text:p>
+     <table:table-cell office:value-type="float" office:value="2484916.49382745" calcext:value-type="float">
+      <text:p>2484916.49382745</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="float" office:value="1" calcext:value-type="float">
       <text:p>1</text:p>
@@ -7352,11 +7352,11 @@
      <table:table-cell table:number-columns-repeated="12"/>
     </table:table-row>
     <table:table-row table:style-name="ro2">
-     <table:table-cell table:formula="of:=[.M208]" office:value-type="float" office:value="786024.50000001" calcext:value-type="float">
-      <text:p>786024.50000001</text:p>
+     <table:table-cell table:formula="of:=[.M208]" office:value-type="float" office:value="786024.500000118" calcext:value-type="float">
+      <text:p>786024.500000118</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="786024.50000001" calcext:value-type="float">
-      <text:p>786024.50000001</text:p>
+     <table:table-cell office:value-type="float" office:value="786024.500000118" calcext:value-type="float">
+      <text:p>786024.500000118</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce15" table:formula="of:=ROUND([.A201];12)=ROUND([.B201];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
@@ -7533,8 +7533,8 @@
       <text:p>=O205</text:p>
      </table:table-cell>
      <table:table-cell table:number-columns-repeated="8"/>
-     <table:table-cell office:value-type="float" office:value="786024.50000001" calcext:value-type="float">
-      <text:p>786024.50000001</text:p>
+     <table:table-cell office:value-type="float" office:value="786024.500000118" calcext:value-type="float">
+      <text:p>786024.500000118</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="float" office:value="1" calcext:value-type="float">
       <text:p>1</text:p>
@@ -7701,11 +7701,11 @@
      <table:table-cell table:number-columns-repeated="12"/>
     </table:table-row>
     <table:table-row table:style-name="ro2">
-     <table:table-cell table:formula="of:=[.M219]" office:value-type="float" office:value="786024.50000001" calcext:value-type="float">
-      <text:p>786024.50000001</text:p>
+     <table:table-cell table:formula="of:=[.M219]" office:value-type="float" office:value="786024.500000118" calcext:value-type="float">
+      <text:p>786024.500000118</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="786024.50000001" calcext:value-type="float">
-      <text:p>786024.50000001</text:p>
+     <table:table-cell office:value-type="float" office:value="786024.500000118" calcext:value-type="float">
+      <text:p>786024.500000118</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce15" table:formula="of:=ROUND([.A216];12)=ROUND([.B216];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
@@ -7789,8 +7789,8 @@
       <text:p>=N217</text:p>
      </table:table-cell>
      <table:table-cell table:number-columns-repeated="8"/>
-     <table:table-cell office:value-type="float" office:value="786024.50000001" calcext:value-type="float">
-      <text:p>786024.50000001</text:p>
+     <table:table-cell office:value-type="float" office:value="786024.500000118" calcext:value-type="float">
+      <text:p>786024.500000118</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="float" office:value="1" calcext:value-type="float">
       <text:p>1</text:p>
diff --git a/sc/qa/unit/data/functions/financial/fods/amordegrc.fods b/sc/qa/unit/data/functions/financial/fods/amordegrc.fods
index 0e98f330bf0c..68c22fb58340 100644
--- a/sc/qa/unit/data/functions/financial/fods/amordegrc.fods
+++ b/sc/qa/unit/data/functions/financial/fods/amordegrc.fods
@@ -1312,11 +1312,11 @@
      <table:table-cell table:style-name="ce28"/>
     </table:table-row>
     <table:table-row table:style-name="ro7">
-     <table:table-cell table:formula="of:=AMORDEGRC([.J1];[.J2];[.J3];[.J4];[.J5];[.J6];[.J7])" office:value-type="float" office:value="2813" calcext:value-type="float">
-      <text:p>2813</text:p>
+     <table:table-cell table:formula="of:=AMORDEGRC([.J1];[.J2];[.J3];[.J4];[.J5];[.J6];[.J7])" office:value-type="float" office:value="2848" calcext:value-type="float">
+      <text:p>2848</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="2813" calcext:value-type="float">
-      <text:p>2813</text:p>
+     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="2848" calcext:value-type="float">
+      <text:p>2848</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce15" table:formula="of:=[.A2]=[.B2]" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>PRAVDA</text:p>
@@ -1344,17 +1344,17 @@
      <table:table-cell/>
     </table:table-row>
     <table:table-row table:style-name="ro8">
-     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.3;1)" office:value-type="float" office:value="2813" calcext:value-type="float">
-      <text:p>2813</text:p>
+     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.31;1)" office:value-type="float" office:value="2848" calcext:value-type="float">
+      <text:p>2848</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="2813" calcext:value-type="float">
-      <text:p>2813</text:p>
+     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="2848" calcext:value-type="float">
+      <text:p>2848</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce15" table:formula="of:=[.A3]=[.B3]" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>PRAVDA</text:p>
      </table:table-cell>
-     <table:table-cell table:formula="of:=FORMULA([.A3])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;1)" calcext:value-type="string">
-      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;1)</text:p>
+     <table:table-cell table:formula="of:=FORMULA([.A3])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;1)" calcext:value-type="string">
+      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;1)</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="string" calcext:value-type="string">
       <text:p>tdf69569, verified with Excel2016</text:p>
@@ -1376,17 +1376,17 @@
      <table:table-cell/>
     </table:table-row>
     <table:table-row table:style-name="ro8">
-     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.3;1)" office:value-type="float" office:value="2813" calcext:value-type="float">
-      <text:p>2813</text:p>
+     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.31;1)" office:value-type="float" office:value="2848" calcext:value-type="float">
+      <text:p>2848</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="2813" calcext:value-type="float">
-      <text:p>2813</text:p>
+     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="2848" calcext:value-type="float">
+      <text:p>2848</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce15" table:formula="of:=[.A4]=[.B4]" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>PRAVDA</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A4])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;1)" calcext:value-type="string">
-      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;1)</text:p>
+     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A4])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;1)" calcext:value-type="string">
+      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;1)</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="string" calcext:value-type="string">
       <text:p>tdf69569, verified with Excel2016</text:p>
@@ -1408,17 +1408,17 @@
      <table:table-cell table:style-name="ce28"/>
     </table:table-row>
     <table:table-row table:style-name="ro9">
-     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.3;0)" office:value-type="float" office:value="2813" calcext:value-type="float">
-      <text:p>2813</text:p>
+     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.31;0)" office:value-type="float" office:value="2848" calcext:value-type="float">
+      <text:p>2848</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="2813" calcext:value-type="float">
-      <text:p>2813</text:p>
+     <table:table-cell office:value-type="float" office:value="2848" calcext:value-type="float">
+      <text:p>2848</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce15" table:formula="of:=[.A5]=[.B5]" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>PRAVDA</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A5])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;0)" calcext:value-type="string">
-      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;0)</text:p>
+     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A5])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;0)" calcext:value-type="string">
+      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;0)</text:p>
      </table:table-cell>
      <table:table-cell table:number-columns-repeated="4"/>
      <table:table-cell office:value-type="string" calcext:value-type="string">
@@ -1437,17 +1437,17 @@
      <table:table-cell/>
     </table:table-row>
     <table:table-row table:style-name="ro6">
-     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.3;3)" office:value-type="float" office:value="2808" calcext:value-type="float">
-      <text:p>2808</text:p>
+     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.31;3)" office:value-type="float" office:value="2843" calcext:value-type="float">
+      <text:p>2843</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="2808" calcext:value-type="float">
-      <text:p>2808</text:p>
+     <table:table-cell office:value-type="float" office:value="2843" calcext:value-type="float">
+      <text:p>2843</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce16" table:formula="of:=[.A6]=[.B6]" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>PRAVDA</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A6])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;3)" calcext:value-type="string">
-      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;3)</text:p>
+     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A6])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;3)" calcext:value-type="string">
+      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;3)</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="string" calcext:value-type="string">
       <text:p>Basis 3</text:p>
@@ -1456,8 +1456,8 @@
      <table:table-cell office:value-type="string" calcext:value-type="string">
       <text:p>rate</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce27" office:value-type="percentage" office:value="0.3" calcext:value-type="percentage">
-      <text:p>30,00%</text:p>
+     <table:table-cell table:style-name="ce27" office:value-type="percentage" office:value="0.31" calcext:value-type="percentage">
+      <text:p>31,00%</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce12"/>
      <table:table-cell table:style-name="ce11" office:value-type="float" office:value="1" calcext:value-type="float">
@@ -1469,17 +1469,17 @@
      <table:table-cell/>
     </table:table-row>
     <table:table-row table:style-name="ro9">
-     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.3;4)" office:value-type="float" office:value="2818" calcext:value-type="float">
-      <text:p>2818</text:p>
+     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.31;4)" office:value-type="float" office:value="2854" calcext:value-type="float">
+      <text:p>2854</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="2818" calcext:value-type="float">
-      <text:p>2818</text:p>
+     <table:table-cell office:value-type="float" office:value="2854" calcext:value-type="float">
+      <text:p>2854</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce17" table:formula="of:=[.A7]=[.B7]" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>PRAVDA</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A7])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;4)" calcext:value-type="string">
-      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;4)</text:p>
+     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A7])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;4)" calcext:value-type="string">
+      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;4)</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="string" calcext:value-type="string">
       <text:p>Basis 4</text:p>
@@ -1501,11 +1501,11 @@
      <table:table-cell table:style-name="ce28"/>
     </table:table-row>
     <table:table-row table:style-name="ro9">
-     <table:table-cell table:style-name="Comma_20_2" table:formula="of:=AMORDEGRC([.J1];[.J2];[.J3];[.J4];[.J5];[.J6];)" office:value-type="float" office:value="2813" calcext:value-type="float">
-      <text:p><text:s/>2 813,00 </text:p>
+     <table:table-cell table:style-name="Comma_20_2" table:formula="of:=AMORDEGRC([.J1];[.J2];[.J3];[.J4];[.J5];[.J6];)" office:value-type="float" office:value="2848" calcext:value-type="float">
+      <text:p><text:s/>2 848,00 </text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="2813" calcext:value-type="float">
-      <text:p>2813</text:p>
+     <table:table-cell office:value-type="float" office:value="2848" calcext:value-type="float">
+      <text:p>2848</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce17" table:formula="of:=[.A8]=[.B8]" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>PRAVDA</text:p>
@@ -1527,11 +1527,11 @@
      <table:table-cell/>
     </table:table-row>
     <table:table-row table:style-name="ro6">
-     <table:table-cell table:formula="of:=AMORDEGRC([.J1];[.J2];[.J3];[.J4];[.J5];[.J6])" office:value-type="float" office:value="2813" calcext:value-type="float">
-      <text:p>2813</text:p>
+     <table:table-cell table:formula="of:=AMORDEGRC([.J1];[.J2];[.J3];[.J4];[.J5];[.J6])" office:value-type="float" office:value="2848" calcext:value-type="float">
+      <text:p>2848</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="2813" calcext:value-type="float">
-      <text:p>2813</text:p>
+     <table:table-cell office:value-type="float" office:value="2848" calcext:value-type="float">
+      <text:p>2848</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce17" table:formula="of:=[.A9]=[.B9]" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>PRAVDA</text:p>
@@ -1573,7 +1573,7 @@
      <table:table-cell table:style-name="ce28"/>
     </table:table-row>
     <table:table-row table:style-name="ro10">
-     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;-1;0.3;4)" office:value-type="string" office:string-value="" calcext:value-type="error">
+     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;-1;0.31;4)" office:value-type="string" office:string-value="" calcext:value-type="error">
       <text:p>Err:502</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="string" calcext:value-type="string">
@@ -1582,8 +1582,8 @@
      <table:table-cell table:style-name="ce15" table:formula="of:=ISERROR([.A11])" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>PRAVDA</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A11])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;-1;0,3;4)" calcext:value-type="string">
-      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;-1;0,3;4)</text:p>
+     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A11])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;-1;0,31;4)" calcext:value-type="string">
+      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;-1;0,31;4)</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="string" calcext:value-type="string">
       <text:p>Tdf#100523</text:p>
@@ -1596,7 +1596,7 @@
      <table:table-cell table:number-columns-repeated="3"/>
     </table:table-row>
     <table:table-row table:style-name="ro10">
-     <table:table-cell table:formula="of:=AMORDEGRC(-10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.3;4)" office:value-type="string" office:string-value="" calcext:value-type="error">
+     <table:table-cell table:formula="of:=AMORDEGRC(-10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.31;4)" office:value-type="string" office:string-value="" calcext:value-type="error">
       <text:p>Err:502</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="string" calcext:value-type="string">
@@ -1605,8 +1605,8 @@
      <table:table-cell table:style-name="ce15" table:formula="of:=ISERROR([.A12])" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>PRAVDA</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A12])" office:value-type="string" office:string-value="=AMORDEGRC(-10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;4)" calcext:value-type="string">
-      <text:p>=AMORDEGRC(-10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;4)</text:p>
+     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A12])" office:value-type="string" office:string-value="=AMORDEGRC(-10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;4)" calcext:value-type="string">
+      <text:p>=AMORDEGRC(-10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;4)</text:p>
      </table:table-cell>
      <table:table-cell table:number-columns-repeated="5"/>
      <table:table-cell office:value-type="float" office:value="2" calcext:value-type="float">
@@ -1615,7 +1615,7 @@
      <table:table-cell table:number-columns-repeated="4"/>
     </table:table-row>
     <table:table-row table:style-name="ro10">
-     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);-1500;1;0.3;4)" office:value-type="string" office:string-value="" calcext:value-type="error">
+     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);-1500;1;0.31;4)" office:value-type="string" office:string-value="" calcext:value-type="error">
       <text:p>Err:502</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="string" calcext:value-type="string">
@@ -1624,8 +1624,8 @@
      <table:table-cell table:style-name="ce15" table:formula="of:=ISERROR([.A13])" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>PRAVDA</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A13])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);-1500;1;0,3;4)" calcext:value-type="string">
-      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);-1500;1;0,3;4)</text:p>
+     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A13])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);-1500;1;0,31;4)" calcext:value-type="string">
+      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);-1500;1;0,31;4)</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="string" calcext:value-type="string">
       <text:p>Tdf #100523</text:p>
@@ -1638,7 +1638,7 @@
      <table:table-cell table:style-name="ce28" table:number-columns-repeated="3"/>
     </table:table-row>
     <table:table-row table:style-name="ro10">
-     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;-0.3;4)" office:value-type="string" office:string-value="" calcext:value-type="error">
+     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;-0.31;4)" office:value-type="string" office:string-value="" calcext:value-type="error">
       <text:p>Err:502</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="string" calcext:value-type="string">
@@ -1647,8 +1647,8 @@
      <table:table-cell table:style-name="ce18" table:formula="of:=ISERROR([.A14])" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>PRAVDA</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A14])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;-0,3;4)" calcext:value-type="string">
-      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;-0,3;4)</text:p>
+     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A14])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;-0,31;4)" calcext:value-type="string">
+      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;-0,31;4)</text:p>
      </table:table-cell>
      <table:table-cell table:number-columns-repeated="5"/>
      <table:table-cell office:value-type="float" office:value="4" calcext:value-type="float">
@@ -1695,13 +1695,13 @@
      <table:table-cell table:number-columns-repeated="11"/>
     </table:table-row>
     <table:table-row table:style-name="ro10">
-     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.3;2)" office:value-type="string" office:string-value="" calcext:value-type="error">
+     <table:table-cell table:formula="of:=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0.31;2)" office:value-type="string" office:string-value="" calcext:value-type="error">
       <text:p>Err:502</text:p>
      </table:table-cell>
      <table:table-cell/>
      <table:table-cell table:style-name="ce21"/>
-     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A19])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;2)" calcext:value-type="string">
-      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,3;2)</text:p>
+     <table:table-cell table:style-name="ce25" table:formula="of:=FORMULA([.A19])" office:value-type="string" office:string-value="=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;2)" calcext:value-type="string">
+      <text:p>=AMORDEGRC(10000;DATE(2012;3;1);DATE(2012;12;31);1500;1;0,31;2)</text:p>
      </table:table-cell>
      <table:table-cell office:value-type="string" calcext:value-type="string">
       <text:p>Basis 2 <text:s text:c="2"/>tdf#100496</text:p>
diff --git a/sc/qa/unit/data/functions/financial/fods/rate.fods b/sc/qa/unit/data/functions/financial/fods/rate.fods
index 15dc9068193c..87080a647c5e 100644
--- a/sc/qa/unit/data/functions/financial/fods/rate.fods
+++ b/sc/qa/unit/data/functions/financial/fods/rate.fods
@@ -2764,11 +2764,11 @@
      <table:table-cell table:number-columns-repeated="7"/>
     </table:table-row>
     <table:table-row table:style-name="ro6">
-     <table:table-cell table:formula="of:=RATE([.L19];[.L21];[.L20];[.L22];[.L23];[.L24])" office:value-type="float" office:value="0.2500000946085" calcext:value-type="float">
-      <text:p>0.2500000946085</text:p>
+     <table:table-cell table:formula="of:=RATE([.L19];[.L21];[.L20];[.L22];[.L23];[.L24])" office:value-type="float" office:value="0.250000092908987" calcext:value-type="float">
+      <text:p>0.250000092908987</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="0.2500000946085" calcext:value-type="float">
-      <text:p>0.2500000946085</text:p>
+     <table:table-cell office:value-type="float" office:value="0.250000092908987" calcext:value-type="float">
+      <text:p>0.250000092908987</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce22" table:formula="of:=ROUND([.A23];12)=ROUND([.B23];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
diff --git a/sc/qa/unit/data/functions/statistical/fods/betadist.fods b/sc/qa/unit/data/functions/statistical/fods/betadist.fods
index 7ecd1f7b4217..45848b5d1f0e 100644
--- a/sc/qa/unit/data/functions/statistical/fods/betadist.fods
+++ b/sc/qa/unit/data/functions/statistical/fods/betadist.fods
@@ -3665,11 +3665,11 @@
      <table:table-cell table:number-columns-repeated="3"/>
     </table:table-row>
     <table:table-row table:style-name="ro7">
-     <table:table-cell table:formula="of:=BETADIST([.I35];[.$J$13];[.$J$14];0;1;FALSE())" office:value-type="float" office:value="10251.4061542503" calcext:value-type="float">
-      <text:p>10251.4061542503</text:p>
+     <table:table-cell table:formula="of:=BETADIST([.I35];[.$J$13];[.$J$14];0;1;FALSE())" office:value-type="float" office:value="10251.4061622172" calcext:value-type="float">
+      <text:p>10251.4061622172</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="10251.4061542503" calcext:value-type="float">
-      <text:p>10251.4061542503</text:p>
+     <table:table-cell office:value-type="float" office:value="10251.4061622172" calcext:value-type="float">
+      <text:p>10251.4061622172</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce17" table:formula="of:=ROUND([.A34];12)=ROUND([.B34];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
@@ -3720,11 +3720,11 @@
      <table:table-cell table:number-columns-repeated="3"/>
     </table:table-row>
     <table:table-row table:style-name="ro7">
-     <table:table-cell table:formula="of:=BETADIST([.I37];[.$J$13];[.$J$14];0;1;FALSE())" office:value-type="float" office:value="6468148.8473596" calcext:value-type="float">
-      <text:p>6468148.8473596</text:p>
+     <table:table-cell table:formula="of:=BETADIST([.I37];[.$J$13];[.$J$14];0;1;FALSE())" office:value-type="float" office:value="6468199.11488617" calcext:value-type="float">
+      <text:p>6468199.11488617</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="6468148.8473596" calcext:value-type="float">
-      <text:p>6468148.847360</text:p>
+     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="6468199.11488617" calcext:value-type="float">
+      <text:p>6468199.11488617</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce17" table:formula="of:=ROUND([.A36];12)=ROUND([.B36];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
@@ -3749,11 +3749,11 @@
      <table:table-cell table:number-columns-repeated="3"/>
     </table:table-row>
     <table:table-row table:style-name="ro7">
-     <table:table-cell table:formula="of:=BETADIST([.I38];[.$J$13];[.$J$14];0;1;FALSE())" office:value-type="float" office:value="162564790.351024" calcext:value-type="float">
-      <text:p>162564790.351024</text:p>
+     <table:table-cell table:formula="of:=BETADIST([.I38];[.$J$13];[.$J$14];0;1;FALSE())" office:value-type="float" office:value="162438470.365225" calcext:value-type="float">
+      <text:p>162438470.365225</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="162564790.351024" calcext:value-type="float">
-      <text:p>162564790.351024</text:p>
+     <table:table-cell office:value-type="float" office:value="162438470.365225" calcext:value-type="float">
+      <text:p>162438470.365225</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce17" table:formula="of:=ROUND([.A37];12)=ROUND([.B37];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
@@ -3777,11 +3777,11 @@
      <table:table-cell table:number-columns-repeated="3"/>
     </table:table-row>
     <table:table-row table:style-name="ro7">
-     <table:table-cell table:formula="of:=BETADIST([.I39];[.$J$13];[.$J$14];0;1;FALSE())" office:value-type="float" office:value="4434383544.877" calcext:value-type="float">
-      <text:p>4434383544.877</text:p>
+     <table:table-cell table:formula="of:=BETADIST([.I39];[.$J$13];[.$J$14];0;1;FALSE())" office:value-type="float" office:value="4083442911.23905" calcext:value-type="float">
+      <text:p>4083442911.23905</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="4434383544.877" calcext:value-type="float">
-      <text:p>4434383544.877</text:p>
+     <table:table-cell office:value-type="float" office:value="4083442911.23905" calcext:value-type="float">
+      <text:p>4083442911.23905</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce17" table:formula="of:=ROUND([.A38];12)=ROUND([.B38];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
@@ -4861,11 +4861,11 @@
      <table:table-cell table:number-columns-repeated="19"/>
     </table:table-row>
     <table:table-row table:style-name="ro7">
-     <table:table-cell table:formula="of:=BETADIST([.I84];[.$J$68];[.$J$69];0;1;FALSE())" office:value-type="float" office:value="90528.0025044751" calcext:value-type="float">
-      <text:p>90528.0025044751</text:p>
+     <table:table-cell table:formula="of:=BETADIST([.I84];[.$J$68];[.$J$69];0;1;FALSE())" office:value-type="float" office:value="90528.00257483" calcext:value-type="float">
+      <text:p>90528.00257483</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="90528.0025044751" calcext:value-type="float">
-      <text:p>90528.002504</text:p>
+     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="90528.00257483" calcext:value-type="float">
+      <text:p>90528.00257483</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce17" table:formula="of:=ROUND([.A81];12)=ROUND([.B81];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
@@ -4903,11 +4903,11 @@
      <table:table-cell table:number-columns-repeated="19"/>
     </table:table-row>
     <table:table-row table:style-name="ro7">
-     <table:table-cell table:formula="of:=BETADIST([.I86];[.$J$68];[.$J$69];0;1;FALSE())" office:value-type="float" office:value="57119197.8430585" calcext:value-type="float">
-      <text:p>57119197.8430585</text:p>
+     <table:table-cell table:formula="of:=BETADIST([.I86];[.$J$68];[.$J$69];0;1;FALSE())" office:value-type="float" office:value="57119641.747623" calcext:value-type="float">
+      <text:p>57119641.747623</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="57119197.8430585" calcext:value-type="float">
-      <text:p>57119197.843059</text:p>
+     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="57119641.747623" calcext:value-type="float">
+      <text:p>57119641.747623</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce17" table:formula="of:=ROUND([.A83];12)=ROUND([.B83];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
@@ -4924,11 +4924,11 @@
      <table:table-cell table:number-columns-repeated="19"/>
     </table:table-row>
     <table:table-row table:style-name="ro7">
-     <table:table-cell table:formula="of:=BETADIST([.I87];[.$J$68];[.$J$69];0;1;FALSE())" office:value-type="float" office:value="1435583912.33735" calcext:value-type="float">
-      <text:p>1435583912.33735</text:p>
+     <table:table-cell table:formula="of:=BETADIST([.I87];[.$J$68];[.$J$69];0;1;FALSE())" office:value-type="float" office:value="1434468400.5526" calcext:value-type="float">
+      <text:p>1434468400.5526</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="1435583912.33735" calcext:value-type="float">
-      <text:p>1435583912.337350</text:p>
+     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="1434468400.5526" calcext:value-type="float">
+      <text:p>1434468400.5526</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce17" table:formula="of:=ROUND([.A84];12)=ROUND([.B84];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
@@ -4945,11 +4945,11 @@
      <table:table-cell table:number-columns-repeated="19"/>
     </table:table-row>
     <table:table-row table:style-name="ro7">
-     <table:table-cell table:formula="of:=BETADIST([.I88];[.$J$68];[.$J$69];0;1;FALSE())" office:value-type="float" office:value="39159338651.6891" calcext:value-type="float">
-      <text:p>39159338651.6891</text:p>
+     <table:table-cell table:formula="of:=BETADIST([.I88];[.$J$68];[.$J$69];0;1;FALSE())" office:value-type="float" office:value="36060237507.1468" calcext:value-type="float">
+      <text:p>36060237507.1468</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="39159338651.6891" calcext:value-type="float">
-      <text:p>39159338651.689100</text:p>
+     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="36060237507.1468" calcext:value-type="float">
+      <text:p>36060237507.1468</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce17" table:formula="of:=ROUND([.A85];12)=ROUND([.B85];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
diff --git a/sc/qa/unit/data/functions/statistical/fods/chiinv.fods b/sc/qa/unit/data/functions/statistical/fods/chiinv.fods
index d8c1cf930361..fa107b013cdd 100644
--- a/sc/qa/unit/data/functions/statistical/fods/chiinv.fods
+++ b/sc/qa/unit/data/functions/statistical/fods/chiinv.fods
@@ -2925,11 +2925,11 @@
      <table:table-cell/>
     </table:table-row>
     <table:table-row table:style-name="ro7">
-     <table:table-cell table:formula="of:=LEGACY.CHIINV([.F8];[.G8])" office:value-type="float" office:value="0.005035400390625" calcext:value-type="float">
-      <text:p>0.005035400390625</text:p>
+     <table:table-cell table:formula="of:=LEGACY.CHIINV([.F8];[.G8])" office:value-type="float" office:value="0.00518798828125" calcext:value-type="float">
+      <text:p>0.00518798828125</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="0.005035400390625" calcext:value-type="float">
-      <text:p>0.005035400390625</text:p>
+     <table:table-cell office:value-type="float" office:value="0.00518798828125" calcext:value-type="float">
+      <text:p>0.00518798828125</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce15" table:formula="of:=ROUND([.A8];12)=ROUND([.B8];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
diff --git a/sc/qa/unit/data/functions/statistical/fods/forecast.ets.mult.fods b/sc/qa/unit/data/functions/statistical/fods/forecast.ets.mult.fods
index 37aa304d199b..9741ba7dc9a2 100644
--- a/sc/qa/unit/data/functions/statistical/fods/forecast.ets.mult.fods
+++ b/sc/qa/unit/data/functions/statistical/fods/forecast.ets.mult.fods
@@ -7804,7 +7804,7 @@
      <table:table-cell office:value-type="float" office:value="61.9729295871504" calcext:value-type="float">
       <text:p>61.9729295871504</text:p>
      </table:table-cell>
-     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="61.9729295871504" calcext:value-type="float">
+     <table:table-cell table:style-name="ce14" office:value-type="float" office:value="61.97292958715045" calcext:value-type="float">
       <text:p>61.972930</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce16" table:formula="of:=ROUND([.A49];12)=ROUND([.B49];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
diff --git a/sc/qa/unit/data/functions/statistical/fods/tinv.fods b/sc/qa/unit/data/functions/statistical/fods/tinv.fods
index 89832a2a16c3..99d93baa3311 100644
--- a/sc/qa/unit/data/functions/statistical/fods/tinv.fods
+++ b/sc/qa/unit/data/functions/statistical/fods/tinv.fods
@@ -4608,11 +4608,11 @@
      <table:table-cell table:number-columns-repeated="2"/>
     </table:table-row>
     <table:table-row table:style-name="ro6">
-     <table:table-cell table:style-name="ce77" office:value-type="float" office:value="0.148831111963765" calcext:value-type="float">
-      <text:p>1.48831111963765E-001</text:p>
+     <table:table-cell table:style-name="ce77" office:value-type="float" office:value="0.148831111963764" calcext:value-type="float">
+      <text:p>1.48831111963764E-001</text:p>
      </table:table-cell>
-     <table:table-cell office:value-type="float" office:value="0.148831111963765" calcext:value-type="float">
-      <text:p>0.148831111963765</text:p>
+     <table:table-cell office:value-type="float" office:value="0.148831111963764" calcext:value-type="float">
+      <text:p>0.148831111963764</text:p>
      </table:table-cell>
      <table:table-cell table:style-name="ce79" table:formula="of:=ORG.LIBREOFFICE.ROUNDSIG([.A29];15)=ORG.LIBREOFFICE.ROUNDSIG([.B29];15)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean">
       <text:p>TRUE</text:p>
diff --git a/sd/qa/unit/export-tests-ooxml2.cxx b/sd/qa/unit/export-tests-ooxml2.cxx
index 8f1436a340eb..2a1802f138ab 100644
--- a/sd/qa/unit/export-tests-ooxml2.cxx
+++ b/sd/qa/unit/export-tests-ooxml2.cxx
@@ -2104,7 +2104,7 @@ void SdOOXMLExportTest2::testTdf118825()
 
     const OUString sPath2 = "M 0.025 0.0571428571428571 L 0.0821428571428571 0.184126984126984 L -0.175 0.234920634920635 L -0.246428571428571 -0.0190476190476191 L -0.0821428571428573 -0.133333333333333 E";
 
-    const OUString sPath3 = "M -0.0107142857142857 0.00634920634920635 C -0.110714285714286 0.501587301587301 -0.153571428571429 -0.00634920634920635 -0.246428571428572 0.184126984126984 C -0.339285714285715 0.374603174603175 -0.296428571428572 0.514285714285714 -0.267857142857143 0.603174603174603 C -0.239285714285715 0.692063492063493 0.0607142857142858 0.590476190476191 0.0607142857142858 0.590476190476191 E";
+    const OUString sPath3 = "M -0.0107142857142857 0.00634920634920635 C -0.110714285714286 0.501587301587301 -0.153571428571429 -0.00634920634920635 -0.246428571428572 0.184126984126984 C -0.339285714285715 0.374603174603175 -0.296428571428572 0.514285714285714 -0.267857142857143 0.603174603174603 C -0.239285714285715 0.692063492063492 0.0607142857142858 0.590476190476191 0.0607142857142858 0.590476190476191 E";
 
     const OUString sPath4 = "M 0.0535714285714286 -0.0444444444444444 L 0.132142857142857 -0.0444444444444444 L 0.132142857142857 -0.146031746031746 L 0.0964285714285715 -0.146031746031746 E";
 
commit f3e7004794eded346d98264d3061f4e4aa80ee0a
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Sun Feb 23 19:19:10 2020 +0300
Commit:     Mike Kaganski <mike.kaganski at collabora.com>
CommitDate: Thu Feb 27 11:02:03 2020 +0100

    tdf#130725: use strtod by David M. Gay to make sure we get the nearest
    
    ... representation of given decimal.
    Use dtoa.c from https://www.netlib.org/fp/dtoa.c to build a custom
    static library that doesn't use current locale (unlike strtod from
    stdlib.h).  This is the implementation used by e.g. python and nss
    (search for "dtoa.c" under UnpackedTarball).
    
    To avoid name clash with the standard strtod, rename the function
    to strtod_nolocale.
    
    Size of buffer on stack in ImpSvNumberInputScan::StringToDouble is
    256 characters. Logging function usage in make check, of ~124 600
    invocations, the longest string was 14 characters, average being
    2.1 characters. So heap allocation is unlikely in scenarios with
    intensive function usage.
    
    After std::from_chars is available in baseline compilers, external
    library can be dropped, and call to strtod_nolocale replaced with
    the standard function.
    
    The artifact at https://dev-www.libreoffice.org/src/dtoa-20180411.tgz
    is created with
    
      mkdir dtoa && mkdir dtoa/src && wget https://www.netlib.org/fp/dtoa.c -O dtoa/src/dtoa.c && \
       printf 'd8bab255476f39ea495c8c8ed164f9077da926e6ca7afb9ad3c56d337c4484fe dtoa/src/dtoa.c' | sha256sum -c && \
       tar -c --owner=0 --group=0 --mode=go=r,u=rw --mtime='Wed, 11 Apr 2018 15:59:39 GMT' dtoa/src/dtoa.c | gzip -n > dtoa-20180411.tgz && \
       printf '0082d0684f7db6f62361b76c4b7faba19e0c7ce5cb8e36c4b65fea8281e711b4 dtoa-20180411.tgz' | sha256sum -c
    
    (where the date "Wed, 11 Apr 2018 15:59:39 GMT" is from
    `wget -S https://www.netlib.org/fp/dtoa.c`
    "Last-Modified: Wed, 11 Apr 2018 15:59:39 GMT" header).
    
    Change-Id: Ia61b7678e257c4bc1ff193f3f856d611aa5c1a21
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88854
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/Makefile.fetch b/Makefile.fetch
index 1fe9970f6237..cfa3dc58c3a5 100644
--- a/Makefile.fetch
+++ b/Makefile.fetch
@@ -112,6 +112,7 @@ $(WORKDIR)/download: $(BUILDDIR)/config_$(gb_Side).mk $(SRCDIR)/download.lst $(S
 		$(call fetch_Optional,CAIRO,PIXMAN_TARBALL) \
 		$(call fetch_Optional,CDR,CDR_TARBALL) \
 		$(call fetch_Optional,CLUCENE,CLUCENE_TARBALL) \
+		DTOA_TARBALL \
 		$(call fetch_Optional,LIBCMIS,LIBCMIS_TARBALL) \
 		$(call fetch_Optional,COINMP,COINMP_TARBALL) \
 		$(call fetch_Optional,CPPUNIT,CPPUNIT_TARBALL) \
diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk
index 1f36dda8f202..a0de7e340de8 100644
--- a/RepositoryExternal.mk
+++ b/RepositoryExternal.mk
@@ -4206,6 +4206,23 @@ endef
 
 endif # SYSTEM_QRCODEGEN
 
+define gb_LinkTarget__use_dtoa
+$(call gb_LinkTarget_use_unpacked,$(1),dtoa)
+$(call gb_LinkTarget_set_include,$(1),\
+	-I$(call gb_UnpackedTarball_get_dir,dtoa/include/)\
+	$$(INCLUDE) \
+)
+$(call gb_LinkTarget_use_static_libraries,$(1),\
+	dtoa \
+)
+
+endef
+
+define gb_ExternalProject__use_dtoa
+$(call gb_ExternalProject_use_static_libraries,$(1),dtoa)
+
+endef
+
 $(eval $(call gb_Helper_register_packages_for_install,ucrt_binarytable,\
 	$(if $(UCRT_REDISTDIR),ucrt) \
 ))
diff --git a/download.lst b/download.lst
index 910e1e09ad47..7141467b9fe3 100644
--- a/download.lst
+++ b/download.lst
@@ -21,6 +21,8 @@ export CDR_SHA256SUM := 01cd00b04a030977e544433c2d127c997205332cd9b8e35ec0ee1711
 export CDR_TARBALL := libcdr-0.1.6.tar.xz
 export CLUCENE_SHA256SUM := ddfdc433dd8ad31b5c5819cc4404a8d2127472a3b720d3e744e8c51d79732eab
 export CLUCENE_TARBALL := 48d647fbd8ef8889e5a7f422c1bfda94-clucene-core-2.3.3.4.tar.gz
+export DTOA_SHA256SUM := 0082d0684f7db6f62361b76c4b7faba19e0c7ce5cb8e36c4b65fea8281e711b4
+export DTOA_TARBALL := dtoa-20180411.tgz
 export LIBCMIS_SHA256SUM := d7b18d9602190e10d437f8a964a32e983afd57e2db316a07d87477a79f5000a2
 export LIBCMIS_TARBALL := libcmis-0.5.2.tar.xz
 export COINMP_SHA256SUM := 86c798780b9e1f5921fe4efe651a93cb420623b45aa1fdff57af8c37f116113f
diff --git a/external/Module_external.mk b/external/Module_external.mk
index 08086c3e2985..286759927781 100644
--- a/external/Module_external.mk
+++ b/external/Module_external.mk
@@ -31,6 +31,7 @@ $(eval $(call gb_Module_add_moduledirs,external,\
 	$(call gb_Helper_optional,CPPUNIT,cppunit) \
 	$(call gb_Helper_optional,CT2N,ct2n) \
 	$(call gb_Helper_optional,CURL,curl) \
+	dtoa \
 	$(call gb_Helper_optional,EBOOK,libebook) \
 	$(call gb_Helper_optional,EPM,epm) \
 	$(call gb_Helper_optional,EPOXY,epoxy) \
diff --git a/external/dtoa/Module_dtoa.mk b/external/dtoa/Module_dtoa.mk
new file mode 100644
index 000000000000..c652f97e0b58
--- /dev/null
+++ b/external/dtoa/Module_dtoa.mk
@@ -0,0 +1,17 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Module_Module,dtoa))
+
+$(eval $(call gb_Module_add_targets,dtoa,\
+    UnpackedTarball_dtoa \
+    StaticLibrary_dtoa \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/external/dtoa/README b/external/dtoa/README
new file mode 100644
index 000000000000..9f46b9865d84
--- /dev/null
+++ b/external/dtoa/README
@@ -0,0 +1,10 @@
+dtoa is available from [ https://www.netlib.org/fp/ ].
+
+Used to convert a decimal string to double (until std::from_chars is available on used compilers).
+Packaged using
+
+  mkdir dtoa && mkdir dtoa/src && wget https://www.netlib.org/fp/dtoa.c -O dtoa/src/dtoa.c && \
+   printf 'd8bab255476f39ea495c8c8ed164f9077da926e6ca7afb9ad3c56d337c4484fe dtoa/src/dtoa.c' | sha256sum -c && \
+   tar -c --owner=0 --group=0 --mode=go=r,u=rw --mtime='Wed, 11 Apr 2018 15:59:39 GMT' dtoa/src/dtoa.c | gzip -n > dtoa-20180411.tgz && \
+   printf '0082d0684f7db6f62361b76c4b7faba19e0c7ce5cb8e36c4b65fea8281e711b4 dtoa-20180411.tgz' | sha256sum -c
+(where the date "Wed, 11 Apr 2018 15:59:39 GMT" is from `wget -S https://www.netlib.org/fp/dtoa.c` "Last-Modified: Wed, 11 Apr 2018 15:59:39 GMT" header).
diff --git a/external/dtoa/StaticLibrary_dtoa.mk b/external/dtoa/StaticLibrary_dtoa.mk
new file mode 100644
index 000000000000..edb358c21da4
--- /dev/null
+++ b/external/dtoa/StaticLibrary_dtoa.mk
@@ -0,0 +1,22 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_StaticLibrary_StaticLibrary,dtoa))
+
+$(eval $(call gb_StaticLibrary_use_unpacked,dtoa,dtoa))
+
+$(eval $(call gb_StaticLibrary_add_cflags,dtoa,-DIEEE_8087))
+
+$(eval $(call gb_StaticLibrary_set_warnings_disabled,dtoa))
+
+$(eval $(call gb_StaticLibrary_add_generated_cobjects,dtoa,\
+    UnpackedTarball/dtoa/src/dtoa \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/external/dtoa/UnpackedTarball_dtoa.mk b/external/dtoa/UnpackedTarball_dtoa.mk
new file mode 100644
index 000000000000..c700b485fe8c
--- /dev/null
+++ b/external/dtoa/UnpackedTarball_dtoa.mk
@@ -0,0 +1,20 @@
+#-*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_UnpackedTarball_UnpackedTarball,dtoa))
+
+$(eval $(call gb_UnpackedTarball_set_tarball,dtoa,$(DTOA_TARBALL)))
+
+$(eval $(call gb_UnpackedTarball_set_patchlevel,dtoa,1))
+
+$(eval $(call gb_UnpackedTarball_add_patches,dtoa, \
+    external/dtoa/include_header.patch \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/external/dtoa/include_header.patch b/external/dtoa/include_header.patch
new file mode 100644
index 000000000000..c34c78d3f6aa
--- /dev/null
+++ b/external/dtoa/include_header.patch
@@ -0,0 +1,37 @@
+--- /dev/null
++++ dtoa/include/dtoa.h
+@@ -0,0 +1,3 @@
++extern "C" double strtod_nolocale(const char *s00, char **se);
++extern "C" char *dtoa_nolocale(double d, int mode, int ndigits,
++			int *decpt, int *sign, char **rve);
+--- dtoa/src/dtoa.c.orig
++++ dtoa/src/dtoa.c
+@@ -1502,8 +1502,8 @@ static unsigned int maxthreads = 0;
+ #define Kmax 7
+ 
+ #ifdef __cplusplus
+-extern "C" double strtod(const char *s00, char **se);
+-extern "C" char *dtoa(double d, int mode, int ndigits,
++extern "C" double strtod_nolocale(const char *s00, char **se);
++extern "C" char *dtoa_nolocale(double d, int mode, int ndigits,
+ 			int *decpt, int *sign, char **rve);
+ #endif
+ 
+@@ -3429,7 +3429,7 @@ retlow1:
+ #endif /* NO_STRTOD_BIGCOMP */
+ 
+  double
+-strtod(const char *s00, char **se)
++strtod_nolocale(const char *s00, char **se)
+ {
+ 	int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1;
+ 	int esign, i, j, k, nd, nd0, nf, nz, nz0, nz1, sign;
+@@ -6185,7 +6185,7 @@ dtoa_r(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve, char
+ 	}
+ 
+  char *
+-dtoa(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve)
++dtoa_nolocale(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve)
+ {
+ 	/*	Sufficient space is allocated to the return value
+ 		to hold the suppressed trailing zeros.
diff --git a/readlicense_oo/license/license.xml b/readlicense_oo/license/license.xml
index 0d4c93d7e9cd..d032d410be98 100644
--- a/readlicense_oo/license/license.xml
+++ b/readlicense_oo/license/license.xml
@@ -1849,6 +1849,25 @@
     Software.</p>
     </blockquote>
     </div>
+    <h2>dtoa</h2>
+    <p>The following software may be included in this product: dtoa.</p>
+    <p>dtoa code is covered by the MIT license:</p>
+    <blockquote>
+    <p> The author of this software is David M. Gay.</p>
+
+    <p> Copyright (c) 1991, 2000, 2001 by Lucent Technologies.</p>
+
+    <p>Permission to use, copy, modify, and distribute this software for any
+    purpose without fee is hereby granted, provided that this entire notice
+    is included in all copies of any software which is or includes a copy
+    or modification of this software and in all copies of the supporting
+    documentation for such software.</p>
+
+    <p>THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+    WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+    REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+    OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.</p>
+    </blockquote>
     <h2>Random123: a Library of Counter-Based Random Number Generators</h2>
     <p>The following software may be included in this product: Random123: a Library of Counter-Based Random Number
     Generators. Use of any of this software is governed by the terms of the license below:</p>
diff --git a/sc/qa/unit/bugfix-test.cxx b/sc/qa/unit/bugfix-test.cxx
index d0cf10a74b9b..2b2523319cec 100644
--- a/sc/qa/unit/bugfix-test.cxx
+++ b/sc/qa/unit/bugfix-test.cxx
@@ -47,6 +47,7 @@ public:
     void testTdf31231();
     void testTdf128951();
     void testTdf129789();
+    void testTdf130725();
 
     CPPUNIT_TEST_SUITE(ScFiltersTest);
     CPPUNIT_TEST(testTdf64229);
@@ -64,6 +65,7 @@ public:
     CPPUNIT_TEST(testTdf31231);
     CPPUNIT_TEST(testTdf128951);
     CPPUNIT_TEST(testTdf129789);
+    CPPUNIT_TEST(testTdf130725);
     CPPUNIT_TEST_SUITE_END();
 private:
     uno::Reference<uno::XInterface> m_xCalcComponent;
@@ -470,6 +472,34 @@ void ScFiltersTest::testTdf129789()
     xDocSh->DoClose();
 }
 
+void ScFiltersTest::testTdf130725()
+{
+    css::uno::Reference<css::frame::XDesktop2> xDesktop
+        = css::frame::Desktop::create(comphelper::getProcessComponentContext());
+    CPPUNIT_ASSERT(xDesktop.is());
+
+    // 1. Create spreadsheet
+    css::uno::Sequence<css::beans::PropertyValue> aHiddenArgList(1);
+    aHiddenArgList[0].Name = "Hidden";
+    aHiddenArgList[0].Value <<= true;
+
+    css::uno::Reference<css::lang::XComponent> xComponent
+        = xDesktop->loadComponentFromURL("private:factory/scalc", "_blank", 0, aHiddenArgList);
+    css::uno::Reference<css::sheet::XSpreadsheetDocument> xDoc(xComponent,
+        css::uno::UNO_QUERY_THROW);
+
+    // 2. Insert 0.0042 into a cell as a formula, to force the conversion from string to double
+    css::uno::Reference<css::sheet::XCellRangesAccess> xSheets(xDoc->getSheets(),
+        css::uno::UNO_QUERY_THROW);
+    css::uno::Reference<css::table::XCell> xCell = xSheets->getCellByPosition(0, 0, 0);
+    xCell->setFormula("0.0042"); // this assumes en-US locale
+
+    // 3. Check that the value is the nearest double-precision representation of the decimal 0.0042
+    //    (it was 0.0042000000000000006 instead of 0.0041999999999999997).
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Value must be the nearest representation of decimal 0.0042",
+        0.0042, xCell->getValue()); // strict equality
+}
+
 ScFiltersTest::ScFiltersTest()
       : ScBootstrapFixture( "sc/qa/unit/data" )
 {
diff --git a/svl/Library_svl.mk b/svl/Library_svl.mk
index c49417d21512..b2ed3f5a6089 100644
--- a/svl/Library_svl.mk
+++ b/svl/Library_svl.mk
@@ -23,6 +23,7 @@ $(eval $(call gb_Library_use_externals,svl,\
     boost_headers \
     $(if $(filter LINUX MACOSX ANDROID %BSD SOLARIS HAIKU,$(OS)), \
         curl) \
+    dtoa \
     icu_headers \
     icuuc \
     mdds_headers \
diff --git a/svl/source/numbers/zforfind.cxx b/svl/source/numbers/zforfind.cxx
index e56a5cef8502..32b471a5df23 100644
--- a/svl/source/numbers/zforfind.cxx
+++ b/svl/source/numbers/zforfind.cxx
@@ -18,6 +18,7 @@
  */
 
 #include <cstdlib>
+#include <dtoa.h>
 #include <float.h>
 #include <comphelper/string.hxx>
 #include <sal/log.hxx>
@@ -36,6 +37,8 @@
 #include "zforscan.hxx"
 #include <svl/zformat.hxx>
 
+#include <memory>
+
 #include "zforfind.hxx"
 
 #ifndef DBG_UTIL
@@ -151,35 +154,30 @@ static void TransformInput( SvNumberFormatter const * pFormatter, OUString& rStr
  */
 double ImpSvNumberInputScan::StringToDouble( const OUString& rStr, bool bForceFraction )
 {
-    double fNum = 0.0;
-    double fFrac = 0.0;
-    int nExp = 0;
-    sal_Int32 nPos = 0;
-    sal_Int32 nLen = rStr.getLength();
-    bool bPreSep = !bForceFraction;
-
-    while (nPos < nLen)
+    std::unique_ptr<char[]> bufInHeap;
+    constexpr int bufOnStackSize = 256;
+    char bufOnStack[bufOnStackSize];
+    char* buf = bufOnStack;
+    const sal_Int32 bufsize = rStr.getLength() + (bForceFraction ? 2 : 1);
+    if (bufsize > bufOnStackSize)
     {
-        if (rStr[nPos] == '.')
-        {
-            bPreSep = false;
-        }
-        else if (bPreSep)
-        {
-            fNum = fNum * 10.0 + static_cast<double>(rStr[nPos] - '0');
-        }
-        else
-        {
-            fFrac = fFrac * 10.0 + static_cast<double>(rStr[nPos] - '0');
-            --nExp;
-        }
-        nPos++;
+        bufInHeap = std::make_unique<char[]>(bufsize);
+        buf = bufInHeap.get();
     }
-    if ( fFrac )
+    char* p = buf;
+    if (bForceFraction)
+        *p++ = '.';
+    for (sal_Int32 nPos = 0; nPos < rStr.getLength(); ++nPos)
     {
-        return fNum + ::rtl::math::pow10Exp( fFrac, nExp );
+        sal_Unicode c = rStr[nPos];
+        if (c == '.' || (c >= '0' && c <= '9'))
+            *p++ = static_cast<char>(c);
+        else
+            break;
     }
-    return fNum;
+    *p = '\0';
+
+    return strtod_nolocale(buf, nullptr);
 }
 
 namespace {


More information about the Libreoffice-commits mailing list