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: ...@@ -30,11 +30,32 @@ public:
static bool SafeDiv( double& fVal1, double fVal2); 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 struct ScFunctionData // to calculate single functions
{ {
WelfordRunner maWelford;
ScSubTotalFunc const eFunc; ScSubTotalFunc const eFunc;
double nVal; double nVal;
long nCount; sal_uInt64 nCount;
bool bError; bool bError;
ScFunctionData( ScSubTotalFunc eFn ) : ScFunctionData( ScSubTotalFunc eFn ) :
......
...@@ -3423,10 +3423,20 @@ class UpdateSubTotalHandler ...@@ -3423,10 +3423,20 @@ class UpdateSubTotalHandler
mrData.nVal = fVal; mrData.nVal = fVal;
} }
break; 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, ...@@ -642,10 +642,43 @@ bool ScDocument::GetSelectionFunction( ScSubTotalFunc eFunc,
else else
aData.bError = true; aData.bError = true;
break; break;
default: 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
{ {
// added to avoid warnings rResult = aData.maWelford.getVariancePopulation();
if (eFunc == SUBTOTAL_FUNC_STDP)
{
if (rResult < 0.0)
aData.bError = true;
else
rResult = sqrt( rResult);
}
} }
break;
default:
// unhandled unknown
aData.bError = true;
} }
if (aData.bError) if (aData.bError)
......
...@@ -62,4 +62,12 @@ bool SubTotal::SafeDiv(double& fVal1, double fVal2) ...@@ -62,4 +62,12 @@ bool SubTotal::SafeDiv(double& fVal1, double fVal2)
return bOk; 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: */ /* 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