sc/source/core/opencl/formulagroupcl.cxx |    6 
 sc/source/core/opencl/op_financial.cxx   |  402 ++++++-------------------------
 sc/source/core/opencl/op_financial.hxx   |   54 +---
 sc/source/core/opencl/op_statistical.cxx |    2 
 sc/source/core/opencl/opbase.cxx         |   96 ++++---
 sc/source/core/opencl/opbase.hxx         |   15 +
 6 files changed, 170 insertions(+), 405 deletions(-)

New commits:
commit e39f5eedc09fb79159bc764f1215d24afa9035e0
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Tue Sep 20 09:57:21 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Tue Sep 20 17:52:27 2022 +0200

    fix and simplify opencl IRR(), MIRR(), XIRR() and XNPV()
    
    Change-Id: Ie57e43458f7fa5a769806d0fe3054745ec71c99e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140221
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/source/core/opencl/formulagroupcl.cxx 
b/sc/source/core/opencl/formulagroupcl.cxx
index b4e35e932ba5..87c34f53ef1c 100644
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -3024,11 +3024,11 @@ 
DynamicKernelSoPArguments::DynamicKernelSoPArguments(const ScCalcConfig& config,
                     mvSubArguments.push_back(SoPHelper(mCalcConfig, ts, 
ft->Children[i],
                             std::make_shared<OpMDuration>(), nResultSize));
                 }
-                /*else if (pChild->GetExternal() == 
"com.sun.star.sheet.addin.Analysis.getXirr")
+                else if (pChild->GetExternal() == 
"com.sun.star.sheet.addin.Analysis.getXirr")
                 {
                     mvSubArguments.push_back(SoPHelper(mCalcConfig, ts, 
ft->Children[i],
-                            std::make_shared<OpXirr, nResultSize));
-                }*/
+                            std::make_shared<OpXirr>(), nResultSize));
+                }
                 else if (pChild->GetExternal() == 
"com.sun.star.sheet.addin.Analysis.getOddlprice")
                 {
                     mvSubArguments.push_back(SoPHelper(mCalcConfig, ts,
diff --git a/sc/source/core/opencl/op_financial.cxx 
b/sc/source/core/opencl/op_financial.cxx
index 83c9472e6c22..92263d78abb4 100644
--- a/sc/source/core/opencl/op_financial.cxx
+++ b/sc/source/core/opencl/op_financial.cxx
@@ -18,13 +18,13 @@ namespace sc::opencl {
 // Definitions of inline functions
 #include "op_financial_helpers.hxx"
 
-void RRI::GenSlidingWindowFunction(
+void OpRRI::GenSlidingWindowFunction(
     outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments)
 {
     CHECK_PARAMETER_COUNT( 3, 3 );
     GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
     ss << "{\n";
-    ss << "    double tmp = " << GetBottom() <<";\n";
+    ss << "    double tmp;\n";
     ss << "    int gid0 = get_global_id(0);\n";
     GenerateArg( "nper", 0, vSubArguments, ss );
     GenerateArg( "pv", 1, vSubArguments, ss );
@@ -402,251 +402,64 @@ vSubArguments)
     ss <<"}";
 }
 
-void IRR::GenSlidingWindowFunction(outputstream &ss,
+void OpIRR::GenSlidingWindowFunction(outputstream &ss,
             const std::string &sSymName, SubArguments &vSubArguments)
 {
     CHECK_PARAMETER_COUNT( 2, 2 );
+    CHECK_PARAMETER_DOUBLEVECTORREF( 0 );
     GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
     ss << "{\n";
     ss << "    #define  Epsilon   1.0E-7\n";
     ss << "    int gid0 = get_global_id(0);\n";
-    FormulaToken* pSur = vSubArguments[1]->GetFormulaToken();
-    assert(pSur);
-    ss << "    double fEstimated = ";
-    ss << vSubArguments[1]->GenSlidingWindowDeclRef() << ";\n";
+    GenerateArgWithDefault( "fEstimated", 1, 0.1, vSubArguments, ss );
     ss << "    double fEps = 1.0;\n";
-    ss << "    double x = 0.0, xNew = 0.0, fNumerator = 0.0, fDenominator = 
0.0;\n";
+    ss << "    double xNew = 0.0, fNumerator = 0.0, fDenominator = 0.0;\n";
     ss << "    double nCount = 0.0;\n";
-    if (pSur->GetType() == formula::svSingleVectorRef)
-    {
-        const formula::SingleVectorRefToken* pSVR =
-            static_cast< const formula::SingleVectorRefToken* >(pSur);
-        ss << "    if (gid0 >= " << pSVR->GetArrayLength() << ")\n";
-        ss << "        fEstimated = 0.1;\n";
-        ss << "    if (isnan(fEstimated))\n";
-        ss << "        x = 0.1;\n";
-        ss << "    else\n";
-    }
-    else if (pSur->GetType() == formula::svDouble)
-    {
-        ss << "    if (isnan(fEstimated))\n";
-        ss << "        x = 0.1;\n";
-        ss << "    else\n";
-    }
-    ss << "        x = fEstimated;\n";
     ss << "    unsigned short nItCount = 0;\n";
-    ss << "    while (fEps > Epsilon && nItCount < 20){\n";
+    ss << "    double x = fEstimated;\n";
+    ss << "    while (fEps > Epsilon && nItCount < 20)\n";
+    ss << "    {\n";
     ss << "        nCount = 0.0; fNumerator = 0.0;  fDenominator = 0.0;\n";
-    ss << "        double arg0, arg1;\n";
-    ss << "        int i = 0;\n";
-    FormulaToken* pCur = vSubArguments[0]->GetFormulaToken();
-    assert(pCur);
-    const formula::DoubleVectorRefToken* pDVR =
-        static_cast<const formula::DoubleVectorRefToken* >(pCur);
-    size_t nCurWindowSize = pDVR->GetRefRowSize();
-    ss << "        for ( ";
-    if (!pDVR->IsStartFixed() && pDVR->IsEndFixed()) {
-        ss << "i = gid0; i < " << pDVR->GetArrayLength();
-        ss << " && i < " << nCurWindowSize << " /2*2; i++){\n";
-        ss << "            arg0 = ";
-        ss << vSubArguments[0]->GenSlidingWindowDeclRef() << ";\n";
-        ss << "            i++;;\n";
-        ss << "            arg1 = ";
-        ss << vSubArguments[0]->GenSlidingWindowDeclRef() << ";\n";
-        ss << "            if (!isnan(arg0)){\n";
-        ss << "            fNumerator += arg0 / pow(1.0 + x, nCount);\n";
-        ss << "            
fDenominator+=-1*nCount*arg0/pow(1.0+x,nCount+1.0);\n";
-        ss << "            nCount += 1;\n";
-        ss << "            }\n";
-        ss << "            if (!isnan(arg1)){\n";
-        ss << "                fNumerator += arg1 / pow(1.0 + x, nCount);\n";
-        ss << "            
fDenominator+=-1*nCount*arg1/pow(1.0+x,nCount+1.0);\n";
-        ss << "                nCount += 1;\n";
-        ss << "            }\n";
-        ss << "        }\n";
-        ss << "if(i < " << pDVR->GetArrayLength();
-        ss << " && i < " << nCurWindowSize << ") ;{\n";
-    }
-    else if (pDVR->IsStartFixed() && !pDVR->IsEndFixed()) {
-        ss << "; i < " << pDVR->GetArrayLength();
-        ss << " && i < (gid0+" << nCurWindowSize << " )/2*2; i++){\n";
-        ss << "            arg0 = ";
-        ss << vSubArguments[0]->GenSlidingWindowDeclRef() << ";\n";
-        ss << "            if (!isnan(arg0)){\n";
-        ss << "            fNumerator += arg0 / pow(1.0 + x, nCount);\n";
-        ss << "            
fDenominator+=-1*nCount*arg0/pow(1.0+x,nCount+1.0);\n";
-        ss << "            nCount += 1;\n";
-        ss << "            }\n";
-        ss << "            i++;\n";
-        ss << "            arg1 = ";
-        ss << vSubArguments[0]->GenSlidingWindowDeclRef() << ";\n";
-        ss << "            if (!isnan(arg1)){\n";
-        ss << "                fNumerator += arg1 / pow(1.0 + x, nCount);\n";
-        ss << "            
fDenominator+=-1*nCount*arg1/pow(1.0+x,nCount+1.0);\n";
-        ss << "                nCount+=1;\n";
-        ss << "            }\n";
-        ss << "        }\n";
-        ss << "        if(i < " << pDVR->GetArrayLength();
-        ss << " && i < gid0+" << nCurWindowSize << "){\n";
-    }
-    else if (!pDVR->IsStartFixed() && !pDVR->IsEndFixed()){
-        ss << " ; i + gid0 < " << pDVR->GetArrayLength();
-        ss << " &&  i < " << nCurWindowSize << " /2*2; i++){\n";
-        ss << "            arg0 = ";
-        ss << vSubArguments[0]->GenSlidingWindowDeclRef() << ";\n";
-        ss << "            i++;;\n";
-        ss << "            arg1 = ";
-        ss << vSubArguments[0]->GenSlidingWindowDeclRef() << ";\n";
-        ss << "            if (!isnan(arg0)){\n";
-        ss << "            fNumerator += arg0 / pow(1.0 + x, nCount);\n";
-        ss << "            
fDenominator+=-1*nCount*arg0/pow(1.0+x,nCount+1.0);\n";
-        ss << "            nCount += 1;\n";
-        ss << "            }\n";
-        ss << "            if (!isnan(arg1)){\n";
-        ss << "                fNumerator += arg1 / pow(1.0 + x, nCount);\n";
-        ss << "            
fDenominator+=-1*nCount*arg1/pow(1.0+x,nCount+1.0);\n";
-        ss << "                nCount+=1;\n";
-        ss << "            }\n";
-        ss << "        }\n";
-        ss << "        if(i + gid0 < " << pDVR->GetArrayLength() << " &&";
-        ss << " i < " << nCurWindowSize << "){\n";
-
-    } else {
-        ss << "; i < " << nCurWindowSize << " /2*2; i++){\n";
-        ss << "            arg0 = ";
-        ss << vSubArguments[0]->GenSlidingWindowDeclRef() << ";\n";
-        ss << "            i++;;\n";
-        ss << "            arg1 = ";
-        ss << vSubArguments[0]->GenSlidingWindowDeclRef() << ";\n";
-        ss << "            if (!isnan(arg0)){\n";
-        ss << "            fNumerator += arg0 / pow(1.0 + x, nCount);\n";
-        ss << "            
fDenominator+=-1*nCount*arg0/pow(1.0+x,nCount+1.0);\n";
-        ss << "            nCount += 1;\n";
-        ss << "            }\n";
-        ss << "            if (!isnan(arg1)){\n";
-        ss << "                fNumerator += arg1 / pow(1.0 + x, nCount);\n";
-        ss << "            
fDenominator+=-1*nCount*arg1/pow(1.0+x,nCount+1.0);\n";
-        ss << "                nCount+=1;\n";
-        ss << "            }\n";
-        ss << "        }\n";
-        ss << "if(i<" << nCurWindowSize << "){\n";
-
-    }
-    ss << "            arg0 = ";
-    ss << vSubArguments[0]->GenSlidingWindowDeclRef() << ";\n";
-    ss << "        if (isnan(arg0))\n";
-    ss << "            continue;\n";
-    ss << "        fNumerator += arg0 / pow(1.0+x, nCount);\n";
-    ss << "        fDenominator  += -nCount * arg0 / pow(1.0+x,nCount+1.0);\n";
-    ss << "        nCount+=1;\n";
-    ss << "        }\n";
+    GenerateRangeArg( 0, vSubArguments, ss,
+        "            if (!isnan(arg))\n"
+        "            {\n"
+        "                fNumerator += arg / pow(1.0 + x, nCount);\n"
+        "                fDenominator+=-1*nCount*arg/pow(1.0+x,nCount+1.0);\n"
+        "                nCount += 1;\n"
+        "            }\n"
+        );
     ss << "        xNew = x - fNumerator / fDenominator;\n";
     ss << "        fEps = fabs(xNew - x);\n";
     ss << "        x = xNew;\n";
-    ss << "        nItCount++;\n    }\n";
-    ss << "        if (fEstimated == 0.0 && fabs(x) < Epsilon)\n";
-    ss << "            x = 0.0;\n";
-    ss << "        if (fEps < Epsilon)\n";
-    ss << "            return x;\n";
-    ss << "        else\n";
-    // FIXME: This is of course horribly wrong. 523 is the error code 
NoConvergence, and this should
-    // be CreateDoubleError(523). Ditto for the other occurrences of 523 in 
the OpenCL code
-    // generated in this file.
-    ss << "            return (double)523;\n";
-    ss << "}";
+    ss << "        nItCount++;\n";
+    ss << "    }\n";
+    ss << "    if (fEstimated == 0.0 && fabs(x) < Epsilon)\n";
+    ss << "        x = 0.0;\n";
+    ss << "    if (fEps < Epsilon)\n";
+    ss << "        return x;\n";
+    ss << "    else\n";
+    ss << "        return CreateDoubleError(NoConvergence);\n";
+    ss << "}\n";
 }
 
 void XNPV::GenSlidingWindowFunction(
     outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments)
 {
     CHECK_PARAMETER_COUNT( 3, 3 );
-    FormulaToken *pCur = vSubArguments[1]->GetFormulaToken();
-    assert(pCur);
-    const formula::DoubleVectorRefToken* pCurDVR =
-        static_cast<const formula::DoubleVectorRefToken *>(pCur);
-    size_t nCurWindowSize = pCurDVR->GetRefRowSize();
+    CHECK_PARAMETER_DOUBLEVECTORREF( 1 );
+    CHECK_PARAMETER_DOUBLEVECTORREF( 2 );
     GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
-    ss << "{\n\t";
-    ss << "double result = 0.0;\n\t";
-    ss << "int gid0 = get_global_id(0);\n\t";
-    ss << "int i=0;\n\t";
-    ss << "double date;\n\t";
-    ss << "double value;\n\t";
-    ss << "double rate;\n\t";
-    ss << "double dateNull;\n\t";
-    FormulaToken *tmpCur0 = vSubArguments[0]->GetFormulaToken();
-    const formula::SingleVectorRefToken*tmpCurDVR0= static_cast<const
-    formula::SingleVectorRefToken *>(tmpCur0);
-
-    FormulaToken *tmpCur1 = vSubArguments[1]->GetFormulaToken();
-    const formula::DoubleVectorRefToken*tmpCurDVR1= static_cast<const
-    formula::DoubleVectorRefToken *>(tmpCur1);
-
-    FormulaToken *tmpCur2 = vSubArguments[2]->GetFormulaToken();
-    const formula::DoubleVectorRefToken*tmpCurDVR2= static_cast<const
-    formula::DoubleVectorRefToken *>(tmpCur2);
-    ss<< "int buffer_rate_len = ";
-    ss<< tmpCurDVR0->GetArrayLength();
-    ss << ";\n\t";
-    ss<< "int buffer_value_len = ";
-    ss<< tmpCurDVR1->GetArrayLength();
-    ss << ";\n\t";
-    ss<< "int buffer_date_len = ";
-    ss<< tmpCurDVR2->GetArrayLength();
-    ss << ";\n\t";
-    ss<<"if((gid0)>=buffer_date_len || isnan(";
-    ss << vSubArguments[2]->GenSlidingWindowDeclRef();
-    ss<<"))\n\t\t";
-    ss<<"return NAN;\n\telse \n";
-    ss<<"dateNull = ";
-    ss << vSubArguments[2]->GenSlidingWindowDeclRef();
-    ss<<";\n\t";
-    ss<<"if((gid0)>=buffer_rate_len || isnan(";
-    ss << vSubArguments[0]->GenSlidingWindowDeclRef();
-    ss<<"))\n\t\t";
-    ss<<"return NAN;\n\telse \n";
-    ss<<"rate = ";
-    ss << vSubArguments[0]->GenSlidingWindowDeclRef();
-    ss<<";\n\t";
-    ss<<"if(1 == buffer_date_len )\n";
-    ss<<"return ";
-    ss << vSubArguments[1]->GenSlidingWindowDeclRef();
-    ss<<";\n\t";
-    ss << "for (int i = ";
-    if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed())
-    {
-        ss << "gid0; i < "<< nCurWindowSize <<"; i++)\n\t\t";
-    }
-    else if (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
-    {
-        ss << "0; i < gid0+"<< nCurWindowSize <<"; i++)\n\t\t";
-    }
-    else
-    {
-        ss << "0; i < "<< nCurWindowSize <<"; i++)\n\t\t";
-    }
-    ss << "{\n\t";
-    if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
-    {
-        ss <<  "if((i+gid0)>=buffer_value_len || 
(i+gid0)>=buffer_date_len)\n\t\t";
-        ss <<  "return result;\n\telse \n\t\t";
-    }
-    else
-    {
-        ss <<  "if(i>=buffer_value_len || i>=buffer_date_len)\n\t\t";
-        ss <<  "return result;\n\telse \n\t\t";
-    }
-
-    ss <<  "value = ";
-    ss <<  vSubArguments[1]->GenSlidingWindowDeclRef(true);
-    ss <<  ";\n";
-    ss <<  " date = ";
-    ss <<  vSubArguments[2]->GenSlidingWindowDeclRef(true);
-    ss <<  ";\n";
-    ss <<  "result += value/(pow((rate+1),(date-dateNull)/365));\n";
-    ss <<  "}\n";
-    ss <<  "return result;\n";
-    ss <<  "}";
+    ss << "{\n";
+    ss << "    double result = 0.0;\n";
+    ss << "    int gid0 = get_global_id(0);\n";
+    GenerateArg( "rate", 0, vSubArguments, ss );
+    GenerateRangeArgElement( "dateNull", 2, "0", vSubArguments, ss );
+    GenerateRangeArgPair( 1, 2, vSubArguments, ss,
+        "        if( !isnan(arg1) && !isnan(arg2))\n"
+        "            result += arg1/(pow((rate+1),(arg2-dateNull)/365));\n"
+        );
+    ss << "    return result;\n";
+    ss << "}";
 }
 
 void PriceMat::BinInlineFun(std::set<std::string>& decls,
@@ -709,13 +522,13 @@ void OpSYD::GenSlidingWindowFunction(outputstream &ss,
     ss <<"}\n";
 }
 
-void MIRR::GenSlidingWindowFunction(
+void OpMIRR::GenSlidingWindowFunction(
     outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments)
 {
     CHECK_PARAMETER_COUNT( 3, 3 );
     GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
     ss << "{\n\t";
-    ss << "double tmp = " << GetBottom() <<";\n\t";
+    ss << "double tmp;\n\t";
     ss << "int gid0 = get_global_id(0);\n\t";
     GenerateArg( 1, vSubArguments, ss );
     GenerateArg( 2, vSubArguments, ss );
@@ -2035,105 +1848,58 @@ void OpXirr::GenSlidingWindowFunction(outputstream &ss,
              const std::string &sSymName, SubArguments &vSubArguments)
 {
     CHECK_PARAMETER_COUNT( 2, 3 );
-    FormulaToken *tmpCur = vSubArguments[0]->GetFormulaToken();
-    const formula::DoubleVectorRefToken*pCurDVR= static_cast<const
-         formula::DoubleVectorRefToken *>(tmpCur);
-    size_t nCurWindowSize = pCurDVR->GetArrayLength() <
-    pCurDVR->GetRefRowSize() ? pCurDVR->GetArrayLength():
-    pCurDVR->GetRefRowSize() ;
     GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
     ss << "{\n";
     ss << "    int gid0 = get_global_id(0);\n";
-    ss << "    int doubleIndex = gid0;\n";
-    ss << "    int singleIndex = gid0;\n";
-    ss << "    double result = 0;\n";
-    ss << "    int i=0;\n";
-    GenTmpVariables(ss,vSubArguments);
-    if(vSubArguments.size() == 2)
-    {
-        ss << "    double tmp2  = 0.1;\n";
-    }
-    else
-    {
-        CheckSubArgumentIsNan(ss,vSubArguments,2);
-    }
-    ss << "    if(tmp2<=-1)\n";
-    ss << "        result = -DBL_MAX;\n";
-    ss << "    else\n";
+    GenerateArgWithDefault( "fResultRate", 2, 0.1, vSubArguments, ss );
+    ss << "    if(fResultRate<=-1)\n";
+    ss << "        return CreateDoubleError(IllegalArgument);\n";
+    ss << "    double fMaxEps = 1e-10;\n";
+    ss << "    int nMaxIter = 50;\n";
+    ss << "    int nIter = 0;\n";
+    ss << "    double fResultValue;\n";
+    ss << "    int nIterScan = 0;\n";
+    ss << "    bool bContLoop = false;\n";
+    ss << "    bool bResultRateScanEnd = false;\n";
+    // Make 'V_0' and 'D_0' be the first elements of arguments 0 and 1.
+    GenerateRangeArgElement( "V_0", 0, "0", vSubArguments, ss );
+    GenerateRangeArgElement( "D_0", 1, "0", vSubArguments, ss );
+    ss << "    do\n";
     ss << "    {\n";
-    ss << "        double fMaxEps = 1e-10;\n";
-    ss << "        int nMaxIter = 50;\n";
-    ss << "        double fNewRate, fRateEps, fResultValue, fResultValue2;\n";
-    ss << "        int nIter = 0;\n";
-    ss << "        int bContLoop;\n";
-    ss << "        int windowsSize = ";
-    ss << nCurWindowSize;
-    ss << ";\n";
-    CheckSubArgumentIsNan(ss,vSubArguments,0);
-    CheckSubArgumentIsNan(ss,vSubArguments,1);
-    ss << "        double D_0 = tmp1;\n";
-    ss << "        double V_0 = tmp0;\n";
-    ss << "        double fResultRate = tmp2;\n";
-    ss << "        double r;\n";
-    ss << "        double fResult;\n";
+    ss << "        if (nIterScan >=1)\n";
+    ss << "            fResultRate = -0.99 + (nIterScan -1)* 0.01;\n";
     ss << "        do\n";
     ss << "        {\n";
+    ss << "            double r = fResultRate + 1;\n";
     ss << "            fResultValue = V_0;\n";
-    ss << "            r = fResultRate + 1;\n";
-    ss << "            for (i = ";
-    if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed()) {
-       ss << "gid0+1; i < "<< nCurWindowSize <<"; i++)\n";
-    } else if (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) {
-       ss << "1; i < gid0+"<< nCurWindowSize <<"; i++)\n";
-    } else {
-       ss << "1; i < "<< nCurWindowSize <<"; i++)\n";
-    }
-    ss << "            {\n";
-    if(!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
-    {
-       ss<< "                doubleIndex =i+gid0;\n";
-    }else
-    {
-       ss<< "                doubleIndex =i;\n";
-    }
-    CheckSubArgumentIsNan(ss,vSubArguments,0);
-    CheckSubArgumentIsNan(ss,vSubArguments,1);
-    ss << "                fResultValue += tmp0/pow(r,(tmp1 - D_0)/365.0);\n";
-    ss << "            }\n";
-    ss << "            fResultValue2 = 0;\n";
-
-    ss << "            for (i = ";
-    if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed()) {
-       ss << "gid0+1; i < "<< nCurWindowSize <<"; i++)\n";
-    } else if (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed()) {
-       ss << "1; i < gid0+"<< nCurWindowSize <<"; i++)\n";
-    } else {
-       ss << "1; i < "<< nCurWindowSize <<"; i++)\n";
-    }
-    ss << "            {\n";
-    if(!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
-    {
-       ss<< "                doubleIndex =i+gid0;\n";
-    }else
-    {
-       ss<< "                doubleIndex =i;\n";
-    }
-    CheckSubArgumentIsNan(ss,vSubArguments,0);
-    CheckSubArgumentIsNan(ss,vSubArguments,1);
-    ss << "                double E_i = (tmp1 - D_0)/365.0;\n";
-    ss << "                fResultValue2 -= E_i * tmp0 / pow(r,E_i + 1.0);\n";
-    ss << "            }\n";
-    ss << "            fNewRate = fResultRate - fResultValue / 
fResultValue2;\n";
-    ss << "            fRateEps = fabs( fNewRate - fResultRate );\n";
+    GenerateRangeArgPair( 0, 1, vSubArguments, ss,
+        "                if(!isnan(arg1) && !isnan(arg2))\n"
+        "                    fResultValue += arg1/pow(r,(arg2 - D_0)/365.0);\n"
+        , "1" // start from 2nd element
+        );
+    ss << "            double fResultValue2 = 0;\n";
+    GenerateRangeArgPair( 0, 1, vSubArguments, ss,
+        "                if(!isnan(arg1) && !isnan(arg2))\n"
+        "                {\n"
+        "                    double E_i = (arg2 - D_0)/365.0;\n"
+        "                    fResultValue2 -= E_i * arg1 / pow(r,E_i + 1.0);\n"
+        "                }\n"
+        , "1" // start from 2nd element
+        );
+    ss << "            double fNewRate = fResultRate - fResultValue / 
fResultValue2;\n";
+    ss << "            double fRateEps = fabs( fNewRate - fResultRate );\n";
     ss << "            fResultRate = fNewRate;\n";
     ss << "            bContLoop = (fRateEps > fMaxEps) && (fabs( fResultValue 
) > fMaxEps);\n";
-    ss << "        }\n";
-    ss << "        while( bContLoop && (++nIter < nMaxIter) );\n";
-    ss << "        if( bContLoop )\n";
-    ss << "            result = -DBL_MAX;\n";
-    ss << "        result = fResultRate;\n";
-    ss << "    }\n";
-    ss << "    return result;\n";
+    ss << "        } while( bContLoop && (++nIter < nMaxIter) );\n";
+    ss << "        nIter = 0;\n";
+    ss << "        if( isnan(fResultRate) || isinf(fResultRate) || 
isnan(fResultValue) || isinf(fResultValue))\n";
+    ss << "            bContLoop = true;\n";
+    ss << "        ++nIterScan;\n";
+    ss << "        bResultRateScanEnd = (nIterScan >= 200);\n";
+    ss << "    } while(bContLoop && !bResultRateScanEnd);\n";
+    ss << "    if( bContLoop )\n";
+    ss << "        return CreateDoubleError(IllegalArgument);\n";
+    ss << "    return fResultRate;\n";
     ss << "}";
 }
 
diff --git a/sc/source/core/opencl/op_financial.hxx 
b/sc/source/core/opencl/op_financial.hxx
index 92f27430d513..718cd6dd22ec 100644
--- a/sc/source/core/opencl/op_financial.hxx
+++ b/sc/source/core/opencl/op_financial.hxx
@@ -14,19 +14,11 @@
 
 namespace sc::opencl {
 
-class RRI: public SlidingFunctionBase
+class OpRRI: public Normal
 {
 public:
     virtual void GenSlidingWindowFunction(outputstream &ss,
             const std::string &sSymName, SubArguments &vSubArguments) override;
-    virtual bool takeString() const override { return false; }
-    virtual bool takeNumeric() const override { return true; }
-};
-
-class OpRRI:public RRI
-{
-public:
-    virtual std::string GetBottom() override { return "0"; }
     virtual std::string BinFuncName() const override { return "RRI"; }
 };
 
@@ -179,18 +171,29 @@ public:
     virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) 
override;
 };
 
-class IRR: public Normal
+class OpIRR: public Normal
 {
 public:
     virtual void GenSlidingWindowFunction(outputstream &ss,
             const std::string &sSymName, SubArguments &vSubArguments) override;
+    virtual std::string BinFuncName() const override { return "IRR"; }
 };
 
-class OpIRR: public IRR
+class OpMIRR: public Normal
 {
 public:
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string BinFuncName() const override { return "IRR"; }
+    virtual void GenSlidingWindowFunction(outputstream &ss,
+            const std::string &sSymName, SubArguments &vSubArguments) override;
+    virtual bool canHandleMultiVector() const override { return true; }
+    virtual std::string BinFuncName() const override { return "MIRR"; }
+};
+
+class OpXirr: public Normal
+{
+public:
+    virtual void GenSlidingWindowFunction(outputstream &ss,
+            const std::string &sSymName, SubArguments &vSubArguments) override;
+    virtual std::string BinFuncName() const override { return "Xirr"; }
 };
 
 class XNPV: public Normal
@@ -216,15 +219,6 @@ public:
      virtual std::string BinFuncName() const override { return "SYD"; }
 };
 
-class MIRR: public Normal
-{
-public:
-    virtual void GenSlidingWindowFunction(outputstream &ss,
-            const std::string &sSymName, SubArguments &vSubArguments) override;
-    virtual bool canHandleMultiVector() const override { return true; }
-    virtual std::string BinFuncName() const override { return "MIRR"; }
-};
-
 class OpEffective:public Normal
 {
 public:
@@ -546,13 +540,6 @@ public:
     virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) 
override;
 };
 
-class OpMIRR: public MIRR
-{
-public:
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string BinFuncName() const override { return "MIRR"; }
-};
-
 class OpPV: public Normal
 {
 public:
@@ -571,15 +558,6 @@ public:
     virtual void BinInlineFun(std::set<std::string>& ,std::set<std::string>& ) 
override;
 };
 
-class OpXirr: public CheckVariables
-{
-public:
-    virtual void GenSlidingWindowFunction(outputstream &ss,
-            const std::string &sSymName, SubArguments &vSubArguments) override;
-
-    virtual std::string BinFuncName() const override { return "Xirr"; }
-};
-
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/opencl/op_statistical.cxx 
b/sc/source/core/opencl/op_statistical.cxx
index f4bf77715cde..c1bef2b9c612 100644
--- a/sc/source/core/opencl/op_statistical.cxx
+++ b/sc/source/core/opencl/op_statistical.cxx
@@ -1917,7 +1917,6 @@ vSubArguments)
     GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
     ss << "{\n";
     ss << "    int gid0 = get_global_id(0);\n";
-    ss << "    int singleIndex = gid0;\n";
     ss << "    double result = 0;\n";
     GenerateArg( "tmp0", 0, vSubArguments, ss );
     GenerateArg( "tmp1", 1, vSubArguments, ss );
@@ -1959,7 +1958,6 @@ vSubArguments)
     GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
     ss << "{\n";
     ss << "    int gid0 = get_global_id(0);\n";
-    ss << "    int singleIndex = gid0;\n";
     ss << "    double result = 0;\n";
     GenerateArg( "tmp0", 0, vSubArguments, ss );
     GenerateArg( "tmp1", 1, vSubArguments, ss );
diff --git a/sc/source/core/opencl/opbase.cxx b/sc/source/core/opencl/opbase.cxx
index f66dede91c59..2cb51e47d080 100644
--- a/sc/source/core/opencl/opbase.cxx
+++ b/sc/source/core/opencl/opbase.cxx
@@ -241,31 +241,7 @@ void SlidingFunctionBase::GenerateRangeArgs( int firstArg, 
int lastArg, SubArgum
             {
                 const formula::DoubleVectorRefToken* pDVR =
                     static_cast<const formula::DoubleVectorRefToken *>(token);
-                size_t nCurWindowSize = pDVR->GetRefRowSize();
-                ss << "    for (int i = ";
-                if (!pDVR->IsStartFixed() && pDVR->IsEndFixed())
-                {
-                    ss << "gid0; i < " << pDVR->GetArrayLength();
-                    ss << " && i < " << nCurWindowSize  << "; i++)\n";
-                    ss << "    {\n";
-                }
-                else if (pDVR->IsStartFixed() && !pDVR->IsEndFixed())
-                {
-                    ss << "0; i < " << pDVR->GetArrayLength();
-                    ss << " && i < gid0+" << nCurWindowSize << "; i++)\n";
-                    ss << "    {\n";
-                }
-                else if (!pDVR->IsStartFixed() && !pDVR->IsEndFixed())
-                {
-                    ss << "0; i + gid0 < " << pDVR->GetArrayLength();
-                    ss << " &&  i < " << nCurWindowSize << "; i++)\n";
-                    ss << "    {\n";
-                }
-                else
-                {
-                    ss << "0; i < " << pDVR->GetArrayLength() << "; i++)\n";
-                    ss << "    {\n";
-                }
+                GenerateDoubleVectorLoopHeader( ss, pDVR, nullptr );
                 ss << "        double arg = ";
                 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
                 ss << ";\n";
@@ -315,7 +291,7 @@ void SlidingFunctionBase::GenerateRangeArg( int arg, 
SubArguments& vSubArguments
 }
 
 void SlidingFunctionBase::GenerateRangeArgPair( int arg1, int arg2, 
SubArguments& vSubArguments,
-    outputstream& ss, const char* code )
+    outputstream& ss, const char* code, const char* firstElementDiff )
 {
     assert( arg1 >= 0 && arg1 < int (vSubArguments.size()));
     assert( arg2 >= 0 && arg2 < int (vSubArguments.size()));
@@ -347,37 +323,71 @@ void SlidingFunctionBase::GenerateRangeArgPair( int arg1, 
int arg2, SubArguments
         throw Unhandled( __FILE__, __LINE__ );
     }
 
-    size_t arrayLength = std::min( pDVR1->GetArrayLength(), 
pDVR2->GetArrayLength());
+    GenerateDoubleVectorLoopHeader( ss,
+        pDVR1->GetArrayLength() < pDVR2->GetArrayLength() ? pDVR1 : pDVR2,
+        firstElementDiff );
+    ss << "        double arg1 = ";
+    ss << vSubArguments[arg1]->GenSlidingWindowDeclRef(true) << ";\n";
+    ss << "        double arg2 = ";
+    ss << vSubArguments[arg2]->GenSlidingWindowDeclRef(true) << ";\n";
+    ss << code;
+    ss << "    }\n";
+}
+
+void SlidingFunctionBase::GenerateRangeArgElement( const char* name, int arg, 
const char* element,
+    SubArguments& vSubArguments, outputstream& ss )
+{
+    assert( arg >= 0 && arg < int (vSubArguments.size()));
+    FormulaToken *token = vSubArguments[arg]->GetFormulaToken();
+    if( token == nullptr )
+        throw Unhandled( __FILE__, __LINE__ );
+    if(token->GetType() != formula::svDoubleVectorRef)
+        throw Unhandled( __FILE__, __LINE__ );
+    const formula::DoubleVectorRefToken* pDVR =
+        static_cast<const formula::DoubleVectorRefToken *>(token);
+    ss << "    double " << name << " = NAN;\n";
+    ss << "    {\n";
+    // GenSlidingWindowDeclRef() may refer to 'i' variable.
+    ss << "        int i = 0;\n";
+    ss << "        if( ";
+    if( !pDVR->IsStartFixed())
+        ss << "gid0 + ";
+    ss << element << " < " << pDVR->GetArrayLength() << " )\n";
+    ss << "            " << name << " = " << 
vSubArguments[arg]->GenSlidingWindowDeclRef(true) << ";\n";
+    ss << "    }\n";
+}
+
+void SlidingFunctionBase::GenerateDoubleVectorLoopHeader( outputstream& ss,
+    const formula::DoubleVectorRefToken* pDVR, const char* firstElementDiff )
+{
+    size_t nCurWindowSize = pDVR->GetRefRowSize();
+    std::string startDiff;
+    if( firstElementDiff )
+        startDiff = std::string( " + " ) + firstElementDiff;
     ss << "    for (int i = ";
-    if (!pDVR1->IsStartFixed() && pDVR1->IsEndFixed())
+    if (!pDVR->IsStartFixed() && pDVR->IsEndFixed())
     {
-        ss << "gid0; i < " << arrayLength;
-        ss << " && i < " << nCurWindowSize1  << "; i++)\n";
+        ss << "gid0" << startDiff << "; i < " << pDVR->GetArrayLength();
+        ss << " && i < " << nCurWindowSize  << "; i++)\n";
         ss << "    {\n";
     }
-    else if (pDVR1->IsStartFixed() && !pDVR1->IsEndFixed())
+    else if (pDVR->IsStartFixed() && !pDVR->IsEndFixed())
     {
-        ss << "0; i < " << arrayLength;
-        ss << " && i < gid0+"<< nCurWindowSize1 << "; i++)\n";
+        ss << "0" << startDiff << "; i < " << pDVR->GetArrayLength();
+        ss << " && i < gid0+" << nCurWindowSize << "; i++)\n";
         ss << "    {\n";
     }
-    else if (!pDVR1->IsStartFixed() && !pDVR1->IsEndFixed())
+    else if (!pDVR->IsStartFixed() && !pDVR->IsEndFixed())
     {
-        ss << "0; i + gid0 < " << arrayLength;
-        ss << " &&  i < " << nCurWindowSize1 << "; i++)\n";
+        ss << "0" << startDiff << "; i + gid0 < " << pDVR->GetArrayLength();
+        ss << " &&  i < " << nCurWindowSize << "; i++)\n";
         ss << "    {\n";
     }
     else
     {
-        ss << "0; i < " << nCurWindowSize1 << "; i++)\n";
+        ss << "0" << startDiff << "; i < " << pDVR->GetArrayLength() << "; 
i++)\n";
         ss << "    {\n";
     }
-    ss << "        double arg1 = ";
-    ss << vSubArguments[arg1]->GenSlidingWindowDeclRef(true) << ";\n";
-    ss << "        double arg2 = ";
-    ss << vSubArguments[arg2]->GenSlidingWindowDeclRef(true) << ";\n";
-    ss << code;
-    ss << "    }\n";
 }
 
 void SlidingFunctionBase::GenerateFunctionDeclaration( const std::string& 
sSymName,
diff --git a/sc/source/core/opencl/opbase.hxx b/sc/source/core/opencl/opbase.hxx
index 9ad6e7480cf0..ee55d72c45b6 100644
--- a/sc/source/core/opencl/opbase.hxx
+++ b/sc/source/core/opencl/opbase.hxx
@@ -279,11 +279,24 @@ protected:
     static void GenerateRangeArgs( SubArguments& vSubArguments, outputstream& 
ss, const char* code );
     // overload, handle the given argument
     static void GenerateRangeArg( int arg, SubArguments& vSubArguments, 
outputstream& ss, const char* code );
+    // Overload.
+    // Both arguments must be svDoubleRef of the same size.
+    // If 'firstElementDiff' is set, the loop start will be offset by '+ 
firstElementDiff'.
+    static void GenerateRangeArg( int arg1, int arg2, SubArguments& 
vSubArguments,
+        outputstream& ss, const char* code, const char* firstElementDiff = 
nullptr );
     // Generate code that will handle the given two arguments in one loop 
where n-th element of arg1 and arg2
     // will be handled at the same time, named 'arg1' and 'arg2'.
     // Both arguments must be svDoubleRef of the same size.
+    // If 'firstElementDiff' is set, the loop start will be offset by '+ 
firstElementDiff'.
     static void GenerateRangeArgPair( int arg1, int arg2, SubArguments& 
vSubArguments,
-        outputstream& ss, const char* code );
+        outputstream& ss, const char* code, const char* firstElementDiff = 
nullptr );
+    // Generate code for "double <name> = range[<element>]" from vSubArguments.
+    // The argument must be svDoubleRef.
+    // There is no isnan(arg) checking.
+    static void GenerateRangeArgElement( const char* name, int arg, const 
char* element,
+        SubArguments& vSubArguments, outputstream& ss );
+    static void GenerateDoubleVectorLoopHeader( outputstream& ss,
+        const formula::DoubleVectorRefToken* pDVR, const char* 
firstElementDiff );
 };
 
 class Normal : public SlidingFunctionBase

Reply via email to