tdf#137679 Use Kahan summation for scmatrix operations

May also want implement Kahan sum in there:
sc/source/core/tool/arraysumSSE2.cxx
sc/source/core/inc/arraysumfunctor.hxx
Under some conditions the sum of a pointer type vector
may be perforemed by arraysumfunctor on NumericCellAccumulator.
arraysumSSE2 implements part of it.
This code has been left unmodified.

Why the test has been modified:
The error was: 238.89000000000001 != 238.89
                                |
                                17 th digit
IEEE 754 double-precision has 53 log10(2) ≈ 15.955 digits.
So it's just noise.

Change-Id: I6f84826bf3875be4f444f5eb61854bc1f95769bb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114627
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Tested-by: Jenkins
diff --git a/sc/inc/columnspanset.hxx b/sc/inc/columnspanset.hxx
index 570f99c..d889a4d 100644
--- a/sc/inc/columnspanset.hxx
+++ b/sc/inc/columnspanset.hxx
@@ -80,7 +80,6 @@ public:
        virtual ~ColumnAction() = 0;
        virtual void startColumn(ScColumn* pCol) = 0;
        virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) = 0;
        virtual void executeSum(SCROW, SCROW, bool, double& )  { return; } ;
    };

    ColumnSpanSet();
@@ -162,7 +161,6 @@ public:
    RangeColumnSpanSet( const ScRange& spanRange )
         : range( spanRange ) {}
    void executeColumnAction(ScDocument& rDoc, sc::ColumnSpanSet::ColumnAction& ac) const;
    void executeColumnAction(ScDocument& rDoc, sc::ColumnSpanSet::ColumnAction& ac, double& fMem) const;
private:
    ScRange range;
};
diff --git a/sc/inc/matrixoperators.hxx b/sc/inc/matrixoperators.hxx
index 540a38e..36fa1ca 100644
--- a/sc/inc/matrixoperators.hxx
+++ b/sc/inc/matrixoperators.hxx
@@ -11,6 +11,7 @@


#include <functional>
#include "math.hxx"

namespace sc::op {

@@ -35,19 +36,19 @@ using Op = Op_<std::function<void(double&, double)>>;
struct Sum
{
    static const double InitVal;
    void operator()(double& rAccum, double fVal) const;
    void operator()(KahanSum& rAccum, double fVal) const;
};

struct SumSquare
{
    static const double InitVal;
    void operator()(double& rAccum, double fVal) const;
    void operator()(KahanSum& rAccum, double fVal) const;
};

struct Product
{
    static const double InitVal;
    void operator()(double& rAccum, double fVal) const;
    void operator()(KahanSum& rAccum, double fVal) const;
};

}
diff --git a/sc/inc/scmatrix.hxx b/sc/inc/scmatrix.hxx
index 60587b2..2a1d934 100644
--- a/sc/inc/scmatrix.hxx
+++ b/sc/inc/scmatrix.hxx
@@ -150,6 +150,21 @@ public:
            mfFirst(fFirst), mfRest(fRest), mnCount(nCount) {}
    };

    /**
      * Version of IterateResult for using Kahan sum.
      */
    struct KahanIterateResult
    {
        KahanSum maAccumulator;
        size_t mnCount;

        KahanIterateResult(double fAccumulator, size_t nCount)
            : maAccumulator(fAccumulator), mnCount(nCount) {}

        double get() { return maAccumulator.get(); }
    };


    /** Checks nC or nR for zero and uses GetElementsMax() whether a matrix of
        the size of nC*nR could be allocated. A zero size (both nC and nR zero)
        matrix is allowed for later resize.
@@ -361,9 +376,9 @@ public:
    double Or() const ;        // logical OR of all matrix values, or NAN
    double Xor() const ;       // logical XOR of all matrix values, or NAN

    IterateResult Sum( bool bTextAsZero, bool bIgnoreErrorValues = false ) const ;
    IterateResult SumSquare( bool bTextAsZero, bool bIgnoreErrorValues = false ) const ;
    IterateResult Product( bool bTextAsZero, bool bIgnoreErrorValues = false ) const ;
    KahanIterateResult Sum( bool bTextAsZero, bool bIgnoreErrorValues = false ) const ;
    KahanIterateResult SumSquare( bool bTextAsZero, bool bIgnoreErrorValues = false ) const ;
    KahanIterateResult Product( bool bTextAsZero, bool bIgnoreErrorValues = false ) const ;
    size_t Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings = false) const ;
    size_t MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const ;
    size_t MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const ;
diff --git a/sc/qa/uitest/calc_tests6/tdf118638.py b/sc/qa/uitest/calc_tests6/tdf118638.py
index 2e1b704..cc5c97f 100644
--- a/sc/qa/uitest/calc_tests6/tdf118638.py
+++ b/sc/qa/uitest/calc_tests6/tdf118638.py
@@ -47,8 +47,8 @@ class Subtotals(UITestCase):
        self.assertEqual(get_cell_by_position(document, 0, 0, 15).getString(), "5408 Sum")
        self.assertEqual(get_cell_by_position(document, 0, 0, 16).getString(), "Grand Sum")

        self.assertEqual(get_cell_by_position(document, 0, 1, 15).getValue(), 238.89)
        self.assertEqual(get_cell_by_position(document, 0, 1, 16).getValue(), 238.89)
        self.assertEqual(round(get_cell_by_position(document, 0, 1, 15).getValue(),12), 238.89)
        self.assertEqual(round(get_cell_by_position(document, 0, 1, 16).getValue(),12), 238.89)

        self.assertEqual(get_cell_by_position(document, 0, 1, 15).getString(), "$238.89")
        self.assertEqual(get_cell_by_position(document, 0, 1, 16).getString(), "$238.89")
diff --git a/sc/source/core/data/columnspanset.cxx b/sc/source/core/data/columnspanset.cxx
index fe9b551..b400cd6 100644
--- a/sc/source/core/data/columnspanset.cxx
+++ b/sc/source/core/data/columnspanset.cxx
@@ -359,27 +359,6 @@ void RangeColumnSpanSet::executeColumnAction(ScDocument& rDoc, sc::ColumnSpanSet
    }
}

void RangeColumnSpanSet::executeColumnAction(ScDocument& rDoc, sc::ColumnSpanSet::ColumnAction& ac, double& fMem) const
{
    for (SCTAB nTab = range.aStart.Tab(); nTab <= range.aEnd.Tab(); ++nTab)
    {
        ScTable* pTab = rDoc.FetchTable(nTab);
        if (!pTab)
            continue;

        SCCOL nEndCol = pTab->ClampToAllocatedColumns(range.aEnd.Col());
        for (SCCOL nCol = range.aStart.Col(); nCol <= nEndCol; ++nCol)
        {
            if (!rDoc.ValidCol(nCol))
                break;

            ScColumn& rColumn = pTab->aCol[nCol];
            ac.startColumn(&rColumn);
            ac.executeSum( range.aStart.Row(), range.aEnd.Row(), true, fMem );
        }
    }
}

} // namespace sc

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx
index 4cf5d9c..0fe64d6 100644
--- a/sc/source/core/tool/interpr5.cxx
+++ b/sc/source/core/tool/interpr5.cxx
@@ -1871,9 +1871,7 @@ void ScInterpreter::ScSumXMY2()
    }
    else
    {
        ScMatrix::IterateResult aRes = pResMat->SumSquare(false);
        double fSum = aRes.mfFirst + aRes.mfRest;
        PushDouble(fSum);
        PushDouble(pResMat->SumSquare(false).get());
    }
}

diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index f506b9f..a48d7d3 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -207,12 +207,11 @@ namespace {

class NumericCellAccumulator
{
    double mfFirst;
    double mfRest;
    KahanSum maSum;
    FormulaError mnError;

public:
    NumericCellAccumulator() : mfFirst(0.0), mfRest(0.0), mnError(FormulaError::NONE) {}
    NumericCellAccumulator() : maSum(0.0), mnError(FormulaError::NONE) {}

    void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize)
    {
@@ -220,28 +219,13 @@ public:
        {
            case sc::element_type_numeric:
            {
                const double *p = &sc::numeric_block::at(*rNode.data, nOffset);
                size_t i = 0;

                // Store the first non-zero value in mfFirst (for some reason).
                if (!mfFirst)
                {
                    for (i = 0; i < nDataSize; ++i)
                    {
                        if (!mfFirst)
                            mfFirst = p[i];
                        else
                            break;
                    }
                }
                p += i;
                nDataSize -= i;
                if (nDataSize == 0)
                    return;

                const double *p = &sc::numeric_block::at(*rNode.data, nOffset);
                sc::ArraySumFunctor functor(p, nDataSize);

                mfRest += functor();
                maSum += functor();
                break;
            }

@@ -267,10 +251,7 @@ public:
                        return;
                    }

                    if ( !mfFirst )
                        mfFirst = fVal;
                    else
                        mfRest += fVal;
                    maSum += fVal;
                }
            }
            break;
@@ -280,8 +261,7 @@ public:
    }

    FormulaError getError() const { return mnError; }
    double getFirst() const { return mfFirst; }
    double getRest() const { return mfRest; }
    KahanSum getResult() const { return maSum; }
};

class NumericCellCounter
@@ -356,7 +336,7 @@ class FuncSum : public sc::ColumnSpanSet::ColumnAction
    const ScInterpreterContext& mrContext;
    sc::ColumnBlockConstPosition maPos;
    ScColumn* mpCol;
    double mfSum;
    KahanSum mfSum;
    FormulaError mnError;
    sal_uInt32 mnNumFmt;

@@ -369,9 +349,7 @@ public:
        mpCol->InitBlockPosition(maPos);
    }

    virtual void execute(SCROW, SCROW, bool) override {}

    virtual void executeSum(SCROW nRow1, SCROW nRow2, bool bVal, double& fMem ) override
    virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) override
    {
        if (!bVal)
            return;
@@ -385,19 +363,13 @@ public:
        if (mnError != FormulaError::NONE)
            return;

        if ( fMem )
            mfSum += aFunc.getFirst() + aFunc.getRest();
        else
        {
            fMem = aFunc.getFirst();
            mfSum += aFunc.getRest();
        }

        mfSum += aFunc.getResult();
        mnNumFmt = mpCol->GetNumberFormat(mrContext, nRow2);
    };

    FormulaError getError() const { return mnError; }
    double getSum() const { return mfSum; }
    KahanSum getSum() const { return mfSum; }
    sal_uInt32 getNumberFormat() const { return mnNumFmt; }
};

@@ -405,7 +377,7 @@ public:

static void IterateMatrix(
    const ScMatrixRef& pMat, ScIterFunc eFunc, bool bTextAsZero, SubtotalFlags nSubTotalFlags,
    sal_uLong& rCount, SvNumFormatType& rFuncFmtType, double& fRes, double& fMem )
    sal_uLong& rCount, SvNumFormatType& rFuncFmtType, KahanSum& fRes )
{
    if (!pMat)
        return;
@@ -417,24 +389,8 @@ static void IterateMatrix(
        case ifAVERAGE:
        case ifSUM:
        {
            ScMatrix::IterateResult aRes = pMat->Sum(bTextAsZero, bIgnoreErrVal);
            // If the first value is a NaN, it probably means it was an empty cell,
            // and should be treated as zero.
            if ( !std::isfinite(aRes.mfFirst) )
            {
                sal_uInt32 nErr = reinterpret_cast< sal_math_Double * >(&aRes.mfFirst)->nan_parts.fraction_lo;
                if (nErr & 0xffff0000)
                {
                    aRes.mfFirst = 0;
                }
            }
            if ( fMem )
                fRes += aRes.mfFirst + aRes.mfRest;
            else
            {
                fMem = aRes.mfFirst;
                fRes += aRes.mfRest;
            }
            ScMatrix::KahanIterateResult aRes = pMat->Sum(bTextAsZero, bIgnoreErrVal);
            fRes += aRes.maAccumulator;
            rCount += aRes.mnCount;
        }
        break;
@@ -447,17 +403,15 @@ static void IterateMatrix(
        break;
        case ifPRODUCT:
        {
            ScMatrix::IterateResult aRes = pMat->Product(bTextAsZero, bIgnoreErrVal);
            fRes *= aRes.mfFirst;
            fRes *= aRes.mfRest;
            ScMatrix::KahanIterateResult aRes = pMat->Product(bTextAsZero, bIgnoreErrVal);
            fRes *= aRes.get();
            rCount += aRes.mnCount;
        }
        break;
        case ifSUMSQ:
        {
            ScMatrix::IterateResult aRes = pMat->SumSquare(bTextAsZero, bIgnoreErrVal);
            fRes += aRes.mfFirst;
            fRes += aRes.mfRest;
            ScMatrix::KahanIterateResult aRes = pMat->SumSquare(bTextAsZero, bIgnoreErrVal);
            fRes += aRes.maAccumulator;
            rCount += aRes.mnCount;
        }
        break;
@@ -484,15 +438,12 @@ size_t ScInterpreter::GetRefListArrayMaxSize( short nParamCount )
    return nSize;
}

static double lcl_IterResult( ScIterFunc eFunc, double fRes, double fMem, sal_uLong nCount )
static double lcl_IterResult( ScIterFunc eFunc, double fRes, sal_uLong nCount )
{
    switch( eFunc )
    {
        case ifSUM:
            fRes = ::rtl::math::approxAdd( fRes, fMem );
        break;
        case ifAVERAGE:
            fRes = sc::div( ::rtl::math::approxAdd( fRes, fMem ), nCount);
            fRes = sc::div( fRes, nCount);
        break;
        case ifCOUNT2:
        case ifCOUNT:
@@ -514,9 +465,8 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
    const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
    ScMatrixRef xResMat, xResCount;
    const double ResInitVal = (eFunc == ifPRODUCT) ? 1.0 : 0.0;
    double fRes = ResInitVal;
    KahanSum fRes = ResInitVal;
    double fVal = 0.0;
    double fMem = 0.0;  // first numeric value != 0.0
    sal_uLong nCount = 0;
    ScAddress aAdr;
    ScRange aRange;
@@ -584,12 +534,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                switch( eFunc )
                {
                    case ifAVERAGE:
                    case ifSUM:
                        if ( fMem )
                            fRes += fVal;
                        else
                            fMem = fVal;
                        break;
                    case ifSUM:     fRes += fVal; break;
                    case ifSUMSQ:   fRes += fVal * fVal; break;
                    case ifPRODUCT: fRes *= fVal; break;
                    default: ; // nothing
@@ -636,12 +581,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                    switch( eFunc )
                    {
                        case ifAVERAGE:
                        case ifSUM:
                            if ( fMem )
                                fRes += fVal;
                            else
                                fMem = fVal;
                            break;
                        case ifSUM:     fRes += fVal; break;
                        case ifSUMSQ:   fRes += fVal * fVal; break;
                        case ifPRODUCT: fRes *= fVal; break;
                        case ifCOUNT:
@@ -705,12 +645,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                        switch( eFunc )
                        {
                            case ifAVERAGE:
                            case ifSUM:
                                if ( fMem )
                                    fRes += fVal;
                                else
                                    fMem = fVal;
                                break;
                            case ifSUM:     fRes += fVal; break;
                            case ifSUMSQ:   fRes += fVal * fVal; break;
                            case ifPRODUCT: fRes *= fVal; break;
                            case ifCOUNT:
@@ -738,11 +673,6 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                if (p && p->IsArrayResult())
                {
                    nRefArrayPos = nRefInList;
                    if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0)
                    {
                        fRes = rtl::math::approxAdd( fRes, fMem);
                        fMem = 0.0;
                    }
                    // The "one value to all references of an array" seems to
                    // be what Excel does if there are other types than just
                    // arrays of references.
@@ -751,7 +681,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                        // Create and init all elements with current value.
                        assert(nMatRows > 0);
                        xResMat = GetNewMat( 1, nMatRows, true);
                        xResMat->FillDouble( fRes, 0,0, 0,nMatRows-1);
                        xResMat->FillDouble( fRes.get(), 0,0, 0,nMatRows-1);
                        if (eFunc != ifSUM)
                        {
                            xResCount = GetNewMat( 1, nMatRows, true);
@@ -775,9 +705,9 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                            {
                                double fVecRes = xResMat->GetDouble(0,i);
                                if (eFunc == ifPRODUCT)
                                    fVecRes *= fRes;
                                    fVecRes *= fRes.get();
                                else
                                    fVecRes += fRes;
                                    fVecRes += fRes.get();
                                xResMat->PutDouble( fVecRes, 0,i);
                            }
                        }
@@ -830,7 +760,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                    if ( eFunc == ifSUM )
                    {
                        FuncSum aAction(mrContext);
                        aSet.executeColumnAction( mrDoc, aAction, fMem );
                        aSet.executeColumnAction( mrDoc, aAction );
                        FormulaError nErr = aAction.getError();
                        if ( nErr != FormulaError::NONE )
                        {
@@ -874,10 +804,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                                            if ( nErr == FormulaError::NONE )
                                            {
                                                SetError(nErr);
                                                if ( fMem )
                                                    fRes += fVal;
                                                else
                                                    fMem = fVal;
                                                fRes += fVal;
                                                nCount++;
                                            }
                                        }
@@ -888,10 +815,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                                        do
                                        {
                                            SetError(nErr);
                                            if ( fMem )
                                                fRes += fVal;
                                            else
                                                fMem = fVal;
                                            fRes += fVal;
                                            nCount++;
                                        }
                                        while (aValIter.GetNext(fVal, nErr));
@@ -950,18 +874,13 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                if (nRefArrayPos != std::numeric_limits<size_t>::max())
                {
                    // Update vector element with current value.
                    if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0)
                    {
                        fRes = rtl::math::approxAdd( fRes, fMem);
                        fMem = 0.0;
                    }
                    if (xResCount)
                        xResCount->PutDouble( xResCount->GetDouble(0,nRefArrayPos) + nCount, 0,nRefArrayPos);
                    double fVecRes = xResMat->GetDouble(0,nRefArrayPos);
                    if (eFunc == ifPRODUCT)
                        fVecRes *= fRes;
                        fVecRes *= fRes.get();
                    else
                        fVecRes += fRes;
                        fVecRes += fRes.get();
                    xResMat->PutDouble( fVecRes, 0,nRefArrayPos);
                    // Reset.
                    fRes = ResInitVal;
@@ -977,14 +896,14 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                if ( nGlobalError != FormulaError::NONE && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
                    break;

                IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes, fMem );
                IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes );
            }
            break;
            case svMatrix :
            {
                ScMatrixRef pMat = PopMatrix();

                IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes, fMem );
                IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes );
            }
            break;
            case svError:
@@ -1021,17 +940,17 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
            sal_uLong nVecCount = (xResCount ? nCount + xResCount->GetDouble(0,i) : nCount);
            double fVecRes = xResMat->GetDouble(0,i);
            if (eFunc == ifPRODUCT)
                fVecRes *= fRes;
                fVecRes *= fRes.get();
            else
                fVecRes += fRes;
            fVecRes = lcl_IterResult( eFunc, fVecRes, fMem, nVecCount);
                fVecRes += fRes.get();
            fVecRes = lcl_IterResult( eFunc, fVecRes, nVecCount);
            xResMat->PutDouble( fVecRes, 0,i);
        }
        PushMatrix( xResMat);
    }
    else
    {
        PushDouble( lcl_IterResult( eFunc, fRes, fMem, nCount));
        PushDouble( lcl_IterResult( eFunc, fRes.get(), nCount));
    }
}

@@ -1065,6 +984,11 @@ void ScInterpreter::ScCount2()
    IterateParameters( ifCOUNT2 );
}

/**
 * The purpose of RAWSUBTRACT() is exactly to not apply any error correction, approximation etc.
 * But use the "raw" IEEE 754 double subtraction.
 * So no Kahan summation
 */
void ScInterpreter::ScRawSubtract()
{
    short nParamCount = GetByte();
diff --git a/sc/source/core/tool/matrixoperators.cxx b/sc/source/core/tool/matrixoperators.cxx
index 31cf6d9..e65d4d7c 100644
--- a/sc/source/core/tool/matrixoperators.cxx
+++ b/sc/source/core/tool/matrixoperators.cxx
@@ -9,30 +9,19 @@

#include <matrixoperators.hxx>


namespace sc::op {

void Sum::operator()(double& rAccum, double fVal) const
namespace sc::op
{
    rAccum += fVal;
}
void Sum::operator()(KahanSum& rAccum, double fVal) const { rAccum += fVal; }

const double Sum::InitVal = 0.0;

void SumSquare::operator()(double& rAccum, double fVal) const
{
    rAccum += fVal * fVal;
}
void SumSquare::operator()(KahanSum& rAccum, double fVal) const { rAccum += fVal * fVal; }

const double SumSquare::InitVal = 0.0;

void Product::operator()(double& rAccum, double fVal) const
{
    rAccum *= fVal;
}
void Product::operator()(KahanSum& rAccum, double fVal) const { rAccum *= fVal; }

const double Product::InitVal = 1.0;

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/scmatrix.cxx b/sc/source/core/tool/scmatrix.cxx
index ad7f4c7..a10863e 100644
--- a/sc/source/core/tool/scmatrix.cxx
+++ b/sc/source/core/tool/scmatrix.cxx
@@ -302,9 +302,9 @@ public:
    double Or() const;
    double Xor() const;

    ScMatrix::IterateResult Sum( bool bTextAsZero, bool bIgnoreErrorValues ) const;
    ScMatrix::IterateResult SumSquare( bool bTextAsZero, bool bIgnoreErrorValues ) const;
    ScMatrix::IterateResult Product( bool bTextAsZero, bool bIgnoreErrorValues ) const;
    ScMatrix::KahanIterateResult Sum( bool bTextAsZero, bool bIgnoreErrorValues ) const;
    ScMatrix::KahanIterateResult SumSquare( bool bTextAsZero, bool bIgnoreErrorValues ) const;
    ScMatrix::KahanIterateResult Product( bool bTextAsZero, bool bIgnoreErrorValues ) const;
    size_t Count(bool bCountStrings, bool bCountErrors, bool bIgnoreEmptyStrings) const;
    size_t MatchDoubleInColumns(double fValue, size_t nCol1, size_t nCol2) const;
    size_t MatchStringInColumns(const svl::SharedString& rStr, size_t nCol1, size_t nCol2) const;
@@ -1111,17 +1111,16 @@ template<typename Op>
class WalkElementBlocks
{
    Op maOp;
    ScMatrix::IterateResult maRes;
    bool mbFirst:1;
    ScMatrix::KahanIterateResult maRes;
    bool mbTextAsZero:1;
    bool mbIgnoreErrorValues:1;
public:
    WalkElementBlocks(bool bTextAsZero, bool bIgnoreErrorValues) :
        maRes(Op::InitVal, Op::InitVal, 0), mbFirst(true),
        maRes(Op::InitVal, 0),
        mbTextAsZero(bTextAsZero), mbIgnoreErrorValues(bIgnoreErrorValues)
    {}

    const ScMatrix::IterateResult& getResult() const { return maRes; }
    const ScMatrix::KahanIterateResult& getResult() const { return maRes; }

    void operator() (const MatrixImplType::element_block_node_type& node)
    {
@@ -1141,16 +1140,7 @@ public:
                        ++nIgnored;
                        continue;
                    }

                    if (mbFirst)
                    {
                        maOp(maRes.mfFirst, *it);
                        mbFirst = false;
                    }
                    else
                    {
                        maOp(maRes.mfRest, *it);
                    }
                    maOp(maRes.maAccumulator, *it);
                }
                maRes.mnCount += node.size - nIgnored;
            }
@@ -1163,15 +1153,7 @@ public:
                block_type::const_iterator itEnd = block_type::end(*node.data);
                for (; it != itEnd; ++it)
                {
                    if (mbFirst)
                    {
                        maOp(maRes.mfFirst, *it);
                        mbFirst = false;
                    }
                    else
                    {
                        maOp(maRes.mfRest, *it);
                    }
                    maOp(maRes.maAccumulator, *it);
                }
                maRes.mnCount += node.size;
            }
@@ -2099,7 +2081,7 @@ public:
namespace {

template<typename TOp>
ScMatrix::IterateResult GetValueWithCount(bool bTextAsZero, bool bIgnoreErrorValues, const MatrixImplType& maMat)
ScMatrix::KahanIterateResult GetValueWithCount(bool bTextAsZero, bool bIgnoreErrorValues, const MatrixImplType& maMat)
{
    WalkElementBlocks<TOp> aFunc(bTextAsZero, bIgnoreErrorValues);
    aFunc = maMat.walk(aFunc);
@@ -2108,17 +2090,17 @@ ScMatrix::IterateResult GetValueWithCount(bool bTextAsZero, bool bIgnoreErrorVal

}

ScMatrix::IterateResult ScMatrixImpl::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
ScMatrix::KahanIterateResult ScMatrixImpl::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
{
    return GetValueWithCount<sc::op::Sum>(bTextAsZero, bIgnoreErrorValues, maMat);
}

ScMatrix::IterateResult ScMatrixImpl::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
ScMatrix::KahanIterateResult ScMatrixImpl::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
{
    return GetValueWithCount<sc::op::SumSquare>(bTextAsZero, bIgnoreErrorValues, maMat);
}

ScMatrix::IterateResult ScMatrixImpl::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
ScMatrix::KahanIterateResult ScMatrixImpl::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
{
    return GetValueWithCount<sc::op::Product>(bTextAsZero, bIgnoreErrorValues, maMat);
}
@@ -3226,17 +3208,17 @@ double ScMatrix::Xor() const
    return pImpl->Xor();
}

ScMatrix::IterateResult ScMatrix::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
ScMatrix::KahanIterateResult ScMatrix::Sum(bool bTextAsZero, bool bIgnoreErrorValues) const
{
    return pImpl->Sum(bTextAsZero, bIgnoreErrorValues);
}

ScMatrix::IterateResult ScMatrix::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
ScMatrix::KahanIterateResult ScMatrix::SumSquare(bool bTextAsZero, bool bIgnoreErrorValues) const
{
    return pImpl->SumSquare(bTextAsZero, bIgnoreErrorValues);
}

ScMatrix::IterateResult ScMatrix::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
ScMatrix::KahanIterateResult ScMatrix::Product(bool bTextAsZero, bool bIgnoreErrorValues) const
{
    return pImpl->Product(bTextAsZero, bIgnoreErrorValues);
}
diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist
index 99d83dc..927c1ce 100644
--- a/solenv/clang-format/excludelist
+++ b/solenv/clang-format/excludelist
@@ -8311,7 +8311,6 @@ sc/source/core/tool/interpr8.cxx
sc/source/core/tool/jumpmatrix.cxx
sc/source/core/tool/listenerquery.cxx
sc/source/core/tool/lookupcache.cxx
sc/source/core/tool/matrixoperators.cxx
sc/source/core/tool/navicfg.cxx
sc/source/core/tool/numformat.cxx
sc/source/core/tool/odffmap.cxx