sc/source/core/data/table4.cxx |   35 ++++++++++++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 5 deletions(-)

New commits:
commit abd42a63f65f810c821085149c095682247e0d0d
Author:     Eike Rathke <er...@redhat.com>
AuthorDate: Tue Oct 11 12:33:22 2022 +0200
Commit:     Eike Rathke <er...@redhat.com>
CommitDate: Tue Oct 11 14:13:58 2022 +0200

    Resolves: tdf#151460 Scale and round time diff fiddling with floating point
    
    Change-Id: I5cf4e16692d55f30cc06723a323b4cd0408aaab7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141216
    Reviewed-by: Eike Rathke <er...@redhat.com>
    Tested-by: Jenkins

diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index 77f17feaa8f3..10c27f8d2c84 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -214,6 +214,28 @@ double approxDiff( double a, double b )
     const int nExpArg = static_cast<int>(floor(log10(std::max(aa, ab)))) - 15;
     return rtl::math::round(c, -std::max(nExp, nExpArg));
 }
+
+double approxTimeDiff( double a, double b )
+{
+    // Scale to hours, round to "nanohours" (multiple nanoseconds), scale back.
+    // Get back 0.0416666666666667 instead of 0.041666666700621136 or
+    // 0.041666666664241347 (raw a-b) for one hour, or worse the approxDiff()
+    // 0.041666666659999997 value. Though there is no such correct value,
+    // IEEE-754 nearest values are
+    // 0.041666666666666664353702032030923874117434024810791015625
+    // (0x3FA5555555555555) and
+    // 0.04166666666666667129259593593815225176513195037841796875
+    // (0x3FA5555555555556).
+    // This works also for a diff of seconds, unless corner cases would be
+    // discovered, which would make it necessary to ditch the floating point
+    // and convert to/from time structure values instead.
+    return rtl::math::round((a - b) * 24, 9) / 24;
+}
+
+double approxTypedDiff( double a, double b, bool bTime )
+{
+    return bTime ? approxTimeDiff( a, b) : approxDiff( a, b);
+}
 }
 
 void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
@@ -399,7 +421,9 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL 
nCol2, SCROW nRow2,
                         aCurrCell = GetCellValue(nColCurr, nRowCurr);
                         if (aCurrCell.getType() == CELLTYPE_VALUE)
                         {
-                            double nDiff = approxDiff(aCurrCell.getDouble(), 
aPrevCell.getDouble());
+                            double nDiff = 
approxTypedDiff(aCurrCell.getDouble(), aPrevCell.getDouble(),
+                                    (nCurrCellFormatType == 
SvNumFormatType::TIME ||
+                                     nCurrCellFormatType == 
SvNumFormatType::DATETIME));
                             if (i == 1)
                                 rInc = nDiff;
                             if (!::rtl::math::approxEqual(nDiff, rInc, 13))
@@ -516,8 +540,9 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL 
nCol2, SCROW nRow2,
         double fVal;
         sal_uInt32 nFormat = GetAttr(nCol,nRow,ATTR_VALUE_FORMAT)->GetValue();
         const SvNumFormatType nFormatType = 
rDocument.GetFormatTable()->GetType(nFormat);
-        bool bDate = (nFormatType  == SvNumFormatType::DATE );
-        bool bBooleanCell = (!bDate && nFormatType == 
SvNumFormatType::LOGICAL);
+        bool bDate = (nFormatType == SvNumFormatType::DATE);        // date 
without time
+        bool bTime = (nFormatType == SvNumFormatType::TIME || nFormatType == 
SvNumFormatType::DATETIME);
+        bool bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL);
         if (bDate)
         {
             if (nCount > 1)
@@ -622,7 +647,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL 
nCol2, SCROW nRow2,
             {
                 double nVal1 = aFirstCell.getDouble();
                 double nVal2 = GetValue(nCol+nAddX, nRow+nAddY);
-                rInc = approxDiff( nVal2, nVal1);
+                rInc = approxTypedDiff( nVal2, nVal1, bTime);
                 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
                 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
                 bool bVal = true;
@@ -632,7 +657,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL 
nCol2, SCROW nRow2,
                     if (aCell.getType() == CELLTYPE_VALUE)
                     {
                         nVal2 = aCell.getDouble();
-                        double nDiff = approxDiff( nVal2, nVal1);
+                        double nDiff = approxTypedDiff( nVal2, nVal1, bTime);
                         if ( !::rtl::math::approxEqual( nDiff, rInc, 13 ) )
                             bVal = false;
                         else if ((nVal2 == 0.0 || nVal2 == 1.0) &&

Reply via email to