tdf#137679 Use kahan summation for ScInterpreter::CalculatePearsonCovar
Change-Id: Ia268415c0fa5c26476cdf328e2f8863e97600167
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114951
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx
index d41f4f9..193a9ca 100644
--- a/sc/source/core/tool/interpr3.cxx
+++ b/sc/source/core/tool/interpr3.cxx
@@ -4557,8 +4557,8 @@ void ScInterpreter::CalculatePearsonCovar( bool _bPearson, bool _bStexy, bool _b
* for example above 10^8
*/
double fCount = 0.0;
double fSumX = 0.0;
double fSumY = 0.0;
KahanSum fSumX = 0.0;
KahanSum fSumY = 0.0;
for (SCSIZE i = 0; i < nC1; i++)
{
@@ -4566,10 +4566,8 @@ void ScInterpreter::CalculatePearsonCovar( bool _bPearson, bool _bStexy, bool _b
{
if (!pMat1->IsStringOrEmpty(i,j) && !pMat2->IsStringOrEmpty(i,j))
{
double fValX = pMat1->GetDouble(i,j);
double fValY = pMat2->GetDouble(i,j);
fSumX += fValX;
fSumY += fValY;
fSumX += pMat1->GetDouble(i,j);
fSumY += pMat2->GetDouble(i,j);
fCount++;
}
}
@@ -4578,11 +4576,11 @@ void ScInterpreter::CalculatePearsonCovar( bool _bPearson, bool _bStexy, bool _b
PushNoValue();
else
{
double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
double fSumSqrDeltaX = 0.0; // sum of (ValX-MeanX)^2
double fSumSqrDeltaY = 0.0; // sum of (ValY-MeanY)^2
const double fMeanX = fSumX / fCount;
const double fMeanY = fSumY / fCount;
KahanSum fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
KahanSum fSumSqrDeltaX = 0.0; // sum of (ValX-MeanX)^2
KahanSum fSumSqrDeltaY = 0.0; // sum of (ValY-MeanY)^2
const double fMeanX = fSumX.get() / fCount;
const double fMeanY = fSumY.get() / fCount;
for (SCSIZE i = 0; i < nC1; i++)
{
for (SCSIZE j = 0; j < nR1; j++)
@@ -4607,17 +4605,17 @@ void ScInterpreter::CalculatePearsonCovar( bool _bPearson, bool _bStexy, bool _b
|| (!_bStexy && fSumSqrDeltaY < ::std::numeric_limits<double>::min()))
PushError( FormulaError::DivisionByZero);
else if ( _bStexy )
PushDouble( sqrt( (fSumSqrDeltaY - fSumDeltaXDeltaY *
fSumDeltaXDeltaY / fSumSqrDeltaX) / (fCount-2)));
PushDouble( sqrt( ( fSumSqrDeltaY - fSumDeltaXDeltaY.get() *
fSumDeltaXDeltaY.get() / fSumSqrDeltaX.get() ).get() / (fCount-2)));
else
PushDouble( fSumDeltaXDeltaY / sqrt( fSumSqrDeltaX * fSumSqrDeltaY));
PushDouble( fSumDeltaXDeltaY.get() / sqrt( fSumSqrDeltaX.get() * fSumSqrDeltaY.get() ));
}
else
{
if ( _bSample )
PushDouble( fSumDeltaXDeltaY / ( fCount - 1 ) );
PushDouble( fSumDeltaXDeltaY.get() / ( fCount - 1 ) );
else
PushDouble( fSumDeltaXDeltaY / fCount);
PushDouble( fSumDeltaXDeltaY.get() / fCount);
}
}
}