sc/inc/subtotal.hxx | 23 ++++++++++++++++++++++- sc/source/core/data/column2.cxx | 14 ++++++++++++-- sc/source/core/data/documen4.cxx | 39 ++++++++++++++++++++++++++++++++++++--- sc/source/core/tool/subtotal.cxx | 8 ++++++++ 4 files changed, 78 insertions(+), 6 deletions(-)
New commits: commit fc1568d570a96bfa57013ae62adf3f9606639fd3 Author: Eike Rathke <er...@redhat.com> AuthorDate: Tue Dec 11 12:43:14 2018 +0100 Commit: Eike Rathke <er...@redhat.com> CommitDate: Tue Dec 11 17:54:36 2018 +0100 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/64957 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins diff --git a/sc/inc/subtotal.hxx b/sc/inc/subtotal.hxx index 7858fcae6f2b..46f6fcc7693c 100644 --- a/sc/inc/subtotal.hxx +++ b/sc/inc/subtotal.hxx @@ -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 ) : diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index c46f1a70ce8b..5f77628699f6 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -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; } } diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx index 9e4cc23cb85d..94b361cde765 100644 --- a/sc/source/core/data/documen4.cxx +++ b/sc/source/core/data/documen4.cxx @@ -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) diff --git a/sc/source/core/tool/subtotal.cxx b/sc/source/core/tool/subtotal.cxx index f57d0ae1d8d4..ec908b16eeec 100644 --- a/sc/source/core/tool/subtotal.cxx +++ b/sc/source/core/tool/subtotal.cxx @@ -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: */ _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits