Resolves: tdf#153924 handle non-numeric and error values in rank array
... of LARGE()/SMALL() instead of yielding error value for all result
elements.
Fallout from
commit e4c2d0bb57ab8ea8f5c400d103d01376b8140f22
CommitDate: Fri Nov 30 22:14:17 2018 +0100
i#32345 Support a matrix of rank argument for LARGE()/SMALL()
that in ScInterpreter::GetTopNumberArray() required the entire
rank array would have to be numeric, which with an empty cell or
string it isn't.
Change-Id: Ieaa1a68bb8f98614119550b1442665b6fbb4817a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148178
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins
(cherry picked from commit 019e751c71dcb2d34c6fd8bb9dda267c6ba2b48e)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148218
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx
index e9100d7..1fa4500 100644
--- a/sc/source/core/tool/interpr3.cxx
+++ b/sc/source/core/tool/interpr3.cxx
@@ -3638,8 +3638,8 @@ void ScInterpreter::CalculateSmallLarge(bool bSmall)
return;
SCSIZE nCol = 0, nRow = 0;
auto aArray = GetTopNumberArray(nCol, nRow);
const auto nRankArraySize = aArray.size();
const auto aArray = GetTopNumberArray(nCol, nRow);
const size_t nRankArraySize = aArray.size();
if (nRankArraySize == 0 || nGlobalError != FormulaError::NONE)
{
PushNoValue();
@@ -3667,7 +3667,12 @@ void ScInterpreter::CalculateSmallLarge(bool bSmall)
{
const SCSIZE k = aRankArray[0];
if (k < 1 || nSize < k)
PushNoValue();
{
if (!std::isfinite(aArray[0]))
PushDouble(aArray[0]); // propagates error
else
PushNoValue();
}
else
{
vector<double>::iterator iPos = aSortArray.begin() + (bSmall ? k-1 : nSize-k);
@@ -3699,15 +3704,19 @@ void ScInterpreter::CalculateSmallLarge(bool bSmall)
else
std::sort(aSortArray.begin(), aSortArray.end());
aArray.clear();
for (SCSIZE n : aRankArray)
std::vector<double> aResultArray;
aResultArray.reserve(nRankArraySize);
for (size_t i = 0; i < nRankArraySize; ++i)
{
const SCSIZE n = aRankArray[i];
if (1 <= n && n <= nSize)
aArray.push_back( aSortArray[bSmall ? n-1 : nSize-n]);
aResultArray.push_back( aSortArray[bSmall ? n-1 : nSize-n]);
else if (!std::isfinite( aArray[i]))
aResultArray.push_back( aArray[i]); // propagate error
else
aArray.push_back( CreateDoubleError( FormulaError::NoValue));
aResultArray.push_back( CreateDoubleError( FormulaError::IllegalArgument));
}
ScMatrixRef pResult = GetNewMat(nCol, nRow, aArray);
ScMatrixRef pResult = GetNewMat(nCol, nRow, aResultArray);
PushMatrix(pResult);
}
}
@@ -3912,19 +3921,30 @@ std::vector<double> ScInterpreter::GetTopNumberArray( SCSIZE& rCol, SCSIZE& rRow
if (!pMat)
break;
const SCSIZE nCount = pMat->GetElementCount();
aArray.reserve(nCount);
// Do not propagate errors from matrix elements as global error.
pMat->SetErrorInterpreter(nullptr);
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);
{
for (SCSIZE i = 0; i < nCount; ++i)
{
if (pMat->IsValue(i))
aArray.push_back( pMat->GetDouble(i));
else
aArray.push_back( CreateDoubleError( FormulaError::NoValue));
}
}
pMat->GetDimensions(rCol, rRow);
}
break;
default:
PopError();
SetError(FormulaError::IllegalParameter);
break;
}