tdf#137679 Use kahan summation for ScInterpreter::SumProduct

Change-Id: Id0ef5b30a01054337f0ad3afd8c71311e6b2b469
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114888
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
diff --git a/sc/qa/uitest/statistics/anova.py b/sc/qa/uitest/statistics/anova.py
index 50237ef..579b9d2 100644
--- a/sc/qa/uitest/statistics/anova.py
+++ b/sc/qa/uitest/statistics/anova.py
@@ -98,7 +98,7 @@ class anova(UITestCase):
        self.assertEqual(get_cell_by_position(document, 0, 6, 5).getValue(), 10)
        self.assertEqual(get_cell_by_position(document, 0, 6, 6).getValue(), 10)
        self.assertEqual(get_cell_by_position(document, 0, 6, 8).getString(), "SS")
        self.assertEqual(round(get_cell_by_position(document, 0, 6, 9).getValue(),11), 1876.56832844573)
        self.assertEqual(round(get_cell_by_position(document, 0, 6, 9).getValue(),11), 1876.56832844575)
        self.assertEqual(round(get_cell_by_position(document, 0, 6, 10).getValue(),10), 6025.1090909091)
        #bug 80583
        self.assertEqual(round(get_cell_by_position(document, 0, 6, 11).getValue(),11), 7901.67741935484)
@@ -128,7 +128,7 @@ class anova(UITestCase):
        self.assertEqual(round(get_cell_by_position(document, 0, 9, 9).getValue(),13), 4.3604117704492)

        self.assertEqual(get_cell_by_position(document, 0, 10, 8).getString(), "P-value")
        self.assertEqual(round(get_cell_by_position(document, 0, 10, 9).getValue(),14), 0.02246149518799)
        self.assertEqual(round(get_cell_by_position(document, 0, 10, 9).getValue(),14), 0.02246149518798)

        self.assertEqual(get_cell_by_position(document, 0, 11, 8).getString(), "F critical")
        self.assertEqual(round(get_cell_by_position(document, 0, 11, 9).getValue(),13), 3.3403855582378)
diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx
index 0fe64d6..4f10bb89 100644
--- a/sc/source/core/tool/interpr5.cxx
+++ b/sc/source/core/tool/interpr5.cxx
@@ -1715,37 +1715,6 @@ void ScInterpreter::ScPow()
    }
}

namespace {

class SumValues
{
    double mfSum;
    bool   mbError;
public:
    SumValues() : mfSum(0.0), mbError(false) {}

    void operator() (double f)
    {
        if (mbError)
            return;

        FormulaError nErr = GetDoubleErrorValue(f);
        if (nErr == FormulaError::NONE)
            mfSum += f;
        else if (nErr != FormulaError::ElementNaN)
        {
            // Propagate the first error encountered, ignore "this is not a
            // number" elements.
            mfSum = f;
            mbError = true;
        }
    }

    double getValue() const { return mfSum; }
};

}

void ScInterpreter::ScSumProduct()
{
    short nParamCount = GetByte();
@@ -1790,8 +1759,21 @@ void ScInterpreter::ScSumProduct()
        pMat->MergeDoubleArrayMultiply(aResArray);
    }

    double fSum = std::for_each(aResArray.begin(), aResArray.end(), SumValues()).getValue();
    PushDouble(fSum);
    KahanSum fSum = 0.0;
    for( double fPosArray : aResArray )
    {
        FormulaError nErr = GetDoubleErrorValue(fPosArray);
        if (nErr == FormulaError::NONE)
            fSum += fPosArray;
        else if (nErr != FormulaError::ElementNaN)
        {
            // Propagate the first error encountered, ignore "this is not a number" elements.
            PushDouble(fPosArray);
            return;
        }
    }

    PushDouble(fSum.get());
}

void ScInterpreter::ScSumX2MY2()