From 5f352a7289786e9648d0aca61a8ec867be4f4aa4 Mon Sep 17 00:00:00 2001 From: Eike Rathke Date: Wed, 29 Aug 2018 10:44:53 +0200 Subject: Round fraction if possible, else truncate; tools::Time::GetClock() With this also some test cases can be narrowed. Change-Id: Ic754baf135dbd362b80fac1cf080758f46017e01 Reviewed-on: https://gerrit.libreoffice.org/59753 Reviewed-by: Eike Rathke Tested-by: Jenkins --- tools/qa/cppunit/test_time.cxx | 30 ++++++++++++++++++++++++------ tools/source/datetime/ttime.cxx | 14 +++++++++++--- 2 files changed, 35 insertions(+), 9 deletions(-) (limited to 'tools') diff --git a/tools/qa/cppunit/test_time.cxx b/tools/qa/cppunit/test_time.cxx index 0de7190bf354..39c8476bce75 100644 --- a/tools/qa/cppunit/test_time.cxx +++ b/tools/qa/cppunit/test_time.cxx @@ -96,24 +96,42 @@ void TimeTest::testClockValues() CPPUNIT_ASSERT_EQUAL_MESSAGE("Hour value.", sal_uInt16(0), nHour); CPPUNIT_ASSERT_EQUAL_MESSAGE("Minute value.", sal_uInt16(0), nMinute); CPPUNIT_ASSERT_EQUAL_MESSAGE("Second value.", sal_uInt16(0), nSecond); - // Last digit may differ. - CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Fraction value.", 0.999, fFractionOfSecond, 1.1e-3); + // Expect this to be a truncated 0.999999 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Fraction value.", 0.999, fFractionOfSecond, 0.0); fTime = 0.524268391203704; Time::GetClock(fTime, nHour, nMinute, nSecond, fFractionOfSecond, 3); CPPUNIT_ASSERT_EQUAL_MESSAGE("Hour value.", sal_uInt16(12), nHour); CPPUNIT_ASSERT_EQUAL_MESSAGE("Minute value.", sal_uInt16(34), nMinute); CPPUNIT_ASSERT_EQUAL_MESSAGE("Second value.", sal_uInt16(56), nSecond); - // Last digit may differ. - CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Fraction value.", 0.789, fFractionOfSecond, 1.1e-3); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Fraction value.", 0.789, fFractionOfSecond, 0.0); fTime = -0.000001; - Time::GetClock(fTime, nHour, nMinute, nSecond, fFractionOfSecond, 9); + Time::GetClock(fTime, nHour, nMinute, nSecond, fFractionOfSecond, 13); CPPUNIT_ASSERT_EQUAL_MESSAGE("Hour value.", sal_uInt16(23), nHour); CPPUNIT_ASSERT_EQUAL_MESSAGE("Minute value.", sal_uInt16(59), nMinute); CPPUNIT_ASSERT_EQUAL_MESSAGE("Second value.", sal_uInt16(59), nSecond); // Expect this to be exact within floating point accuracy. - CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Fraction value.", 0.913599999, fFractionOfSecond, 1e-15); + // This is a hairy rounding condition, if it yields problems on any + // platform feel free to disable the test for that platform. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Fraction value.", 0.9135999999999, fFractionOfSecond, + 1e-14); + + fTime = -0.000001; + Time::GetClock(fTime, nHour, nMinute, nSecond, fFractionOfSecond, 4); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Hour value.", sal_uInt16(23), nHour); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Minute value.", sal_uInt16(59), nMinute); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Second value.", sal_uInt16(59), nSecond); + // Expect this to be rounded. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Fraction value.", 0.9136, fFractionOfSecond, 0.0); + + fTime = -0.00000000001; + Time::GetClock(fTime, nHour, nMinute, nSecond, fFractionOfSecond, 4); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Hour value.", sal_uInt16(23), nHour); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Minute value.", sal_uInt16(59), nMinute); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Second value.", sal_uInt16(59), nSecond); + // Expect this to be a truncated 0.999999 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Fraction value.", 0.9999, fFractionOfSecond, 0.0); fTime = -1e-24; // value insignificant for time Time::GetClock(fTime, nHour, nMinute, nSecond, fFractionOfSecond, 0); diff --git a/tools/source/datetime/ttime.cxx b/tools/source/datetime/ttime.cxx index f1dea02a6afb..7f058cf2ac6d 100644 --- a/tools/source/datetime/ttime.cxx +++ b/tools/source/datetime/ttime.cxx @@ -313,10 +313,18 @@ void tools::Time::GetClock( double fTimeInDays, nSecond = fSeconds; fSeconds -= nSecond; - // Do not round the fraction, otherwise .999 would end up as .00 again. + assert(fSeconds < 1.0); // or back to the drawing board.. + if (nFractionDecimals > 0) - fFractionOfSecond = rtl::math::pow10Exp( std::trunc( - rtl::math::pow10Exp( fSeconds, nFractionDecimals)), -nFractionDecimals); + { + // Do not simply round the fraction, otherwise .999 would end up as .00 + // again. Truncate instead if rounding would round up into an integer + // value. + fFractionOfSecond = rtl::math::round( fSeconds, nFractionDecimals); + if (fFractionOfSecond >= 1.0) + fFractionOfSecond = rtl::math::pow10Exp( std::trunc( + rtl::math::pow10Exp( fSeconds, nFractionDecimals)), -nFractionDecimals); + } else fFractionOfSecond = fSeconds; } -- cgit