[Libreoffice-commits] core.git: 2 commits - sc/qa sc/source
Eike Rathke
erack at redhat.com
Mon May 22 14:58:25 UTC 2017
sc/qa/unit/ucalc_formula.cxx | 9 +++
sc/source/core/tool/interpr1.cxx | 114 +++++++++++++++++++++++++++++++++++----
2 files changed, 113 insertions(+), 10 deletions(-)
New commits:
commit a21f1c11aacde31fa190859828f257544afea818
Author: Eike Rathke <erack at redhat.com>
Date: Mon May 22 16:57:36 2017 +0200
Unit test for SUBTOTAL STDEV with array of references, tdf#58874
Change-Id: I27d8a0a3c03012a4575785feb32df11a76d6fcdb
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 69f3a47962c1..da0dc34cec2c 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -7955,6 +7955,15 @@ void Test::testFuncRefListArraySUBTOTAL()
aPos.IncRow();
CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MAX for A4:A5 failed", 16.0, m_pDoc->GetValue(aPos));
+ // Matrix in F7:F9, individual STDEV of A2:A3, A3:A4 and A4:A5
+ m_pDoc->InsertMatrixFormula(5, 6, 5, 8, aMark, "=SUBTOTAL(7;OFFSET(A1;ROW(1:3);0;2))");
+ aPos.Set(5,6,0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SUBTOTAL STDEV for A2:A3 failed", 1.414214, m_pDoc->GetValue(aPos), 1e-6);
+ aPos.IncRow();
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SUBTOTAL STDEV for A3:A4 failed", 2.828427, m_pDoc->GetValue(aPos), 1e-6);
+ aPos.IncRow();
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SUBTOTAL STDEV for A4:A5 failed", 5.656854, m_pDoc->GetValue(aPos), 1e-6);
+
m_pDoc->DeleteTab(0);
}
commit fda09a666dd22aa6b2a9abfb25f7c97a3ab910fe
Author: Eike Rathke <erack at redhat.com>
Date: Mon May 22 16:56:50 2017 +0200
Handle STDEV, STDEVP, VAR and VARP with arrays of references, tdf#58874
Change-Id: Ifdd5336124df9a085902417590d081646d05a588
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 )
More information about the Libreoffice-commits
mailing list