summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2017-05-20 23:05:33 +0200
committerEike Rathke <erack@redhat.com>2017-05-22 11:00:56 +0200
commitc41b82203ef54a74bd0693e29f65617d0e158a06 (patch)
tree93d39faba40c5fa74166c5ffc18e746f7a0607c0
parent5236e847191bbc3fb47a630bec5dbe8ed65679d7 (diff)
Handle MIN and MAX with arrays of references, tdf#58874
Change-Id: I24c9f3078f60e14e64f1e1e3910963dfe0a38d77
-rw-r--r--sc/source/core/tool/interpr1.cxx162
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 )