sc/inc/dpglobal.hxx | 2 +- 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 ++++++++ 5 files changed, 79 insertions(+), 7 deletions(-)
New commits: commit 80fdc2491df857c910afbd30c025b4594cb1cf83 Author: Eike Rathke <[email protected]> AuthorDate: Tue Dec 11 17:35:00 2018 +0100 Commit: Eike Rathke <[email protected]> CommitDate: Tue Dec 11 22:24:16 2018 +0100 Correct typed_flags<PivotFunc> mask is 0x1fff This was wrong since commit 298ee50676b849020a8a5042e8612f71379ecf3b CommitDate: Sun Nov 20 00:14:28 2016 +0100 PivotMedian: Implement median as a new pivot table function and in fact in a debug build failed an assertion soffice.bin: include/o3tl/typed_flags_set.hxx:85: constexpr o3tl::is_typed_flags<E, M>::Wrap::Wrap(type name std::underlying_type<_Tp>::type) [with E = PivotFunc; typename std::underlying_type<_Tp>::type M = 4607; typename std::underlying_type<_Tp>::type = int]: Assertion `static_cast<typename std::underlying_type<E>::type>(~0) == M || (value & ~M) == 0' failed. when one of the functions (e.g. StdVar) not included in the mask was chosen as pivot table data function. Change-Id: I5b9efc7d2cbcf6fece3ef228db8f6e0ffa17b510 Reviewed-on: https://gerrit.libreoffice.org/64974 Reviewed-by: Eike Rathke <[email protected]> Tested-by: Jenkins (cherry picked from commit 639a401fbd910c1fede35f7106a5acf716ec5fea) Reviewed-on: https://gerrit.libreoffice.org/64984 diff --git a/sc/inc/dpglobal.hxx b/sc/inc/dpglobal.hxx index 295af86db148..0a5b6e94dc6b 100644 --- a/sc/inc/dpglobal.hxx +++ b/sc/inc/dpglobal.hxx @@ -39,7 +39,7 @@ enum class PivotFunc { Auto = 0x1000 }; namespace o3tl { - template<> struct typed_flags<PivotFunc> : is_typed_flags<PivotFunc, 0x11ff> {}; + template<> struct typed_flags<PivotFunc> : is_typed_flags<PivotFunc, 0x1fff> {}; } struct ScDPValue commit 1cb79dd63e0f825cee46fa58a6a9df39e8160f60 Author: Eike Rathke <[email protected]> AuthorDate: Tue Dec 11 12:43:14 2018 +0100 Commit: Eike Rathke <[email protected]> CommitDate: Tue Dec 11 22:24:03 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 <[email protected]> Tested-by: Jenkins (cherry picked from commit fc1568d570a96bfa57013ae62adf3f9606639fd3) Reviewed-on: https://gerrit.libreoffice.org/64975 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 [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
