diff options
author | Eike Rathke <erack@redhat.com> | 2017-05-22 16:56:50 +0200 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2017-05-22 16:56:57 +0200 |
commit | fda09a666dd22aa6b2a9abfb25f7c97a3ab910fe (patch) | |
tree | 9ce94aecc058c4b14717c62b6417161e79f0ec43 | |
parent | 3e9f9bff4a3d8365f58545dae0c004a1254a56e3 (diff) |
Handle STDEV, STDEVP, VAR and VARP with arrays of references, tdf#58874
Change-Id: Ifdd5336124df9a085902417590d081646d05a588
-rw-r--r-- | sc/source/core/tool/interpr1.cxx | 114 |
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 ) |