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()