diff options
author | Takeshi Abe <tabe@fixedpoint.jp> | 2018-11-27 11:28:18 +0900 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2018-11-30 22:14:17 +0100 |
commit | e4c2d0bb57ab8ea8f5c400d103d01376b8140f22 (patch) | |
tree | e9544de25cafd3a4be25bcb8123fe32efc0a7dd7 | |
parent | 776f7e7463de3e97f3056712ee567f49a314829d (diff) |
i#32345 Support a matrix of rank argument for LARGE()/SMALL()
This is a followup of e22ab5e6f6b0ea49231ca454a567133996306116.
Change-Id: I7052e113173204f7cfcd40622f52c5d4e14b3aa9
Reviewed-on: https://gerrit.libreoffice.org/64139
Tested-by: Jenkins
Reviewed-by: Eike Rathke <erack@redhat.com>
-rw-r--r-- | sc/qa/unit/data/functions/statistical/fods/large.fods | 16 | ||||
-rw-r--r-- | sc/qa/unit/data/functions/statistical/fods/small.fods | 17 | ||||
-rw-r--r-- | sc/source/core/inc/interpre.hxx | 5 | ||||
-rw-r--r-- | sc/source/core/tool/interpr3.cxx | 93 | ||||
-rw-r--r-- | sc/source/core/tool/interpr5.cxx | 33 |
5 files changed, 141 insertions, 23 deletions
diff --git a/sc/qa/unit/data/functions/statistical/fods/large.fods b/sc/qa/unit/data/functions/statistical/fods/large.fods index 6e701e71671f..d72e3bde9a20 100644 --- a/sc/qa/unit/data/functions/statistical/fods/large.fods +++ b/sc/qa/unit/data/functions/statistical/fods/large.fods @@ -4794,10 +4794,18 @@ <table:table-cell table:number-columns-repeated="2"/> </table:table-row> <table:table-row table:style-name="ro8"> - <table:table-cell table:style-name="ce10"/> - <table:table-cell/> - <table:table-cell table:style-name="ce17"/> - <table:table-cell table:style-name="ce22"/> + <table:table-cell table:style-name="ce11" table:formula="of:=MDETERM(LARGE([.I30:.I39];{1;2|3;4}))" office:value-type="float" office:value="-2" calcext:value-type="float"> + <text:p>-2</text:p> + </table:table-cell> + <table:table-cell office:value-type="float" office:value="-2" calcext:value-type="float"> + <text:p>-2</text:p> + </table:table-cell> + <table:table-cell table:style-name="ce16" table:formula="of:=ROUND([.A30];12)=ROUND([.B30];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean"> + <text:p>TRUE</text:p> + </table:table-cell> + <table:table-cell table:style-name="ce22" table:formula="of:=FORMULA([.A30])" office:value-type="string" office:string-value="=MDETERM(LARGE(I30:I39,{1,2;3,4}))" calcext:value-type="string"> + <text:p>=MDETERM(LARGE(I30:I39,{1,2;3,4}))</text:p> + </table:table-cell> <table:table-cell table:number-columns-repeated="4"/> <table:table-cell table:style-name="ce11" office:value-type="float" office:value="2" calcext:value-type="float"> <text:p>2</text:p> diff --git a/sc/qa/unit/data/functions/statistical/fods/small.fods b/sc/qa/unit/data/functions/statistical/fods/small.fods index 94a6ae6344ef..549be5c7e187 100644 --- a/sc/qa/unit/data/functions/statistical/fods/small.fods +++ b/sc/qa/unit/data/functions/statistical/fods/small.fods @@ -4186,10 +4186,19 @@ <table:table-cell table:style-name="ce27" table:number-columns-repeated="4"/> <table:table-cell table:number-columns-repeated="2"/> </table:table-row> - <table:table-row table:style-name="ro6"> - <table:table-cell table:number-columns-repeated="2"/> - <table:table-cell table:style-name="ce28"/> - <table:table-cell table:style-name="ce32"/> + <table:table-row table:style-name="ro2"> + <table:table-cell table:style-name="ce19" table:formula="of:=MDETERM(SMALL([.F1:.F11];{1;2|3;4}))" office:value-type="float" office:value="-13" calcext:value-type="float"> + <text:p>-13</text:p> + </table:table-cell> + <table:table-cell office:value-type="float" office:value="-13" calcext:value-type="float"> + <text:p>-13</text:p> + </table:table-cell> + <table:table-cell table:style-name="ce25" table:formula="of:=ROUND([.A13];12)=ROUND([.B13];12)" office:value-type="boolean" office:boolean-value="true" calcext:value-type="boolean"> + <text:p>TRUE</text:p> + </table:table-cell> + <table:table-cell table:style-name="ce32" table:formula="of:=FORMULA([.A13])" office:value-type="string" office:string-value="=MDETERM(SMALL(F1:F11,{1,2;3,4}))" calcext:value-type="string"> + <text:p>=MDETERM(SMALL(F1:F11,{1,2;3,4}))</text:p> + </table:table-cell> <table:table-cell table:number-columns-repeated="4"/> <table:table-cell office:value-type="float" office:value="900000012" calcext:value-type="float"> <text:p>900000012</text:p> diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx index 7608098d53bb..b6c68dcdb264 100644 --- a/sc/source/core/inc/interpre.hxx +++ b/sc/source/core/inc/interpre.hxx @@ -175,6 +175,8 @@ public: ScMatrixRef GetNewMat(SCSIZE nC, SCSIZE nR, bool bEmpty = false); + ScMatrixRef GetNewMat(SCSIZE nC, SCSIZE nR, const std::vector<double>& rValues); + enum VolatileType { VOLATILE, VOLATILE_MACRO, @@ -225,6 +227,8 @@ private: VolatileType meVolatileType; + void MakeMatNew(ScMatrixRef& rMat, SCSIZE nC, SCSIZE nR); + /// Merge global and document specific settings. void MergeCalcConfig(); @@ -934,6 +938,7 @@ private: void ScMedian(); double GetMedian( ::std::vector<double> & rArray ); double GetPercentileExclusive( ::std::vector<double> & rArray, double fPercentile ); + std::vector<double> GetTopNumberArray( SCSIZE& rCol, SCSIZE& rRow ); void GetNumberSequenceArray( sal_uInt8 nParamCount, ::std::vector<double>& rArray, bool bConvertTextInArray ); void GetSortArray( sal_uInt8 nParamCount, ::std::vector<double>& rSortArray, ::std::vector<long>* pIndexOrder, bool bConvertTextInArray, bool bAllowEmptyArray ); static void QuickSort(::std::vector<double>& rSortArray, ::std::vector<long>* pIndexOrder); diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx index ac980b7257da..f91d0037ddb5 100644 --- a/sc/source/core/tool/interpr3.cxx +++ b/sc/source/core/tool/interpr3.cxx @@ -3639,14 +3639,15 @@ void ScInterpreter::CalculateSmallLarge(bool bSmall) if ( !MustHaveParamCount( GetByte(), 2 ) ) return; - std::vector<double> aArray; - GetNumberSequenceArray(1, aArray, false); + SCSIZE nCol = 0, nRow = 0; + auto aArray = GetTopNumberArray(nCol, nRow); auto aArraySize = aArray.size(); if (aArraySize == 0 || nGlobalError != FormulaError::NONE) { PushNoValue(); return; } + assert(aArraySize == nCol * nRow); for (double fArg : aArray) { double f = ::rtl::math::approxFloor(fArg); @@ -3701,8 +3702,7 @@ void ScInterpreter::CalculateSmallLarge(bool bSmall) aArray.clear(); for (SCSIZE n : aRankArray) aArray.push_back(aSortArray[bSmall ? n-1 : nSize-n]); - ScMatrixRef pResult = GetNewMat(1, aArraySize, true); - pResult->PutDoubleVector(aArray, 0, 0); + ScMatrixRef pResult = GetNewMat(nCol, nRow, aArray); PushMatrix(pResult); } } @@ -3841,6 +3841,91 @@ void ScInterpreter::ScTrimMean() } } +std::vector<double> ScInterpreter::GetTopNumberArray( SCSIZE& rCol, SCSIZE& rRow ) +{ + std::vector<double> aArray; + switch (GetStackType()) + { + case svDouble: + aArray.push_back(PopDouble()); + rCol = rRow = 1; + break; + case svSingleRef: + { + ScAddress aAdr; + PopSingleRef(aAdr); + ScRefCellValue aCell(*pDok, aAdr); + if (aCell.hasNumeric()) + { + aArray.push_back(GetCellValue(aAdr, aCell)); + rCol = rRow = 1; + } + } + break; + case svDoubleRef: + { + ScRange aRange; + PopDoubleRef(aRange, true); + if (nGlobalError != FormulaError::NONE) + break; + + // give up unless the start and end are in the same sheet + if (aRange.aStart.Tab() != aRange.aEnd.Tab()) + { + SetError(FormulaError::IllegalParameter); + break; + } + + // the range already is in order + assert(aRange.aStart.Col() <= aRange.aEnd.Col()); + assert(aRange.aStart.Row() <= aRange.aEnd.Row()); + rCol = aRange.aEnd.Col() - aRange.aStart.Col() + 1; + rRow = aRange.aEnd.Row() - aRange.aStart.Row() + 1; + aArray.reserve(rCol * rRow); + + FormulaError nErr = FormulaError::NONE; + double fCellVal; + ScValueIterator aValIter(pDok, aRange, mnSubTotalFlags); + if (aValIter.GetFirst(fCellVal, nErr)) + { + do + aArray.push_back(fCellVal); + while (aValIter.GetNext(fCellVal, nErr) && nErr == FormulaError::NONE); + } + if (aArray.size() != rCol * rRow) + { + aArray.clear(); + SetError(nErr); + } + } + break; + case svMatrix: + case svExternalSingleRef: + case svExternalDoubleRef: + { + ScMatrixRef pMat = GetMatrix(); + if (!pMat) + break; + + if (pMat->IsNumeric()) + { + SCSIZE nCount = pMat->GetElementCount(); + aArray.reserve(nCount); + for (SCSIZE i = 0; i < nCount; ++i) + aArray.push_back(pMat->GetDouble(i)); + pMat->GetDimensions(rCol, rRow); + } + else + SetError(FormulaError::IllegalParameter); + } + break; + default: + SetError(FormulaError::IllegalParameter); + break; + } + return aArray; +} + void ScInterpreter::GetNumberSequenceArray( sal_uInt8 nParamCount, vector<double>& rArray, bool bConvertTextInArray ) { ScAddress aAdr; diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx index c898d7a95057..db6500b067f1 100644 --- a/sc/source/core/tool/interpr5.cxx +++ b/sc/source/core/tool/interpr5.cxx @@ -281,25 +281,36 @@ void ScInterpreter:: ScLCM() } } -ScMatrixRef ScInterpreter::GetNewMat(SCSIZE nC, SCSIZE nR, bool bEmpty) +void ScInterpreter::MakeMatNew(ScMatrixRef& rMat, SCSIZE nC, SCSIZE nR) { - ScMatrixRef pMat; - if (bEmpty) - pMat = new ScMatrix(nC, nR); - else - pMat = new ScMatrix(nC, nR, 0.0); - - pMat->SetErrorInterpreter( this); + rMat->SetErrorInterpreter( this); // A temporary matrix is mutable and ScMatrix::CloneIfConst() returns the // very matrix. - pMat->SetMutable(); + rMat->SetMutable(); SCSIZE nCols, nRows; - pMat->GetDimensions( nCols, nRows); + rMat->GetDimensions( nCols, nRows); if ( nCols != nC || nRows != nR ) { // arbitrary limit of elements exceeded SetError( FormulaError::MatrixSize); - pMat.reset(); + rMat.reset(); } +} + +ScMatrixRef ScInterpreter::GetNewMat(SCSIZE nC, SCSIZE nR, bool bEmpty) +{ + ScMatrixRef pMat; + if (bEmpty) + pMat = new ScMatrix(nC, nR); + else + pMat = new ScMatrix(nC, nR, 0.0); + MakeMatNew(pMat, nC, nR); + return pMat; +} + +ScMatrixRef ScInterpreter::GetNewMat(SCSIZE nC, SCSIZE nR, const std::vector<double>& rValues) +{ + ScMatrixRef pMat(new ScMatrix(nC, nR, rValues)); + MakeMatNew(pMat, nC, nR); return pMat; } |