[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