summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2017-05-22 16:56:50 +0200
committerEike Rathke <erack@redhat.com>2017-05-22 16:56:57 +0200
commitfda09a666dd22aa6b2a9abfb25f7c97a3ab910fe (patch)
tree9ce94aecc058c4b14717c62b6417161e79f0ec43
parent3e9f9bff4a3d8365f58545dae0c004a1254a56e3 (diff)
Handle STDEV, STDEVP, VAR and VARP with arrays of references, tdf#58874
Change-Id: Ifdd5336124df9a085902417590d081646d05a588
-rw-r--r--sc/source/core/tool/interpr1.cxx114
1 files changed, 104 insertions, 10 deletions
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 23f599e45a2d..f80f49557d82 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -3785,10 +3785,19 @@ void ScInterpreter::ScMax( bool bTextAsZero )
void ScInterpreter::GetStVarParams( bool bTextAsZero, double(*VarResult)( double fVal, size_t nValCount ) )
{
short nParamCount = GetByte();
+ const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
+
+ struct ArrayRefListValue
+ {
+ std::vector<double> mvValues;
+ double mfSum;
+ ArrayRefListValue() : mfSum(0.0) {}
+ };
+ std::vector<ArrayRefListValue> vArrayValues;
+ size_t nRefArrayPos = std::numeric_limits<size_t>::max();
std::vector<double> values;
double fSum = 0.0;
- double vSum = 0.0;
double fVal = 0.0;
ScAddress aAdr;
ScRange aRange;
@@ -3826,9 +3835,60 @@ void ScInterpreter::GetStVarParams( bool bTextAsZero, double(*VarResult)( double
}
}
break;
- case svDoubleRef :
case svRefList :
{
+ const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
+ if (p && p->IsArrayResult())
+ {
+ nRefArrayPos = nRefInList;
+ if (vArrayValues.empty())
+ {
+ // Create and init all elements with current value.
+ assert(nMatRows > 0);
+ vArrayValues.resize(nMatRows);
+ for (auto & it : vArrayValues)
+ {
+ it.mvValues = values;
+ it.mfSum = fSum;
+ }
+ }
+ else
+ {
+ // Current value and values from vector are operands
+ // for each vector position.
+ for (auto & it : vArrayValues)
+ {
+ it.mvValues.insert( it.mvValues.end(), values.begin(), values.end());
+ it.mfSum += fSum;
+ }
+ }
+ ArrayRefListValue& rArrayValue = vArrayValues[nRefArrayPos];
+ FormulaError nErr = FormulaError::NONE;
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags, bTextAsZero );
+ if (aValIter.GetFirst(fVal, nErr))
+ {
+ do
+ {
+ rArrayValue.mvValues.push_back(fVal);
+ rArrayValue.mfSum += fVal;
+ }
+ while ((nErr == FormulaError::NONE) && aValIter.GetNext(fVal, nErr));
+ }
+ if ( nErr != FormulaError::NONE )
+ {
+ rArrayValue.mfSum = CreateDoubleError( nErr);
+ }
+ // Reset.
+ std::vector<double>().swap(values);
+ fSum = 0.0;
+ nRefArrayPos = std::numeric_limits<size_t>::max();
+ break;
+ }
+ }
+ SAL_FALLTHROUGH;
+ case svDoubleRef :
+ {
FormulaError nErr = FormulaError::NONE;
PopDoubleRef( aRange, nParamCount, nRefInList);
ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags, bTextAsZero );
@@ -3893,16 +3953,50 @@ void ScInterpreter::GetStVarParams( bool bTextAsZero, double(*VarResult)( double
}
}
- ::std::vector<double>::size_type n = values.size();
- if (!n)
- SetError( FormulaError::DivisionByZero);
- if (nGlobalError == FormulaError::NONE)
+ if (!vArrayValues.empty())
{
- const double vMean = fSum / n;
- for (::std::vector<double>::size_type i = 0; i < n; i++)
- vSum += ::rtl::math::approxSub( values[i], vMean) * ::rtl::math::approxSub( values[i], vMean);
+ // Include value of last non-references-array type and calculate final result.
+ if (!values.empty())
+ {
+ for (auto & it : vArrayValues)
+ {
+ it.mvValues.insert( it.mvValues.end(), values.begin(), values.end());
+ it.mfSum += fSum;
+ }
+ }
+ ScMatrixRef xResMat = GetNewMat( 1, nMatRows, true);
+ for (SCSIZE r=0; r < nMatRows; ++r)
+ {
+ ::std::vector<double>::size_type n = vArrayValues[r].mvValues.size();
+ if (!n)
+ xResMat->PutError( FormulaError::DivisionByZero, 0, r);
+ else
+ {
+ ArrayRefListValue& rArrayValue = vArrayValues[r];
+ double vSum = 0.0;
+ const double vMean = rArrayValue.mfSum / n;
+ for (::std::vector<double>::size_type i = 0; i < n; i++)
+ vSum += ::rtl::math::approxSub( rArrayValue.mvValues[i], vMean) *
+ ::rtl::math::approxSub( rArrayValue.mvValues[i], vMean);
+ xResMat->PutDouble( VarResult( vSum, n), 0, r);
+ }
+ }
+ PushMatrix( xResMat);
+ }
+ else
+ {
+ ::std::vector<double>::size_type n = values.size();
+ if (!n)
+ SetError( FormulaError::DivisionByZero);
+ double vSum = 0.0;
+ if (nGlobalError == FormulaError::NONE)
+ {
+ const double vMean = fSum / n;
+ for (::std::vector<double>::size_type i = 0; i < n; i++)
+ vSum += ::rtl::math::approxSub( values[i], vMean) * ::rtl::math::approxSub( values[i], vMean);
+ }
+ PushDouble( VarResult( vSum, n));
}
- PushDouble( VarResult( vSum, n));
}
void ScInterpreter::ScVar( bool bTextAsZero )