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