[Libreoffice-commits] core.git: Branch 'libreoffice-5-1' - sal/qa sal/rtl

Eike Rathke erack at redhat.com
Fri Jan 15 05:24:12 PST 2016


 sal/qa/rtl/math/test-rtl-math.cxx |   55 +++++++++++++++++++++++++
 sal/rtl/math.cxx                  |   82 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 137 insertions(+)

New commits:
commit e480172cb91b4adca6a7fcd42f68c2ff2874fe54
Author: Eike Rathke <erack at redhat.com>
Date:   Wed Jan 13 14:40:12 2016 +0100

    tdf#96918 display accurate integer double values up to (2^53)-1
    
    (cherry picked from commit 0f6203edf74832f84d8263d7a544d679203a4efc)
    
    unit test for tdf#96918 display accurate integer double values
    
    (cherry picked from commit a3f5f4f6369552a3da870de1ed4ea9d8c628c7a8)
    
    619e0cb0fbbfd0dfba3b2fe9c3476be55a3eea8e
    
    sal: as always C++ is too stupid to deduce parameter types of min
    
    (cherry picked from commit 2d526a9ffbad7effaabb70f4e52904c09d0ab22b)
    
    b00f29a6024e22c65a30bf4a45332e550994f03f
    
    loplugin:defaultparams
    
    (cherry picked from commit 036b4a366ecc7ea343a3fedee268463d6576cb32)
    
    Keep MSVC happy
    
    (warning C4305 when converting 9007199254740993 from __int64 to double)
    
    (cherry picked from commit e5d393cf0edc5d871cfe1aea6acede482eecec84)
    
    handle negative decimal places for rounding, tdf#96918 related
    
    (cherry picked from commit fdf982f70b2944053d995baaa3d78c7cdc4bbc4b)
    
    unit test for negative decimal places rounding, tdf#96918 related
    
    (cherry picked from commit 5299400e5cce3060a0de85bb4dedd065b5ad1f41)
    
    use getN10Exp(x) instead of pow(10.0,x)
    
    (cherry picked from commit e6c9bdfdc181c95d5757b96b6194d639a0df3c79)
    
    use ::std::swap() to reverse buffer
    
    (cherry picked from commit f19b4826c44e9e5f54b968fef59a3fcd3007d522)
    
    0e2b92a01ba5ae1824d609ee2e557f1a1cc85cbd
    fa423eabc64ead519c4f4a3370a06e88ea5c7466
    b2f3ffaa7c4216b66479c750465c2beab927405a
    b7e49126cbffc510fa941c25a8d57222bad51c46
    7e18e57636416f0a3ed96c2fa3adc004fb3ba013
    507a16e1d87460dead79b78621202c68ee12c2c8
    
    Change-Id: I42001583c72bc3faab94489a4eabfa183cab5ae2
    Reviewed-on: https://gerrit.libreoffice.org/21429
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Michael Stahl <mstahl at redhat.com>

diff --git a/sal/qa/rtl/math/test-rtl-math.cxx b/sal/qa/rtl/math/test-rtl-math.cxx
index aa7b213..3de4956 100644
--- a/sal/qa/rtl/math/test-rtl-math.cxx
+++ b/sal/qa/rtl/math/test-rtl-math.cxx
@@ -88,6 +88,60 @@ public:
         CPPUNIT_ASSERT_EQUAL(0.0, res);
     }
 
+    void test_doubleToString() {
+        double fVal = 999999999999999.0;
+        sal_Int32 aGroups[3] = { 3, 2, 0 };
+        rtl::OUString aRes( rtl::math::doubleToUString( fVal,
+                    rtl_math_StringFormat_Automatic,
+                    rtl_math_DecimalPlaces_Max,
+                    '.', aGroups, ',', true));
+        CPPUNIT_ASSERT_EQUAL( OUString("99,99,99,99,99,99,999"), aRes);
+
+        fVal = 949.0;
+        aRes = rtl::math::doubleToUString( fVal,
+                    rtl_math_StringFormat_Automatic,
+                    -2,     // round before decimals
+                    '.', aGroups, ',', true);
+        CPPUNIT_ASSERT_EQUAL( OUString("900"), aRes);
+
+        fVal = 950.0;
+        aRes = rtl::math::doubleToUString( fVal,
+                    rtl_math_StringFormat_Automatic,
+                    -2,     // round before decimals
+                    '.', aGroups, ',', true);
+        CPPUNIT_ASSERT_EQUAL( OUString("1,000"), aRes);
+
+        fVal = 4503599627370495.0;
+        aRes = rtl::math::doubleToUString( fVal,
+                    rtl_math_StringFormat_Automatic,
+                    rtl_math_DecimalPlaces_Max, '.');
+        CPPUNIT_ASSERT_EQUAL( OUString("4503599627370495"), aRes);
+
+        fVal = 4503599627370496.0;
+        aRes = rtl::math::doubleToUString( fVal,
+                    rtl_math_StringFormat_Automatic,
+                    2, '.');
+        CPPUNIT_ASSERT_EQUAL( OUString("4503599627370496.00"), aRes);
+
+        fVal = 9007199254740991.0;  // (2^53)-1
+        aRes = rtl::math::doubleToUString( fVal,
+                    rtl_math_StringFormat_Automatic,
+                    rtl_math_DecimalPlaces_Max, '.', true);
+        CPPUNIT_ASSERT_EQUAL( OUString("9007199254740991"), aRes);
+
+        fVal = 9007199254740992.0;  // (2^53), algorithm switch
+        aRes = rtl::math::doubleToUString( fVal,
+                    rtl_math_StringFormat_Automatic,
+                    rtl_math_DecimalPlaces_Max, '.', true);
+        CPPUNIT_ASSERT_EQUAL( OUString("9.00719925474099E+015"), aRes);
+
+        fVal = 9007199254740993.0;  // (2^53)+1 would be but is 9007199254740992
+        aRes = rtl::math::doubleToUString( fVal,
+                    rtl_math_StringFormat_Automatic,
+                    rtl_math_DecimalPlaces_Max, '.', true);
+        CPPUNIT_ASSERT_EQUAL( OUString("9.00719925474099E+015"), aRes);
+    }
+
     void test_erf() {
         double x, res;
         x =  0.0;
@@ -176,6 +230,7 @@ public:
     CPPUNIT_TEST(test_stringToDouble_good);
     CPPUNIT_TEST(test_stringToDouble_bad);
     CPPUNIT_TEST(test_stringToDouble_exponent_without_digit);
+    CPPUNIT_TEST(test_doubleToString);
     CPPUNIT_TEST(test_erf);
     CPPUNIT_TEST(test_erfc);
     CPPUNIT_TEST(test_expm1);
diff --git a/sal/rtl/math.cxx b/sal/rtl/math.cxx
index fd33130..49d1544 100644
--- a/sal/rtl/math.cxx
+++ b/sal/rtl/math.cxx
@@ -207,6 +207,88 @@ inline void doubleToString(StringT ** pResult,
         return;
     }
 
+    // Use integer representation for integer values that fit into the
+    // mantissa (1.((2^53)-1)) with a precision of 1 for highest accuracy.
+    const sal_Int64 kMaxInt = (static_cast<sal_Int64>(1) << 53) - 1;
+    if ((eFormat == rtl_math_StringFormat_Automatic ||
+         eFormat == rtl_math_StringFormat_F) && fValue <= static_cast<double>(kMaxInt))
+    {
+        sal_Int64 nInt = static_cast<sal_Int64>(fValue);
+        // Check the integer range again because double comparison may yield
+        // true within the precision range.
+        if (nInt <= kMaxInt && static_cast<double>(nInt) == fValue)
+        {
+            if (nDecPlaces == rtl_math_DecimalPlaces_Max)
+                nDecPlaces = 0;
+            else
+                nDecPlaces = ::std::max<sal_Int32>( ::std::min<sal_Int32>( nDecPlaces, 15), -15);
+            if (bEraseTrailingDecZeros && nDecPlaces > 0)
+                nDecPlaces = 0;
+
+            // Round before decimal position.
+            if (nDecPlaces < 0)
+            {
+                sal_Int64 nRounding = static_cast<sal_Int64>( getN10Exp( -nDecPlaces - 1));
+                sal_Int64 nTemp = nInt / nRounding;
+                int nDigit = nTemp % 10;
+                nTemp /= 10;
+                if (nDigit >= 5)
+                    ++nTemp;
+                nTemp *= 10;
+                nTemp *= nRounding;
+                nInt = nTemp;
+                nDecPlaces = 0;
+            }
+
+            // Max 1 sign, 16 integer digits, 15 group separators, 1 decimal
+            // separator, 15 decimals digits.
+            typename T::Char aBuf[64];
+            typename T::Char * pBuf = aBuf;
+            typename T::Char * p = pBuf;
+
+            // Backward fill.
+            size_t nGrouping = 0;
+            sal_Int32 nGroupDigits = 0;
+            do
+            {
+                typename T::Char nDigit = nInt % 10;
+                nInt /= 10;
+                *p++ = nDigit + '0';
+                if (pGroups && pGroups[nGrouping] == ++nGroupDigits && nInt > 0 && cGroupSeparator)
+                {
+                    *p++ = cGroupSeparator;
+                    if (pGroups[nGrouping+1])
+                        ++nGrouping;
+                    nGroupDigits = 0;
+                }
+            }
+            while (nInt > 0);
+            if (bSign)
+                *p++ = '-';
+
+            // Reverse buffer content.
+            sal_Int32 n = (p - pBuf) / 2;
+            for (sal_Int32 i=0; i < n; ++i)
+            {
+                ::std::swap( pBuf[i], p[-i-1]);
+            }
+            // Append decimals.
+            if (nDecPlaces > 0)
+            {
+                *p++ = cDecSeparator;
+                while (nDecPlaces--)
+                    *p++ = '0';
+            }
+
+            if (pResultCapacity == nullptr)
+                T::createString(pResult, pBuf, p - pBuf);
+            else
+                T::appendChars(pResult, pResultCapacity, &nResultOffset, pBuf, p - pBuf);
+
+            return;
+        }
+    }
+
     // find the exponent
     int nExp = 0;
     if ( fValue > 0.0 )


More information about the Libreoffice-commits mailing list