formula/inc/core_resource.hrc | 12 ++++++++++ include/formula/compiler.hxx | 6 +++-- include/formula/opcode.hxx | 4 +++ sc/inc/helpids.h | 2 + sc/inc/scfuncs.hrc | 16 +++++++++++++ sc/qa/extras/scfunctionlistobj.cxx | 2 - sc/qa/unit/ucalc.cxx | 2 + sc/source/core/data/funcdesc.cxx | 4 ++- sc/source/core/inc/interpre.hxx | 3 ++ sc/source/core/tool/interpr1.cxx | 42 ++++++++++++++++++++++++++++++----- sc/source/core/tool/interpr4.cxx | 2 + sc/source/core/tool/parclass.cxx | 1 sc/source/filter/excel/xlformula.cxx | 4 ++- sc/source/filter/oox/formulabase.cxx | 4 ++- 14 files changed, 93 insertions(+), 11 deletions(-)
New commits: commit 716655820d69a0d6aaa2714cb4f12bae1aa2b862 Author: Eike Rathke <er...@redhat.com> AuthorDate: Mon Apr 27 23:12:42 2020 +0200 Commit: Eike Rathke <er...@redhat.com> CommitDate: Tue Apr 28 11:26:38 2020 +0200 Resolves: tdf#127831 implement RAND.NV() and RANDBETWEEN.NV() non-volatile Same as RAND() and RANDBETWEEN() but not recalculating on every change, just the normal expression recalculation. Change-Id: I8ba7099125e487a78bd3d91db8b666c2f36b22fd Reviewed-on: https://gerrit.libreoffice.org/c/core/+/92994 Tested-by: Jenkins Reviewed-by: Eike Rathke <er...@redhat.com> diff --git a/formula/inc/core_resource.hrc b/formula/inc/core_resource.hrc index 2ad8d3cf5a9e..cf1cca33373f 100644 --- a/formula/inc/core_resource.hrc +++ b/formula/inc/core_resource.hrc @@ -467,6 +467,8 @@ const std::pair<const char*, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF[] = { "ORG.LIBREOFFICE.ROUNDSIG" , SC_OPCODE_ROUNDSIG }, { "ORG.LIBREOFFICE.REGEX" , SC_OPCODE_REGEX }, { "ORG.LIBREOFFICE.FOURIER", SC_OPCODE_FOURIER }, + { "ORG.LIBREOFFICE.RAND.NV" , SC_OPCODE_RANDOM_NV }, + { "ORG.LIBREOFFICE.RANDBETWEEN.NV" , SC_OPCODE_RANDBETWEEN_NV }, { nullptr, -1 } }; @@ -911,6 +913,8 @@ const std::pair<const char*, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML[] = { "_xlfn.ORG.LIBREOFFICE.ROUNDSIG" , SC_OPCODE_ROUNDSIG }, { "_xlfn.ORG.LIBREOFFICE.REGEX" , SC_OPCODE_REGEX }, { "_xlfn.ORG.LIBREOFFICE.FOURIER", SC_OPCODE_FOURIER }, + { "_xlfn.ORG.LIBREOFFICE.RAND.NV" , SC_OPCODE_RANDOM_NV }, + { "_xlfn.ORG.LIBREOFFICE.RANDBETWEEN.NV" , SC_OPCODE_RANDBETWEEN_NV }, { nullptr, -1 } }; @@ -1360,6 +1364,8 @@ const std::pair<const char*, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_PODF[] = { "ROUNDSIG" , SC_OPCODE_ROUNDSIG }, { "REGEX" , SC_OPCODE_REGEX }, { "FOURIER", SC_OPCODE_FOURIER }, + { "RAND.NV" , SC_OPCODE_RANDOM_NV }, + { "RANDBETWEEN.NV" , SC_OPCODE_RANDBETWEEN_NV }, { nullptr, -1 } }; @@ -1808,6 +1814,8 @@ const std::pair<const char*, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_API[] = { "ROUNDSIG" , SC_OPCODE_ROUNDSIG }, { "REGEX" , SC_OPCODE_REGEX }, { "FOURIER", SC_OPCODE_FOURIER }, + { "RAND.NV" , SC_OPCODE_RANDOM_NV }, + { "RANDBETWEEN.NV" , SC_OPCODE_RANDBETWEEN_NV }, { nullptr, -1 } }; @@ -2255,6 +2263,8 @@ const std::pair<const char*, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH[] = { "ROUNDSIG" , SC_OPCODE_ROUNDSIG }, { "REGEX" , SC_OPCODE_REGEX }, { "FOURIER", SC_OPCODE_FOURIER }, + { "RAND.NV" , SC_OPCODE_RANDOM_NV }, + { "RANDBETWEEN.NV" , SC_OPCODE_RANDBETWEEN_NV }, { nullptr, -1 } }; @@ -2699,6 +2709,8 @@ const std::pair<const char*, int> RID_STRLIST_FUNCTION_NAMES[] = { 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 }, + { NC_("RID_STRLIST_FUNCTION_NAMES", "RAND.NV"), SC_OPCODE_RANDOM_NV }, + { NC_("RID_STRLIST_FUNCTION_NAMES", "RANDBETWEEN.NV"), SC_OPCODE_RANDBETWEEN_NV }, { nullptr, -1 } }; diff --git a/include/formula/compiler.hxx b/include/formula/compiler.hxx index c5e5cfdf0da2..baf3e23f6161 100644 --- a/include/formula/compiler.hxx +++ b/include/formula/compiler.hxx @@ -112,7 +112,8 @@ #define SC_OPCODE_GET_ACT_TIME 80 #define SC_OPCODE_NO_VALUE 81 #define SC_OPCODE_CURRENT 82 -#define SC_OPCODE_STOP_NO_PAR 83 +#define SC_OPCODE_RANDOM_NV 83 +#define SC_OPCODE_STOP_NO_PAR 84 /*** Functions with one parameter ***/ #define SC_OPCODE_START_1_PAR 90 @@ -507,7 +508,8 @@ #define SC_OPCODE_SEARCHB 496 #define SC_OPCODE_REGEX 497 #define SC_OPCODE_FOURIER 498 -#define SC_OPCODE_STOP_2_PAR 499 /* last function with two or more parameters' OpCode + 1 */ +#define SC_OPCODE_RANDBETWEEN_NV 499 +#define SC_OPCODE_STOP_2_PAR 500 /* 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 b969a0047007..3123e8f3fa38 100644 --- a/include/formula/opcode.hxx +++ b/include/formula/opcode.hxx @@ -106,6 +106,7 @@ enum OpCode : sal_uInt16 ocGetActTime = SC_OPCODE_GET_ACT_TIME, ocNotAvail = SC_OPCODE_NO_VALUE, ocCurrent = SC_OPCODE_CURRENT, + ocRandomNV = SC_OPCODE_RANDOM_NV, // Functions with one parameter ocNot = SC_OPCODE_NOT, ocNeg = SC_OPCODE_NEG, @@ -501,6 +502,7 @@ enum OpCode : sal_uInt16 ocErfc_MS = SC_OPCODE_ERFC_MS, ocEncodeURL = SC_OPCODE_ENCODEURL, ocFourier = SC_OPCODE_FOURIER, + ocRandbetweenNV = SC_OPCODE_RANDBETWEEN_NV, // internal stuff ocInternalBegin = SC_OPCODE_INTERNAL_BEGIN, ocTTT = SC_OPCODE_TTT, @@ -586,6 +588,7 @@ inline std::string OpCodeEnumToString(OpCode eCode) case ocNegSub: return "NegSub"; case ocPi: return "Pi"; case ocRandom: return "Random"; + case ocRandomNV: return "RandomNV"; case ocTrue: return "True"; case ocFalse: return "False"; case ocGetActDate: return "GetActDate"; @@ -974,6 +977,7 @@ inline std::string OpCodeEnumToString(OpCode eCode) case ocErfc_MS: return "Erfc_MS"; case ocEncodeURL: return "EncodeURL"; case ocFourier: return "Fourier"; + case ocRandbetweenNV: return "RandbetweenNV"; 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 d6616f106784..f9c30fc615a0 100644 --- a/sc/inc/helpids.h +++ b/sc/inc/helpids.h @@ -579,6 +579,8 @@ #define HID_FUNC_SEARCHB "SC_HID_FUNC_SEARCHB" #define HID_FUNC_REGEX "SC_HID_FUNC_REGEX" #define HID_FUNC_FOURIER "SC_HID_FUNC_FOURIER" +#define HID_FUNC_RAND_NV "SC_HID_FUNC_RAND_NV" +#define HID_FUNC_RANDBETWEEN_NV "SC_HID_FUNC_RANDBETWEEN_NV" #endif diff --git a/sc/inc/scfuncs.hrc b/sc/inc/scfuncs.hrc index 77031c5a5ac8..9a96b3d9975c 100644 --- a/sc/inc/scfuncs.hrc +++ b/sc/inc/scfuncs.hrc @@ -4134,6 +4134,22 @@ const char* SC_OPCODE_FOURIER_ARY[] = NC_("SC_OPCODE_FOURIER", "In case of Polar=TRUE, the frequency components below this magnitude are clipped out (default 0.0).") }; +// -=*# Resource for function RAND.NV #*=- +const char* SC_OPCODE_RANDOM_NV_ARY[] = +{ + NC_("SC_OPCODE_RANDOM_NV", "Returns a random number between 0 and 1, non-volatile.") +}; + +// -=*# Resource for function RANDBETWEEN.NV #*=- +const char* SC_OPCODE_RANDBETWEEN_NV_ARY[] = +{ + NC_("SC_OPCODE_RANDBETWEEN_NV", "Returns a random integer between the numbers you specify, non-volatile."), + NC_("SC_OPCODE_RANDBETWEEN_NV", "Bottom"), + NC_("SC_OPCODE_RANDBETWEEN_NV", "The smallest integer returned."), + NC_("SC_OPCODE_RANDBETWEEN_NV", "Top"), + NC_("SC_OPCODE_RANDBETWEEN_NV", "The largest integer returned.") +}; + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/qa/extras/scfunctionlistobj.cxx b/sc/qa/extras/scfunctionlistobj.cxx index cf8c962bfb06..385ea7d8962a 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(393) + , XIndexAccess(395) , 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 964247b9fe7f..0bc11aaeeaae 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -2405,6 +2405,8 @@ void Test::testFunctionLists() "PRODUCT", "RADIANS", "RAND", + "RAND.NV", + "RANDBETWEEN.NV", "RAWSUBTRACT", "ROUND", "ROUNDDOWN", diff --git a/sc/source/core/data/funcdesc.cxx b/sc/source/core/data/funcdesc.cxx index 7c37b12f3d65..6768dd6f8bcd 100644 --- a/sc/source/core/data/funcdesc.cxx +++ b/sc/source/core/data/funcdesc.cxx @@ -408,6 +408,7 @@ ScFunctionList::ScFunctionList() { SC_OPCODE_GET_ACT_TIME, ENTRY(SC_OPCODE_GET_ACT_TIME_ARY), 0, ID_FUNCTION_GRP_DATETIME, HID_FUNC_JETZT, 0, { } }, { SC_OPCODE_NO_VALUE, ENTRY(SC_OPCODE_NO_VALUE_ARY), 0, ID_FUNCTION_GRP_INFO, HID_FUNC_NV, 0, { } }, { SC_OPCODE_CURRENT, ENTRY(SC_OPCODE_CURRENT_ARY), 0, ID_FUNCTION_GRP_INFO, HID_FUNC_AKTUELL, 0, { } }, + { SC_OPCODE_RANDOM_NV, ENTRY(SC_OPCODE_RANDOM_NV_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_RAND_NV, 0, { } }, { SC_OPCODE_DEG, ENTRY(SC_OPCODE_DEG_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_DEG, 1, { 0 } }, { SC_OPCODE_RAD, ENTRY(SC_OPCODE_RAD_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_RAD, 1, { 0 } }, { SC_OPCODE_SIN, ENTRY(SC_OPCODE_SIN_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_SIN, 1, { 0 } }, @@ -786,7 +787,8 @@ ScFunctionList::ScFunctionList() { 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_FOURIER, ENTRY(SC_OPCODE_FOURIER_ARY), 0, ID_FUNCTION_GRP_MATRIX, HID_FUNC_FOURIER, 5, { 0, 0, 1, 1, 1 } } + { SC_OPCODE_FOURIER, ENTRY(SC_OPCODE_FOURIER_ARY), 0, ID_FUNCTION_GRP_MATRIX, HID_FUNC_FOURIER, 5, { 0, 0, 1, 1, 1 } }, + { SC_OPCODE_RANDBETWEEN_NV, ENTRY(SC_OPCODE_RANDBETWEEN_NV_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_RANDBETWEEN_NV, 2, { 0, 0 } } }; ScFuncDesc* pDesc = nullptr; diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx index 4cecd7ef3058..9aaeeb96259c 100644 --- a/sc/source/core/inc/interpre.hxx +++ b/sc/source/core/inc/interpre.hxx @@ -530,6 +530,9 @@ private: void ScUnionFunc(); void ScPi(); void ScRandom(); + void ScRandbetween(); + void ScRandomImpl( const std::function<double( double fFirst, double fLast )>& RandomFunc, + double fFirst, double fLast ); void ScTrue(); void ScFalse(); void ScDeg(); diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index 03a8f46731a6..839c5135d665 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -1736,13 +1736,14 @@ void ScInterpreter::ScPi() PushDouble(F_PI); } -void ScInterpreter::ScRandom() +void ScInterpreter::ScRandomImpl( const std::function<double( double fFirst, double fLast )>& RandomFunc, + double fFirst, double fLast ) { if (bMatrixFormula) { SCCOL nCols = 0; SCROW nRows = 0; - if(pMyFormulaCell) + if (pMyFormulaCell) pMyFormulaCell->GetMatColsRows( nCols, nRows); if (nCols == 1 && nRows == 1) @@ -1752,7 +1753,7 @@ void ScInterpreter::ScRandom() // default are executed in array context unless // FA.setPropertyValue("IsArrayFunction",False) was set, return a // scalar double instead of a 1x1 matrix object. tdf#128218 - PushDouble( comphelper::rng::uniform_real_distribution()); + PushDouble( RandomFunc( fFirst, fLast)); return; } @@ -1773,7 +1774,7 @@ void ScInterpreter::ScRandom() { for (SCROW j=0; j < nRows; ++j) { - pResMat->PutDouble( comphelper::rng::uniform_real_distribution(), + pResMat->PutDouble( RandomFunc( fFirst, fLast), static_cast<SCSIZE>(i), static_cast<SCSIZE>(j)); } } @@ -1782,8 +1783,39 @@ void ScInterpreter::ScRandom() } else { - PushDouble( comphelper::rng::uniform_real_distribution()); + PushDouble( RandomFunc( fFirst, fLast)); + } +} + +void ScInterpreter::ScRandom() +{ + auto RandomFunc = []( double, double ) + { + return comphelper::rng::uniform_real_distribution(); + }; + ScRandomImpl( RandomFunc, 0.0, 0.0); +} + +void ScInterpreter::ScRandbetween() +{ + if (!MustHaveParamCount( GetByte(), 2)) + return; + + // Same like scaddins/source/analysis/analysis.cxx + // AnalysisAddIn::getRandbetween() + double fMax = rtl::math::round( GetDouble(), 0, rtl_math_RoundingMode_Up); + double fMin = rtl::math::round( GetDouble(), 0, rtl_math_RoundingMode_Up); + if (nGlobalError != FormulaError::NONE || fMin > fMax) + { + PushIllegalArgument(); + return; } + fMax = std::nextafter( fMax+1, -DBL_MAX); + auto RandomFunc = []( double fFirst, double fLast ) + { + return floor( comphelper::rng::uniform_real_distribution( fFirst, fLast)); + }; + ScRandomImpl( RandomFunc, fMin, fMax); } void ScInterpreter::ScTrue() diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index 6fd4da8a1e36..7a6f03026121 100644 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -4062,6 +4062,8 @@ StackVar ScInterpreter::Interpret() case ocPercentSign : ScPercentSign(); break; case ocPi : ScPi(); break; case ocRandom : ScRandom(); break; + case ocRandomNV : ScRandom(); break; + case ocRandbetweenNV : ScRandbetween(); break; case ocTrue : ScTrue(); break; case ocFalse : ScFalse(); break; case ocGetActDate : ScGetActDate(); break; diff --git a/sc/source/core/tool/parclass.cxx b/sc/source/core/tool/parclass.cxx index 3f9843fb333c..b2f0914b680a 100644 --- a/sc/source/core/tool/parclass.cxx +++ b/sc/source/core/tool/parclass.cxx @@ -221,6 +221,7 @@ const ScParameterClassification::RawData ScParameterClassification::pRawData[] = { ocQuartile_Inc, {{ Reference, Value }, 0, Value }}, { ocRSQ, {{ ForceArray, ForceArray }, 0, Value }}, { ocRandom, {{ Bounds }, 0, Value }}, + { ocRandomNV, {{ Bounds }, 0, Value }}, { ocRange, {{ Reference, Reference }, 0, Reference }}, { ocRank, {{ Value, Reference, Value }, 0, Value }}, { ocRank_Avg, {{ Value, Reference, Value }, 0, Value }}, diff --git a/sc/source/filter/excel/xlformula.cxx b/sc/source/filter/excel/xlformula.cxx index c4037b4c9d91..30db442f67de 100644 --- a/sc/source/filter/excel/xlformula.cxx +++ b/sc/source/filter/excel/xlformula.cxx @@ -638,7 +638,9 @@ static const XclFunctionInfo saFuncTable_OOoLO[] = 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( ocFourier, 2, 5, 0, "ORG.LIBREOFFICE.FOURIER" ) + EXC_FUNCENTRY_OOO( ocFourier, 2, 5, 0, "ORG.LIBREOFFICE.FOURIER" ), + EXC_FUNCENTRY_OOO( ocRandomNV, 0, 0, 0, "ORG.LIBREOFFICE.RAND.NV" ), + EXC_FUNCENTRY_OOO( ocRandbetweenNV, 2, 2, 0, "ORG.LIBREOFFICE.RANDBETWEEN.NV" ) }; #undef EXC_FUNCENTRY_OOO_IBR diff --git a/sc/source/filter/oox/formulabase.cxx b/sc/source/filter/oox/formulabase.cxx index b2c074a1d277..f29c922a26ba 100644 --- a/sc/source/filter/oox/formulabase.cxx +++ b/sc/source/filter/oox/formulabase.cxx @@ -915,7 +915,9 @@ static const FunctionData saFuncTableOOoLO[] = { "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.FOURIER", "ORG.LIBREOFFICE.FOURIER", NOID, NOID, 2, 5, A, { RX }, FuncFlags::MACROCALL_NEW } + { "ORG.LIBREOFFICE.FOURIER", "ORG.LIBREOFFICE.FOURIER", NOID, NOID, 2, 5, A, { RX }, FuncFlags::MACROCALL_NEW }, + { "ORG.LIBREOFFICE.RAND.NV", "ORG.LIBREOFFICE.RAND.NV", NOID, NOID, 0, 0, V, {}, FuncFlags::MACROCALL_NEW }, + { "ORG.LIBREOFFICE.RANDBETWEEN.NV", "ORG.LIBREOFFICE.RANDBETWEEN.NV", NOID, NOID, 2, 2, V, { VR }, FuncFlags::MACROCALL_NEW } }; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits