diff options
-rw-r--r-- | formula/inc/core_resource.hrc | 6 | ||||
-rw-r--r-- | formula/source/core/api/FormulaCompiler.cxx | 1 | ||||
-rw-r--r-- | include/formula/compiler.hxx | 3 | ||||
-rw-r--r-- | include/formula/opcode.hxx | 2 | ||||
-rw-r--r-- | sc/inc/helpids.h | 1 | ||||
-rw-r--r-- | sc/inc/scfuncs.hrc | 14 | ||||
-rw-r--r-- | sc/qa/extras/scfunctionlistobj.cxx | 2 | ||||
-rw-r--r-- | sc/qa/unit/ucalc.cxx | 1 | ||||
-rw-r--r-- | sc/source/core/data/funcdesc.cxx | 3 | ||||
-rw-r--r-- | sc/source/core/inc/interpre.hxx | 1 | ||||
-rw-r--r-- | sc/source/core/tool/interpr3.cxx | 297 | ||||
-rw-r--r-- | sc/source/core/tool/interpr4.cxx | 1 | ||||
-rw-r--r-- | sc/source/core/tool/parclass.cxx | 1 | ||||
-rw-r--r-- | sc/source/filter/excel/xlformula.cxx | 3 | ||||
-rw-r--r-- | sc/source/filter/oox/formulabase.cxx | 3 |
15 files changed, 334 insertions, 5 deletions
diff --git a/formula/inc/core_resource.hrc b/formula/inc/core_resource.hrc index 9d97fd771d9e..cd2baa334b52 100644 --- a/formula/inc/core_resource.hrc +++ b/formula/inc/core_resource.hrc @@ -466,6 +466,7 @@ const std::pair<const char*, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF[] = { "ORG.LIBREOFFICE.RAWSUBTRACT" , SC_OPCODE_RAWSUBTRACT }, { "ORG.LIBREOFFICE.ROUNDSIG" , SC_OPCODE_ROUNDSIG }, { "ORG.LIBREOFFICE.REGEX" , SC_OPCODE_REGEX }, + { "ORG.LIBREOFFICE.FOURIER", SC_OPCODE_FOURIER }, { nullptr, -1 } }; @@ -909,6 +910,7 @@ const std::pair<const char*, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML[] = { "_xlfn.ORG.LIBREOFFICE.RAWSUBTRACT" , SC_OPCODE_RAWSUBTRACT }, { "_xlfn.ORG.LIBREOFFICE.ROUNDSIG" , SC_OPCODE_ROUNDSIG }, { "_xlfn.ORG.LIBREOFFICE.REGEX" , SC_OPCODE_REGEX }, + { "_xlfn.ORG.LIBREOFFICE.FOURIER", SC_OPCODE_FOURIER }, { nullptr, -1 } }; @@ -1357,6 +1359,7 @@ const std::pair<const char*, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_PODF[] = { "RAWSUBTRACT" , SC_OPCODE_RAWSUBTRACT }, { "ROUNDSIG" , SC_OPCODE_ROUNDSIG }, { "REGEX" , SC_OPCODE_REGEX }, + { "FOURIER", SC_OPCODE_FOURIER }, { nullptr, -1 } }; @@ -1804,6 +1807,7 @@ const std::pair<const char*, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_API[] = { "RAWSUBTRACT" , SC_OPCODE_RAWSUBTRACT }, { "ROUNDSIG" , SC_OPCODE_ROUNDSIG }, { "REGEX" , SC_OPCODE_REGEX }, + { "FOURIER", SC_OPCODE_FOURIER }, { nullptr, -1 } }; @@ -2250,6 +2254,7 @@ const std::pair<const char*, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH[] = { "RAWSUBTRACT" , SC_OPCODE_RAWSUBTRACT }, { "ROUNDSIG" , SC_OPCODE_ROUNDSIG }, { "REGEX" , SC_OPCODE_REGEX }, + { "FOURIER", SC_OPCODE_FOURIER }, { nullptr, -1 } }; @@ -2680,6 +2685,7 @@ const std::pair<const char*, int> RID_STRLIST_FUNCTION_NAMES[] = { NC_("RID_STRLIST_FUNCTION_NAMES", "FINDB") , SC_OPCODE_FINDB }, { NC_("RID_STRLIST_FUNCTION_NAMES", "SEARCHB") , SC_OPCODE_SEARCHB }, { NC_("RID_STRLIST_FUNCTION_NAMES", "REGEX") , SC_OPCODE_REGEX }, + { NC_("RID_STRLIST_FUNCTION_NAMES", "FOURIER"), SC_OPCODE_FOURIER }, { nullptr, -1 } }; diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx index f243aab357f7..930774023ace 100644 --- a/formula/source/core/api/FormulaCompiler.cxx +++ b/formula/source/core/api/FormulaCompiler.cxx @@ -1051,6 +1051,7 @@ bool FormulaCompiler::IsMatrixFunction( OpCode eOpCode ) case ocMatInv : case ocMatrixUnit : case ocModalValue_Multi : + case ocFourier : return true; default: { diff --git a/include/formula/compiler.hxx b/include/formula/compiler.hxx index 09a507fc3d68..c5e5cfdf0da2 100644 --- a/include/formula/compiler.hxx +++ b/include/formula/compiler.hxx @@ -506,7 +506,8 @@ #define SC_OPCODE_FINDB 495 #define SC_OPCODE_SEARCHB 496 #define SC_OPCODE_REGEX 497 -#define SC_OPCODE_STOP_2_PAR 498 /* last function with two or more parameters' OpCode + 1 */ +#define SC_OPCODE_FOURIER 498 +#define SC_OPCODE_STOP_2_PAR 499 /* last function with two or more parameters' OpCode + 1 */ #define SC_OPCODE_STOP_FUNCTION SC_OPCODE_STOP_2_PAR /* last function's OpCode + 1 */ #define SC_OPCODE_LAST_OPCODE_ID (SC_OPCODE_STOP_FUNCTION - 1) /* last OpCode */ diff --git a/include/formula/opcode.hxx b/include/formula/opcode.hxx index d2c6548e286f..b969a0047007 100644 --- a/include/formula/opcode.hxx +++ b/include/formula/opcode.hxx @@ -500,6 +500,7 @@ enum OpCode : sal_uInt16 ocErf_MS = SC_OPCODE_ERF_MS, ocErfc_MS = SC_OPCODE_ERFC_MS, ocEncodeURL = SC_OPCODE_ENCODEURL, + ocFourier = SC_OPCODE_FOURIER, // internal stuff ocInternalBegin = SC_OPCODE_INTERNAL_BEGIN, ocTTT = SC_OPCODE_TTT, @@ -972,6 +973,7 @@ inline std::string OpCodeEnumToString(OpCode eCode) case ocErf_MS: return "Erf_MS"; case ocErfc_MS: return "Erfc_MS"; case ocEncodeURL: return "EncodeURL"; + case ocFourier: return "Fourier"; case ocTTT: return "TTT"; case ocDebugVar: return "DebugVar"; case ocDataToken1: return "DataToken1"; diff --git a/sc/inc/helpids.h b/sc/inc/helpids.h index 283057e3ccce..d6616f106784 100644 --- a/sc/inc/helpids.h +++ b/sc/inc/helpids.h @@ -578,6 +578,7 @@ #define HID_FUNC_FINDB "SC_HID_FUNC_FINDB" #define HID_FUNC_SEARCHB "SC_HID_FUNC_SEARCHB" #define HID_FUNC_REGEX "SC_HID_FUNC_REGEX" +#define HID_FUNC_FOURIER "SC_HID_FUNC_FOURIER" #endif diff --git a/sc/inc/scfuncs.hrc b/sc/inc/scfuncs.hrc index c08df5adc072..c4a050a4c334 100644 --- a/sc/inc/scfuncs.hrc +++ b/sc/inc/scfuncs.hrc @@ -4118,6 +4118,20 @@ const char* SC_OPCODE_SEARCHB_ARY[] = NC_("SC_OPCODE_SEARCHB", "The position in the text from which the search starts.") }; +// -=*# Resource for function FOURIER #*=- +const char* SC_OPCODE_FOURIER_ARY[] = +{ + NC_("SC_OPCODE_FOURIER", "Computes the Discrete Fourier Transform (DFT) of an array"), + NC_("SC_OPCODE_FOURIER", "Array"), + NC_("SC_OPCODE_FOURIER", "The array whose DFT needs to be computed. The dimensions of this array can be Nx1 or Nx2 or 1xN or 2xN."), + NC_("SC_OPCODE_FOURIER", "GroupedByColumns"), + NC_("SC_OPCODE_FOURIER", "Flag to indicate whether the array is grouped by columns or not (default TRUE)."), + NC_("SC_OPCODE_FOURIER", "Inverse"), + NC_("SC_OPCODE_FOURIER", "Flag to indicate whether an inverse DFT is to be computed (default FALSE)."), + NC_("SC_OPCODE_FOURIER", "Polar"), + NC_("SC_OPCODE_FOURIER", "Flag to indicate whether to return the results in polar form (default FALSE).") +}; + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/qa/extras/scfunctionlistobj.cxx b/sc/qa/extras/scfunctionlistobj.cxx index 0ce8953ecc21..cf8c962bfb06 100644 --- a/sc/qa/extras/scfunctionlistobj.cxx +++ b/sc/qa/extras/scfunctionlistobj.cxx @@ -82,7 +82,7 @@ private: ScFunctionListObj::ScFunctionListObj() : CalcUnoApiTest("/sc/qa/extras/testdocuments") , XElementAccess(cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get()) - , XIndexAccess(392) + , XIndexAccess(393) , XNameAccess("IF") , XServiceInfo("stardiv.StarCalc.ScFunctionListObj", "com.sun.star.sheet.FunctionDescriptions") { diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index bfb780a8e172..f1a594912eec 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -2423,6 +2423,7 @@ void Test::testFunctionLists() }; const char* aArray[] = { + "FOURIER", "FREQUENCY", "GROWTH", "LINEST", diff --git a/sc/source/core/data/funcdesc.cxx b/sc/source/core/data/funcdesc.cxx index 15a2e22d8811..a5cc499e44df 100644 --- a/sc/source/core/data/funcdesc.cxx +++ b/sc/source/core/data/funcdesc.cxx @@ -787,7 +787,8 @@ ScFunctionList::ScFunctionList() { SC_OPCODE_REPLACEB, ENTRY(SC_OPCODE_REPLACEB_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_REPLACEB, 4, { 0, 0, 0, 0 } }, { SC_OPCODE_FINDB, ENTRY(SC_OPCODE_FINDB_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_FINDB, 3, { 0, 0, 1 } }, { SC_OPCODE_SEARCHB, ENTRY(SC_OPCODE_SEARCHB_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_SEARCHB, 3, { 0, 0, 1 } }, - { SC_OPCODE_REGEX, ENTRY(SC_OPCODE_REGEX_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_REGEX, 4, { 0, 0, 1, 1 } } + { SC_OPCODE_REGEX, ENTRY(SC_OPCODE_REGEX_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_REGEX, 4, { 0, 0, 1, 1 } }, + { SC_OPCODE_FOURIER, ENTRY(SC_OPCODE_FOURIER_ARY), 0, ID_FUNCTION_GRP_MATRIX, HID_FUNC_FOURIER, 4, { 0, 0, 1, 1 } } }; ScFuncDesc* pDesc = nullptr; diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx index b6c68dcdb264..4f76af346d63 100644 --- a/sc/source/core/inc/interpre.hxx +++ b/sc/source/core/inc/interpre.hxx @@ -857,6 +857,7 @@ private: void ScLogest(); void ScForecast(); void ScForecast_Ets( ScETSType eETSType ); + void ScFourier(); void ScNoName(); void ScBadName(); // Statistics: diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx index 1015d8cfc78a..e568e4f96367 100644 --- a/sc/source/core/tool/interpr3.cxx +++ b/sc/source/core/tool/interpr3.cxx @@ -4721,4 +4721,301 @@ void ScInterpreter::ScForecast() } } +static void lcl_roundUpNearestPow2(SCSIZE& nNum, SCSIZE& nNumBits) +{ + // Find the least power of 2 that is less than or equal to nNum. + SCSIZE nPow2(1); + nNumBits = std::numeric_limits<SCSIZE>::digits; + nPow2 <<= (nNumBits - 1); + while (nPow2 >= 1) + { + if (nNum & nPow2) + break; + + --nNumBits; + nPow2 >>= 1; + } + + if (nPow2 != nNum) + nNum = nPow2 ? (nPow2 << 1) : 1; + else + --nNumBits; +} + +static SCSIZE lcl_bitReverse(SCSIZE nIn, SCSIZE nBound) +{ + SCSIZE nOut = 0; + for (SCSIZE nMask = 1; nMask < nBound; nMask <<= 1) + { + nOut <<= 1; + + if (nIn & nMask) + nOut |= 1; + } + + return nOut; +} + +class ScFFT2 +{ +public: + ScFFT2(ScMatrixRef& pMat, SCSIZE nPoints, bool bRealInput, bool bInverse, bool bPolar) : + mpMat(pMat), + mnPoints(nPoints), + mnStages(0), + mbRealInput(bRealInput), + mbInverse(bInverse), + mbPolar(bPolar) + {} + + void Compute(); +private: + + void prepare(); + void computeTFactors(); + void normalize(); + void convertToPolar(); + + double getReal(SCSIZE nIdx) + { + return mpMat->GetDouble(0, nIdx); + } + + void setReal(double fVal, SCSIZE nIdx) + { + mpMat->PutDouble(fVal, 0, nIdx); + } + + double getImag(SCSIZE nIdx) + { + return mpMat->GetDouble(1, nIdx); + } + + void setImag(double fVal, SCSIZE nIdx) + { + mpMat->PutDouble(fVal, 1, nIdx); + } + + SCSIZE getTFactorIndex(SCSIZE nPtIndex, SCSIZE nTfIdxScale) + { + return ( ( nPtIndex * nTfIdxScale ) & ( mnPoints - 1 ) ); // (x & (N-1)) is same as (x % N) but faster. + } + + void computeFly(SCSIZE nTopIdx, SCSIZE nBottomIdx, SCSIZE nWIdx1, SCSIZE nWIdx2, SCSIZE nStage) + { + const double x1r = getReal(nTopIdx); + + const double& w1r = mfWReal[nWIdx1]; + const double& w1i = mfWImag[nWIdx1]; + + const double x2r = getReal(nBottomIdx); + + const double& w2r = mfWReal[nWIdx2]; + const double& w2i = mfWImag[nWIdx2]; + + // Optimization for real input in stage #0 + if (nStage == 0 && mbRealInput) + { + setReal(x1r + x2r*w1r, nTopIdx); + setImag(x2r*w1i, nTopIdx); + + setReal(x1r + x2r*w2r, nBottomIdx); + setImag(x2r*w2i, nBottomIdx); + + return; + } + + const double x1i = getImag(nTopIdx); + const double x2i = getImag(nBottomIdx); + + setReal(x1r + x2r*w1r - x2i*w1i, nTopIdx); + setImag(x1i + x2i*w1r + x2r*w1i, nTopIdx); + + setReal(x1r + x2r*w2r - x2i*w2i, nBottomIdx); + setImag(x1i + x2i*w2r + x2r*w2i, nBottomIdx); + } + + ScMatrixRef& mpMat; + std::vector<double> mfWReal; + std::vector<double> mfWImag; + SCSIZE mnPoints; + SCSIZE mnStages; + bool mbRealInput:1; + bool mbInverse:1; + bool mbPolar:1; +}; + +void ScFFT2::prepare() +{ + lcl_roundUpNearestPow2(mnPoints, mnStages); + + mpMat->Resize(2, mnPoints, 0.0); + + // Reorder array by bit-reversed indices. + for (SCSIZE nIdx = 0; nIdx < mnPoints; ++nIdx) + { + SCSIZE nRevIdx = lcl_bitReverse(nIdx, mnPoints); + if (nIdx < nRevIdx) + { + double fTmp = getReal(nIdx); + setReal(getReal(nRevIdx), nIdx); + setReal(fTmp, nRevIdx); + + if (!mbRealInput) + { + fTmp = getImag(nIdx); + setImag(getImag(nRevIdx), nIdx); + setImag(fTmp, nRevIdx); + } + } + } +} + +void ScFFT2::computeTFactors() +{ + mfWReal.resize(mnPoints); + mfWImag.resize(mnPoints); + + double nW = -2.0*F_PI/static_cast<double>(mnPoints); + if (mbInverse) + nW = -nW; + + for (SCSIZE nIdx = 0; nIdx < mnPoints; ++nIdx) + { + mfWReal[nIdx] = cos(nW*static_cast<double>(nIdx)); + mfWImag[nIdx] = sin(nW*static_cast<double>(nIdx)); + } +} + +void ScFFT2::normalize() +{ + const double fScale = 1.0/static_cast<double>(mnPoints); + + for (SCSIZE nIdx = 0; nIdx < mnPoints; ++nIdx) + setReal(getReal(nIdx)*fScale, nIdx); + + // If already in polar coordinates, we should only scale the magnitude part + // which is stored where "real" part was stored before. + if (!mbPolar) + for (SCSIZE nIdx = 0; nIdx < mnPoints; ++nIdx) + setImag(getImag(nIdx)*fScale, nIdx); +} + +void ScFFT2::convertToPolar() +{ + double fMag, fPhase, fR, fI; + for (SCSIZE nIdx = 0; nIdx < mnPoints; ++nIdx) + { + fR = getReal(nIdx); + fI = getImag(nIdx); + fPhase = atan(fI/fR); + fMag = sqrt(fR*fR + fI*fI); + + setReal(fMag, nIdx); + setImag(fPhase, nIdx); + } +} + +void ScFFT2::Compute() +{ + prepare(); + computeTFactors(); + + const SCSIZE nFliesInStage = mnPoints/2; + for (SCSIZE nStage = 0; nStage < mnStages; ++nStage) + { + const SCSIZE nTFIdxScale = (1 << (mnStages-nStage-1)); // Twiddle factor index's scale factor. + const SCSIZE nFliesInGroup = 1<<nStage; + const SCSIZE nGroups = nFliesInStage/nFliesInGroup; + const SCSIZE nFlyWidth = nFliesInGroup; + for (SCSIZE nGroup = 0, nFlyTopIdx = 0; nGroup < nGroups; ++nGroup) + { + for (SCSIZE nFly = 0; nFly < nFliesInGroup; ++nFly, ++nFlyTopIdx) + { + SCSIZE nFlyBottomIdx = nFlyTopIdx + nFlyWidth; + SCSIZE nWIdx1 = getTFactorIndex(nFlyTopIdx, nTFIdxScale); + SCSIZE nWIdx2 = getTFactorIndex(nFlyBottomIdx, nTFIdxScale); + + computeFly(nFlyTopIdx, nFlyBottomIdx, nWIdx1, nWIdx2, nStage); + } + + nFlyTopIdx += nFlyWidth; + } + } + + if (mbPolar) + convertToPolar(); + + // Normalize after converting to polar, so we have a chance to + // save O(mnPoints) flops. + if (mbInverse) + normalize(); +} + +void ScInterpreter::ScFourier() +{ + sal_uInt8 nParamCount = GetByte(); + if ( !MustHaveParamCount( nParamCount, 2, 4 ) ) + return; + + bool bInverse = false; + bool bPolar = false; + + if (nParamCount == 4) + bPolar = GetBool(); + + if (nParamCount > 2) + { + if (IsMissing()) + Pop(); + else + bInverse = GetBool(); + } + + bool bGroupedByColumn = GetBool(); + + ScMatrixRef pInputMat = GetMatrix(); + if (!pInputMat) + { + PushIllegalParameter(); + return; + } + + SCSIZE nC, nR; + pInputMat->GetDimensions(nC, nR); + + if ((bGroupedByColumn && nC > 2) || (!bGroupedByColumn && nR > 2)) + { + // There can be no more than 2 columns (real, imaginary) if data grouped by columns. + // and no more than 2 rows if data is grouped by rows. + PushIllegalArgument(); + return; + } + + if (!pInputMat->IsNumeric()) + { + PushNoValue(); + return; + } + + SCSIZE nNumPoints; + bool bRealInput = true; + if (!bGroupedByColumn) + { + pInputMat->MatTrans(*pInputMat); + nNumPoints = nC; + bRealInput = (nR == 1); + } + else + { + nNumPoints = nR; + bRealInput = (nC == 1); + } + + ScFFT2 aFFT2(pInputMat, nNumPoints, bRealInput, bInverse, bPolar); + aFFT2.Compute(); + + PushMatrix(pInputMat); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index 5c2cd6e97cb7..238edf4eba9b 100644 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -4357,6 +4357,7 @@ StackVar ScInterpreter::Interpret() case ocBetaDist_MS : ScBetaDist_MS(); break; case ocBetaInv : case ocBetaInv_MS : ScBetaInv(); break; + case ocFourier : ScFourier(); break; case ocExternal : ScExternal(); break; case ocTableOp : ScTableOp(); break; case ocStop : break; diff --git a/sc/source/core/tool/parclass.cxx b/sc/source/core/tool/parclass.cxx index ce6c9094cc71..7e2cd6eacd9f 100644 --- a/sc/source/core/tool/parclass.cxx +++ b/sc/source/core/tool/parclass.cxx @@ -146,6 +146,7 @@ const ScParameterClassification::RawData ScParameterClassification::pRawData[] = { ocForecast_ETS_STA, {{ ForceArray, ForceArray, ForceArray, Value, Value, Value }, 0, Value }}, { ocForecast_ETS_STM, {{ ForceArray, ForceArray, ForceArray, Value, Value, Value }, 0, Value }}, { ocFormula, {{ Reference }, 0, Value }}, + { ocFourier, {{ ForceArray, Value, Value, Value }, 0, Value }}, { ocFrequency, {{ ReferenceOrForceArray, ReferenceOrForceArray }, 0, ForceArrayReturn }}, { ocGCD, {{ Reference }, 1, Value }}, { ocGeoMean, {{ Reference }, 1, Value }}, diff --git a/sc/source/filter/excel/xlformula.cxx b/sc/source/filter/excel/xlformula.cxx index 3df57661f009..8cdf9806896f 100644 --- a/sc/source/filter/excel/xlformula.cxx +++ b/sc/source/filter/excel/xlformula.cxx @@ -637,7 +637,8 @@ static const XclFunctionInfo saFuncTable_OOoLO[] = EXC_FUNCENTRY_OOO( ocForecast_ETS_PIM, 3, 7, 0, "ORG.LIBREOFFICE.FORECAST.ETS.PI.MULT" ), EXC_FUNCENTRY_OOO( ocForecast_ETS_STM, 3, 6, 0, "ORG.LIBREOFFICE.FORECAST.ETS.STAT.MULT" ), EXC_FUNCENTRY_OOO( ocRoundSig, 2, 2, 0, "ORG.LIBREOFFICE.ROUNDSIG" ), - EXC_FUNCENTRY_OOO( ocRegex, 2, 4, 0, "ORG.LIBREOFFICE.REGEX" ) + EXC_FUNCENTRY_OOO( ocRegex, 2, 4, 0, "ORG.LIBREOFFICE.REGEX" ), + EXC_FUNCENTRY_OOO( ocFourier, 2, 4, 0, "ORG.LIBREOFFICE.FOURIER" ) }; #undef EXC_FUNCENTRY_OOO_IBR diff --git a/sc/source/filter/oox/formulabase.cxx b/sc/source/filter/oox/formulabase.cxx index 62633437c1cb..707db93ed22f 100644 --- a/sc/source/filter/oox/formulabase.cxx +++ b/sc/source/filter/oox/formulabase.cxx @@ -910,7 +910,8 @@ static const FunctionData saFuncTableOOoLO[] = { "ORG.LIBREOFFICE.FORECAST.ETS.PI.MULT", "ORG.LIBREOFFICE.FORECAST.ETS.PI.MULT", NOID, NOID, 4, 7, V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW }, { "ORG.LIBREOFFICE.FORECAST.ETS.STAT.MULT", "ORG.LIBREOFFICE.FORECAST.ETS.STAT.MULT", NOID, NOID, 3, 6, V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW }, { "ORG.LIBREOFFICE.ROUNDSIG", "ORG.LIBREOFFICE.ROUNDSIG", NOID, NOID, 2, 2, V, { RX }, FuncFlags::MACROCALL_NEW }, - { "ORG.LIBREOFFICE.REGEX", "ORG.LIBREOFFICE.REGEX", NOID, NOID, 2, 4, V, { RX }, FuncFlags::MACROCALL_NEW } + { "ORG.LIBREOFFICE.REGEX", "ORG.LIBREOFFICE.REGEX", NOID, NOID, 2, 4, V, { RX }, FuncFlags::MACROCALL_NEW }, + { "ORG.LIBREOFFICE.FOURIER", "ORG.LIBREOFFICE.FOURIER", NOID, NOID, 2, 4, V, { RX }, FuncFlags::MACROCALL_NEW } }; |