Kaydet (Commit) fc1568d5 authored tarafından Eike Rathke's avatar Eike Rathke

Resolves: tdf#46119 implement GeneralFunction_VAR, VARP, STDEV and STDEVP

These were never implemented. Likely because they aren't used
internally by Calc, which for formula expressions in the
interpreter and for DataPilot / pivot table uses a different
approach, but they are needed for
css::sheet::XSheetOperation::computeFunction()

Change-Id: I1af038bf9db8d0c04d69598b992b827b083e2248
Reviewed-on: https://gerrit.libreoffice.org/64957Reviewed-by: 's avatarEike Rathke <erack@redhat.com>
Tested-by: Jenkins
üst aca3a4c3
......@@ -30,11 +30,32 @@ public:
static bool SafeDiv( double& fVal1, double fVal2);
};
/** Implements the Welford Online one-pass algorithm.
See https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_Online_algorithm
and Donald E. Knuth, TAoCP vol.2, 3rd edn., p. 232
*/
class WelfordRunner
{
public:
WelfordRunner() : fMean(0.0), fM2(0.0), nCount(0) {}
void update( double fVal );
sal_uInt64 getCount() const { return nCount; }
double getMean() const { return fMean; }
double getVarianceSample() const { return nCount > 1 ? fM2 / (nCount-1) : 0.0; }
double getVariancePopulation() const { return nCount > 0 ? fM2 / nCount : 0.0; }
private:
double fMean;
double fM2;
sal_Int64 nCount;
};
struct ScFunctionData // to calculate single functions
{
WelfordRunner maWelford;
ScSubTotalFunc const eFunc;
double nVal;
long nCount;
sal_uInt64 nCount;
bool bError;
ScFunctionData( ScSubTotalFunc eFn ) :
......
......@@ -3423,10 +3423,20 @@ class UpdateSubTotalHandler
mrData.nVal = fVal;
}
break;
default:
case SUBTOTAL_FUNC_VAR:
case SUBTOTAL_FUNC_VARP:
case SUBTOTAL_FUNC_STD:
case SUBTOTAL_FUNC_STDP:
{
// added to avoid warnings
if (!bVal)
return;
mrData.maWelford.update( fVal);
}
break;
default:
// unhandled unknown
mrData.bError = true;
}
}
......
......@@ -642,10 +642,43 @@ bool ScDocument::GetSelectionFunction( ScSubTotalFunc eFunc,
else
aData.bError = true;
break;
case SUBTOTAL_FUNC_VAR:
case SUBTOTAL_FUNC_STD:
if (aData.maWelford.getCount() < 2)
aData.bError = true;
else
{
rResult = aData.maWelford.getVarianceSample();
if (eFunc == SUBTOTAL_FUNC_STD)
{
if (rResult < 0.0)
aData.bError = true;
else
rResult = sqrt( rResult);
}
}
break;
case SUBTOTAL_FUNC_VARP:
case SUBTOTAL_FUNC_STDP:
if (aData.maWelford.getCount() < 1)
aData.bError = true;
else if (aData.maWelford.getCount() == 1)
rResult = 0.0;
else
{
rResult = aData.maWelford.getVariancePopulation();
if (eFunc == SUBTOTAL_FUNC_STDP)
{
if (rResult < 0.0)
aData.bError = true;
else
rResult = sqrt( rResult);
}
}
break;
default:
{
// added to avoid warnings
}
// unhandled unknown
aData.bError = true;
}
if (aData.bError)
......
......@@ -62,4 +62,12 @@ bool SubTotal::SafeDiv(double& fVal1, double fVal2)
return bOk;
}
void WelfordRunner::update( double fVal )
{
++nCount;
const double fDelta = fVal - fMean;
fMean += fDelta / nCount;
fM2 += fDelta * (fVal - fMean);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment