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 <erack@redhat.com>
Tested-by: Jenkins
diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index 77f17fe..10c27f8 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) &&