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;
    }