diff options
author | Eike Rathke <erack@redhat.com> | 2017-05-20 23:05:33 +0200 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2017-05-22 11:00:56 +0200 |
commit | c41b82203ef54a74bd0693e29f65617d0e158a06 (patch) | |
tree | 93d39faba40c5fa74166c5ffc18e746f7a0607c0 | |
parent | 5236e847191bbc3fb47a630bec5dbe8ed65679d7 (diff) |
Handle MIN and MAX with arrays of references, tdf#58874
Change-Id: I24c9f3078f60e14e64f1e1e3910963dfe0a38d77
-rw-r--r-- | sc/source/core/tool/interpr1.cxx | 162 |
1 files changed, 153 insertions, 9 deletions
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index 7417e54b8ca3..bf8b9dc77c00 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -3461,6 +3461,9 @@ void ScInterpreter::ScMin( bool bTextAsZero ) short nParamCount = GetByte(); if (!MustHaveParamCountMin( nParamCount, 1)) return; + const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount); + ScMatrixRef xResMat; + size_t nRefArrayPos = std::numeric_limits<size_t>::max(); double nMin = ::std::numeric_limits<double>::max(); double nVal = 0.0; ScAddress aAdr; @@ -3494,9 +3497,35 @@ void ScInterpreter::ScMin( bool bTextAsZero ) } } break; - case svDoubleRef : case svRefList : { + const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]); + if (p && p->IsArrayResult()) + { + nRefArrayPos = nRefInList; + if (!xResMat) + { + // Create and init all elements with current value. + assert(nMatRows > 0); + xResMat = GetNewMat( 1, nMatRows, true); + xResMat->FillDouble( nMin, 0,0, 0,nMatRows-1); + } + else + { + // Current value and values from vector are operands + // for each vector position. + for (SCSIZE i=0; i < nMatRows; ++i) + { + double fVecRes = xResMat->GetDouble(0,i); + if (fVecRes > nMin) + xResMat->PutDouble( nMin, 0,i); + } + } + } + } + SAL_FALLTHROUGH; + case svDoubleRef : + { FormulaError nErr = FormulaError::NONE; PopDoubleRef( aRange, nParamCount, nRefInList); ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags, bTextAsZero ); @@ -3512,6 +3541,18 @@ void ScInterpreter::ScMin( bool bTextAsZero ) } SetError(nErr); } + if (nRefArrayPos != std::numeric_limits<size_t>::max()) + { + // Update vector element with current value. + double fVecRes = xResMat->GetDouble(0,nRefArrayPos); + if (fVecRes > nMin) + xResMat->PutDouble( nMin, 0,nRefArrayPos); + + // Reset. + nMin = std::numeric_limits<double>::max(); + nVal = 0.0; + nRefArrayPos = std::numeric_limits<size_t>::max(); + } } break; case svMatrix : @@ -3545,10 +3586,41 @@ void ScInterpreter::ScMin( bool bTextAsZero ) SetError(FormulaError::IllegalParameter); } } - if ( nVal < nMin ) - PushDouble(0.0); + + if (xResMat) + { + // Include value of last non-references-array type and calculate final result. + if (nMin < std::numeric_limits<double>::max()) + { + for (SCSIZE i=0; i < nMatRows; ++i) + { + double fVecRes = xResMat->GetDouble(0,i); + if (fVecRes > nMin) + xResMat->PutDouble( nMin, 0,i); + } + } + else + { + /* TODO: the awkward "no value is minimum 0.0" is likely the case + * if a value is numeric_limits::max. Still, that could be a valid + * minimum value as well, but nVal and nMin had been reset after + * the last svRefList.. so we may lie here. */ + for (SCSIZE i=0; i < nMatRows; ++i) + { + double fVecRes = xResMat->GetDouble(0,i); + if (fVecRes == std::numeric_limits<double>::max()) + xResMat->PutDouble( 0.0, 0,i); + } + } + PushMatrix( xResMat); + } else - PushDouble(nMin); + { + if ( nVal < nMin ) + PushDouble(0.0); // zero or only empty arguments + else + PushDouble(nMin); + } } void ScInterpreter::ScMax( bool bTextAsZero ) @@ -3556,7 +3628,10 @@ void ScInterpreter::ScMax( bool bTextAsZero ) short nParamCount = GetByte(); if (!MustHaveParamCountMin( nParamCount, 1)) return; - double nMax = -(::std::numeric_limits<double>::max()); + const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount); + ScMatrixRef xResMat; + size_t nRefArrayPos = std::numeric_limits<size_t>::max(); + double nMax = std::numeric_limits<double>::lowest(); double nVal = 0.0; ScAddress aAdr; ScRange aRange; @@ -3589,9 +3664,35 @@ void ScInterpreter::ScMax( bool bTextAsZero ) } } break; - case svDoubleRef : case svRefList : { + const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]); + if (p && p->IsArrayResult()) + { + nRefArrayPos = nRefInList; + if (!xResMat) + { + // Create and init all elements with current value. + assert(nMatRows > 0); + xResMat = GetNewMat( 1, nMatRows, true); + xResMat->FillDouble( nMax, 0,0, 0,nMatRows-1); + } + else + { + // Current value and values from vector are operands + // for each vector position. + for (SCSIZE i=0; i < nMatRows; ++i) + { + double fVecRes = xResMat->GetDouble(0,i); + if (fVecRes < nMax) + xResMat->PutDouble( nMax, 0,i); + } + } + } + } + SAL_FALLTHROUGH; + case svDoubleRef : + { FormulaError nErr = FormulaError::NONE; PopDoubleRef( aRange, nParamCount, nRefInList); ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags, bTextAsZero ); @@ -3607,6 +3708,18 @@ void ScInterpreter::ScMax( bool bTextAsZero ) } SetError(nErr); } + if (nRefArrayPos != std::numeric_limits<size_t>::max()) + { + // Update vector element with current value. + double fVecRes = xResMat->GetDouble(0,nRefArrayPos); + if (fVecRes < nMax) + xResMat->PutDouble( nMax, 0,nRefArrayPos); + + // Reset. + nMax = std::numeric_limits<double>::lowest(); + nVal = 0.0; + nRefArrayPos = std::numeric_limits<size_t>::max(); + } } break; case svMatrix : @@ -3640,10 +3753,41 @@ void ScInterpreter::ScMax( bool bTextAsZero ) SetError(FormulaError::IllegalParameter); } } - if ( nVal > nMax ) - PushDouble(0.0); + + if (xResMat) + { + // Include value of last non-references-array type and calculate final result. + if (nMax > std::numeric_limits<double>::lowest()) + { + for (SCSIZE i=0; i < nMatRows; ++i) + { + double fVecRes = xResMat->GetDouble(0,i); + if (fVecRes < nMax) + xResMat->PutDouble( nMax, 0,i); + } + } + else + { + /* TODO: the awkward "no value is maximum 0.0" is likely the case + * if a value is numeric_limits::lowest. Still, that could be a + * valid maximum value as well, but nVal and nMax had been reset + * after the last svRefList.. so we may lie here. */ + for (SCSIZE i=0; i < nMatRows; ++i) + { + double fVecRes = xResMat->GetDouble(0,i); + if (fVecRes == -std::numeric_limits<double>::max()) + xResMat->PutDouble( 0.0, 0,i); + } + } + PushMatrix( xResMat); + } else - PushDouble(nMax); + { + if ( nVal > nMax ) + PushDouble(0.0); // zero or only empty arguments + else + PushDouble(nMax); + } } void ScInterpreter::GetStVarParams( double& rVal, double& rValCount, bool bTextAsZero ) |