From ddf952baa57a6d3f8d3f9e34b605020534447b47 Mon Sep 17 00:00:00 2001 From: RevolverOcelotIII Date: Wed, 9 Sep 2026 15:46:56 -0300 Subject: [PATCH 1/2] Adding custom round with Up and down args --- parser/mpFuncNonCmplx.cpp | 2 +- parser/mpFuncNonCmplx.h | 1 - parser/mpFuncRound.cpp | 50 ++++++++++++++++++++++++++++++++++++ parser/mpFuncRound.h | 19 ++++++++++++++ parser/mpPackageNonCmplx.cpp | 1 + tests.sh | 4 +++ 6 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 parser/mpFuncRound.cpp create mode 100644 parser/mpFuncRound.h diff --git a/parser/mpFuncNonCmplx.cpp b/parser/mpFuncNonCmplx.cpp index 4b10329..9a29cfe 100644 --- a/parser/mpFuncNonCmplx.cpp +++ b/parser/mpFuncNonCmplx.cpp @@ -33,6 +33,7 @@ */ #include "mpFuncNonCmplx.h" +#include "mpFuncRound.h" //--- Standard includes ---------------------------------------------------- #include @@ -111,7 +112,6 @@ double round(long_double_type number, int_type precision) { MUP_UNARY_FUNC(FunExp, "exp", std::exp, "exp(x) - e to the power of x") // number functions MUP_UNARY_FUNC(FunAbs, "abs", std::fabs, "abs(x) - absolute value of x") - MUP_UNARY_FUNC(FunRound, "round", std::round, "round(x) - round the value of x to its nearest integer") #undef MUP_UNARY_FUNC #define MUP_BINARY_FUNC(CLASS, IDENT, FUNC, DESC) \ diff --git a/parser/mpFuncNonCmplx.h b/parser/mpFuncNonCmplx.h index a07327a..cfa3293 100644 --- a/parser/mpFuncNonCmplx.h +++ b/parser/mpFuncNonCmplx.h @@ -81,7 +81,6 @@ MUP_NAMESPACE_START MUP_UNARY_FUNC_DEF(FunExp) // number functions MUP_UNARY_FUNC_DEF(FunAbs) - MUP_UNARY_FUNC_DEF(FunRound) #undef MUP_UNARY_FUNC_DEF #define MUP_BINARY_FUNC_DEF(CLASS) \ diff --git a/parser/mpFuncRound.cpp b/parser/mpFuncRound.cpp new file mode 100644 index 0000000..9df164d --- /dev/null +++ b/parser/mpFuncRound.cpp @@ -0,0 +1,50 @@ +#include "mpFuncRound.h" + +#include + +#include "mpError.h" +#include "mpValue.h" + +MUP_NAMESPACE_START + +FunRound::FunRound() + :ICallback(cmFUNC, _T("round"), -1) +{} + +void FunRound::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) +{ + if (a_iArgc < 1) { + throw ParserError(ErrorContext(ecTOO_FEW_PARAMS, GetExprPos(), GetIdent())); + } else if (a_iArgc > 2) { + throw ParserError(ErrorContext(ecTOO_MANY_PARAMS, GetExprPos(), GetIdent())); + } + + float_type value = a_pArg[0]->GetFloat(); + if (a_iArgc == 1) { + *ret = std::round(value); + return; + } + + string_type direction = a_pArg[1]->GetString(); + if (direction == _T("up")) { + *ret = std::ceil(value); + } else if (direction == _T("down")) { + *ret = std::floor(value); + } else { + ErrorContext err(ecINVALID_PARAMETER, GetExprPos(), GetIdent()); + err.Arg = 2; + throw ParserError(err); + } +} + +const char_type* FunRound::GetDesc() const +{ + return _T("round(x[, direction]) - round x normally, up or down"); +} + +IToken* FunRound::Clone() const +{ + return new FunRound(*this); +} + +MUP_NAMESPACE_END diff --git a/parser/mpFuncRound.h b/parser/mpFuncRound.h new file mode 100644 index 0000000..93bdb88 --- /dev/null +++ b/parser/mpFuncRound.h @@ -0,0 +1,19 @@ +#ifndef MUP_FUNC_ROUND_H +#define MUP_FUNC_ROUND_H + +#include "mpICallback.h" + +MUP_NAMESPACE_START + +class FunRound : public ICallback +{ +public: + FunRound(); + virtual void Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) override; + virtual const char_type* GetDesc() const override; + virtual IToken* Clone() const override; +}; + +MUP_NAMESPACE_END + +#endif diff --git a/parser/mpPackageNonCmplx.cpp b/parser/mpPackageNonCmplx.cpp index 6b84dc1..a4dc3fc 100644 --- a/parser/mpPackageNonCmplx.cpp +++ b/parser/mpPackageNonCmplx.cpp @@ -32,6 +32,7 @@ #include "mpParserBase.h" #include "mpFuncNonCmplx.h" +#include "mpFuncRound.h" #include "mpOprtNonCmplx.h" #include "mpOprtBinCommon.h" diff --git a/tests.sh b/tests.sh index 8fdf8e3..a85b2a5 100755 --- a/tests.sh +++ b/tests.sh @@ -65,6 +65,10 @@ test_eval "10.5 / 5.25" "2" test_eval "abs(-5)" "5" test_eval "log10(10)" "1" test_eval "round(4.4)" "4" +test_eval 'round(10.1, "up")' "11" +test_eval 'round(10.9, "down")' "10" +test_eval 'round(-10.9, "up")' "-10" +test_eval 'round(-10.1, "down")' "-11" test_eval "(3^3)^2" "729" test_eval "3^(3^(2))" "19683" test_eval "10!" "3628800" From 9204160c6b2bf04f71dcd3294ba36708532b8d0d Mon Sep 17 00:00:00 2001 From: RevolverOcelotIII Date: Wed, 9 Sep 2026 16:21:33 -0300 Subject: [PATCH 2/2] Adding round direction to round_decimal --- parser/mpFuncNonCmplx.cpp | 11 ----- parser/mpFuncNonCmplx.h | 1 - parser/mpFuncRound.cpp | 88 +++++++++++++++++++++++++++++---------- parser/mpFuncRound.h | 9 ++++ tests.sh | 4 ++ 5 files changed, 79 insertions(+), 34 deletions(-) diff --git a/parser/mpFuncNonCmplx.cpp b/parser/mpFuncNonCmplx.cpp index 9a29cfe..1d206a5 100644 --- a/parser/mpFuncNonCmplx.cpp +++ b/parser/mpFuncNonCmplx.cpp @@ -49,16 +49,6 @@ MUP_NAMESPACE_START -//------------------------------------------------------------------------------ -// -// Auxiliary Functions -// -//------------------------------------------------------------------------------ -double round(long_double_type number, int_type precision) { - int_type decimals = std::pow(10, precision); - return (std::round(number * decimals)) / decimals; -} - //------------------------------------------------------------------------------ // // @@ -138,7 +128,6 @@ double round(long_double_type number, int_type precision) { MUP_BINARY_FUNC(FunHypot, "hypot", std::hypot, "hypot(x, y) - compute the length of the vector x,y") MUP_BINARY_FUNC(FunAtan2, "atan2", std::atan2, "arcus tangens with quadrant fix") MUP_BINARY_FUNC(FunFmod, "fmod", std::fmod, "fmod(x, y) - floating point remainder of x / y") - MUP_BINARY_FUNC(FunRoundDecimal, "round_decimal", round, "round_decimal(x, y) - round the x number considering y precision") MUP_BINARY_FUNC(FunRemainder, "remainder", std::remainder, "remainder(x, y) - IEEE remainder of x / y") #undef MUP_BINARY_FUNC diff --git a/parser/mpFuncNonCmplx.h b/parser/mpFuncNonCmplx.h index cfa3293..4b91fd1 100644 --- a/parser/mpFuncNonCmplx.h +++ b/parser/mpFuncNonCmplx.h @@ -97,7 +97,6 @@ MUP_NAMESPACE_START MUP_BINARY_FUNC_DEF(FunHypot) MUP_BINARY_FUNC_DEF(FunAtan2) MUP_BINARY_FUNC_DEF(FunFmod) - MUP_BINARY_FUNC_DEF(FunRoundDecimal) MUP_BINARY_FUNC_DEF(FunRemainder) #undef MUP_BINARY_FUNC_DEF diff --git a/parser/mpFuncRound.cpp b/parser/mpFuncRound.cpp index 9df164d..47fd18c 100644 --- a/parser/mpFuncRound.cpp +++ b/parser/mpFuncRound.cpp @@ -7,34 +7,59 @@ MUP_NAMESPACE_START +namespace +{ + void eval_round(ICallback &callback, + ptr_val_type &ret, + const ptr_val_type *args, + int argc, + bool has_precision) + { + int required_argc = has_precision ? 2 : 1; + if (argc < required_argc) { + throw ParserError(ErrorContext(ecTOO_FEW_PARAMS, + callback.GetExprPos(), + callback.GetIdent())); + } else if (argc > required_argc + 1) { + throw ParserError(ErrorContext(ecTOO_MANY_PARAMS, + callback.GetExprPos(), + callback.GetIdent())); + } + + int_type scale = 1; + if (has_precision) { + int_type precision = args[1]->GetFloat(); + scale = std::pow(10, precision); + } + + float_type value = args[0]->GetFloat() * scale; + if (argc == required_argc) { + *ret = std::round(value) / scale; + return; + } + + string_type direction = args[required_argc]->GetString(); + if (direction == _T("up")) { + *ret = std::ceil(value) / scale; + } else if (direction == _T("down")) { + *ret = std::floor(value) / scale; + } else { + ErrorContext err(ecINVALID_PARAMETER, + callback.GetExprPos(), + callback.GetIdent()); + err.Arg = required_argc + 1; + throw ParserError(err); + } + } +} + FunRound::FunRound() :ICallback(cmFUNC, _T("round"), -1) {} void FunRound::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) { - if (a_iArgc < 1) { - throw ParserError(ErrorContext(ecTOO_FEW_PARAMS, GetExprPos(), GetIdent())); - } else if (a_iArgc > 2) { - throw ParserError(ErrorContext(ecTOO_MANY_PARAMS, GetExprPos(), GetIdent())); - } - - float_type value = a_pArg[0]->GetFloat(); - if (a_iArgc == 1) { - *ret = std::round(value); - return; - } - - string_type direction = a_pArg[1]->GetString(); - if (direction == _T("up")) { - *ret = std::ceil(value); - } else if (direction == _T("down")) { - *ret = std::floor(value); - } else { - ErrorContext err(ecINVALID_PARAMETER, GetExprPos(), GetIdent()); - err.Arg = 2; - throw ParserError(err); - } + eval_round(*this, ret, a_pArg, a_iArgc, false); } const char_type* FunRound::GetDesc() const @@ -47,4 +72,23 @@ IToken* FunRound::Clone() const return new FunRound(*this); } +FunRoundDecimal::FunRoundDecimal() + :ICallback(cmFUNC, _T("round_decimal"), -1) +{} + +void FunRoundDecimal::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) +{ + eval_round(*this, ret, a_pArg, a_iArgc, true); +} + +const char_type* FunRoundDecimal::GetDesc() const +{ + return _T("round_decimal(x, precision[, direction]) - round x at the given precision"); +} + +IToken* FunRoundDecimal::Clone() const +{ + return new FunRoundDecimal(*this); +} + MUP_NAMESPACE_END diff --git a/parser/mpFuncRound.h b/parser/mpFuncRound.h index 93bdb88..739930f 100644 --- a/parser/mpFuncRound.h +++ b/parser/mpFuncRound.h @@ -14,6 +14,15 @@ class FunRound : public ICallback virtual IToken* Clone() const override; }; +class FunRoundDecimal : public ICallback +{ +public: + FunRoundDecimal(); + virtual void Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) override; + virtual const char_type* GetDesc() const override; + virtual IToken* Clone() const override; +}; + MUP_NAMESPACE_END #endif diff --git a/tests.sh b/tests.sh index a85b2a5..734e085 100755 --- a/tests.sh +++ b/tests.sh @@ -79,6 +79,10 @@ test_eval "max(1, 2) + min(3, 4) + sum(5, 6)" "16" test_eval "avg(9, 9.8, 10)" "9.6" test_eval "pow(2, 3)" "8" test_eval "round_decimal(4.559, 2)" "4.56" +test_eval 'round_decimal(10.11, 1, "up")' "10.2" +test_eval 'round_decimal(10.19, 1, "down")' "10.1" +test_eval 'round_decimal(-10.19, 1, "up")' "-10.1" +test_eval 'round_decimal(-10.11, 1, "down")' "-10.2" # Conditional tests test_eval "4 > 2 ? \"bigger\" : \"smaller\"" "\"bigger\""