[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