diff --git a/include/fintamath/core/MathObjectTypes.hpp b/include/fintamath/core/MathObjectTypes.hpp index 25ca434f0..2424ca229 100644 --- a/include/fintamath/core/MathObjectTypes.hpp +++ b/include/fintamath/core/MathObjectTypes.hpp @@ -25,6 +25,7 @@ class MathObjectType { InvTrigExpression, HyperbExpression, InvHyperbExpression, + RoundExpression, IBinaryExpression = 4000, diff --git a/src/fintamath/config/ExpressionConfig.cpp b/src/fintamath/config/ExpressionConfig.cpp index 8f6faa220..f9b5f7dd3 100644 --- a/src/fintamath/config/ExpressionConfig.cpp +++ b/src/fintamath/config/ExpressionConfig.cpp @@ -17,6 +17,7 @@ #include "fintamath/expressions/unary/InvHyperbExpression.hpp" #include "fintamath/expressions/unary/InvTrigExpression.hpp" #include "fintamath/expressions/unary/NotExpression.hpp" +#include "fintamath/expressions/unary/RoundExpression.hpp" #include "fintamath/expressions/unary/TrigExpression.hpp" #include "fintamath/functions/arithmetic/Add.hpp" #include "fintamath/functions/arithmetic/Div.hpp" @@ -58,6 +59,8 @@ #include "fintamath/functions/logic/Nequiv.hpp" #include "fintamath/functions/logic/Not.hpp" #include "fintamath/functions/logic/Or.hpp" +#include "fintamath/functions/ntheory/Ceil.hpp" +#include "fintamath/functions/ntheory/Floor.hpp" #include "fintamath/functions/other/Deg.hpp" #include "fintamath/functions/other/Index.hpp" #include "fintamath/functions/other/Percent.hpp" @@ -433,8 +436,17 @@ struct ExpressionConfig { static const ArgumentPtr deg1 = Deg()(Integer(1)); return mulExpr(args.front(), deg1); }); + + Expression::registerFunctionExpressionMaker([](ArgumentPtrVector &&args) { + return RoundExpression(Floor(), args.front()).clone(); + }); + + Expression::registerFunctionExpressionMaker([](ArgumentPtrVector &&args) { + return RoundExpression(Ceil(), args.front()).clone(); + }); } }; const ExpressionConfig config; + } diff --git a/src/fintamath/expressions/IExpression.cpp b/src/fintamath/expressions/IExpression.cpp index dce7e8f93..ffbc2f4ed 100644 --- a/src/fintamath/expressions/IExpression.cpp +++ b/src/fintamath/expressions/IExpression.cpp @@ -325,10 +325,10 @@ ArgumentPtr IExpression::approximateSimplify() const { } if (!containsVar && areNumberChilrenPrecise) { - auto res = callFunction(*approxSimplExpr->getFunction(), - convertToApproximatedNumbers(approxSimplExpr->getChildren())); + if (auto res = callFunction(*approxSimplExpr->getFunction(), + convertToApproximatedNumbers(approxSimplExpr->getChildren())); + is(res)) { - if (is(res)) { return res; } } diff --git a/src/fintamath/expressions/unary/RoundExpression.cpp b/src/fintamath/expressions/unary/RoundExpression.cpp new file mode 100644 index 000000000..2b5acf3f2 --- /dev/null +++ b/src/fintamath/expressions/unary/RoundExpression.cpp @@ -0,0 +1,31 @@ +#include "fintamath/expressions/unary/RoundExpression.hpp" + +#include "fintamath/expressions/ExpressionUtils.hpp" +#include "fintamath/functions/ntheory/Ceil.hpp" +#include "fintamath/functions/ntheory/Floor.hpp" + +namespace fintamath { + +RoundExpression::RoundExpression(const IFunction &inFunc, ArgumentPtr inChild) + : IUnaryExpressionCRTP(inFunc, std::move(inChild)) { +} + +RoundExpression::SimplifyFunctionVector RoundExpression::getFunctionsForPostSimplify() const { + static const RoundExpression::SimplifyFunctionVector simplifyFunctions = { + &RoundExpression::intApproximateSimplify, + }; + return simplifyFunctions; +} + +ArgumentPtr RoundExpression::intApproximateSimplify(const IFunction &func, const ArgumentPtr &rhs) { + if (containsVariable(rhs)) { + return {}; + } + + ArgumentPtr approx = rhs->clone(); + approximateSimplifyChild(approx); + + return callFunction(func, {approx}); +} + +} diff --git a/src/fintamath/expressions/unary/RoundExpression.hpp b/src/fintamath/expressions/unary/RoundExpression.hpp new file mode 100644 index 000000000..09fbbfc2c --- /dev/null +++ b/src/fintamath/expressions/unary/RoundExpression.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "fintamath/expressions/interfaces/IUnaryExpression.hpp" + +namespace fintamath { + +class Rational; + +class RoundExpression : public IUnaryExpressionCRTP { +public: + explicit RoundExpression(const IFunction &inFunc, ArgumentPtr inChild); + + static MathObjectType getTypeStatic() { + return MathObjectType::RoundExpression; + } + +protected: + SimplifyFunctionVector getFunctionsForPostSimplify() const override; + +private: + static ArgumentPtr intApproximateSimplify(const IFunction &func, const ArgumentPtr &rhs); +}; + +} diff --git a/tests/src/expressions/ExpressionTests.cpp b/tests/src/expressions/ExpressionTests.cpp index d4d74657f..68b6c6f3d 100644 --- a/tests/src/expressions/ExpressionTests.cpp +++ b/tests/src/expressions/ExpressionTests.cpp @@ -472,6 +472,19 @@ TEST(ExpressionTests, stringConstructorTest) { EXPECT_EQ(Expression("log(1000!,1000!)").toString(), "1"); EXPECT_EQ(Expression("log(100000000000!,100000000000!)").toString(), "1"); + EXPECT_EQ(Expression("floor(E)").toString(), "2"); + EXPECT_EQ(Expression("ceil(E)").toString(), "3"); + EXPECT_EQ(Expression("floor(E^10)").toString(), "22026"); + EXPECT_EQ(Expression("ceil(E^10)").toString(), "22027"); + EXPECT_EQ(Expression("floor(11^10)").toString(), "25937424601"); + EXPECT_EQ(Expression("ceil(11^10)").toString(), "25937424601"); + EXPECT_EQ(Expression("tan(floor(E/3))").toString(), "0"); + EXPECT_EQ(Expression("tan(ceil(-E/3))").toString(), "0"); + EXPECT_EQ(Expression("ln(floor(E/3))").toString(), "-Inf"); + EXPECT_EQ(Expression("root(ceil(-E/3), 3)").toString(), "0"); + EXPECT_EQ(Expression("floor(E + I)").toString(), "2 + I"); + EXPECT_EQ(Expression("floor(E + x)").toString(), "floor(x + E)"); + EXPECT_EQ(Expression("-sin(x)").toString(), "-sin(x)"); EXPECT_EQ(Expression("-sin(x) + sin(2)").toString(), "-sin(x) + sin(2)"); EXPECT_EQ(Expression("-3sin(E)").toString(), "-3 sin(E)"); @@ -547,6 +560,7 @@ TEST(ExpressionTests, stringConstructorTest) { EXPECT_EQ(Expression("log(1deg, (1deg)^(1deg)) = 1deg").toString(), "True"); EXPECT_EQ(Expression("E^Pi > Pi^E").toString(), "-Pi^E + E^Pi > 0"); // TODO: True EXPECT_EQ(Expression("Pi^E < E^Pi").toString(), "-E^Pi + Pi^E < 0"); // TODO: True + EXPECT_EQ(Expression("log(floor(E), E) = lb(E)").toString(), "True"); EXPECT_EQ(Expression("derivative(a, a)").toString(), "1"); EXPECT_EQ(Expression("derivative(a+a, a)").toString(), "derivative(2 a, a)"); @@ -1849,18 +1863,6 @@ TEST(ExpressionTests, approximateTest) { "7182818284590452353602874713526624977572470936999595749669676277240766303535476^(2." "3315043990071954622896899110121376663320174289635168232800545468180794366424973*10^1656520))"); - EXPECT_EQ(Expression("floor(E)").approximate().toString(), - "2"); - EXPECT_EQ(Expression("ceil(E)").approximate().toString(), - "3"); - EXPECT_EQ(Expression("floor(E^10)").approximate().toString(), - "22026"); - EXPECT_EQ(Expression("ceil(E^10)").approximate().toString(), - "22027"); - EXPECT_EQ(Expression("floor(11^10)").approximate().toString(), - "25937424601"); - EXPECT_EQ(Expression("ceil(11^10)").approximate().toString(), - "25937424601"); EXPECT_EQ(Expression("sin(floor(E^10))").approximate().toString(), "-0.28969263040207500615366554669422425489060452363910610917250538601423874640051459"); EXPECT_EQ(Expression("sin(ceil(E^10))").approximate().toString(), @@ -1869,10 +1871,6 @@ TEST(ExpressionTests, approximateTest) { "-0.4398324432476489878621537810397255512584110903388962591029029773506989984056853"); EXPECT_EQ(Expression("cos(ceil(11^10))").approximate().toString(), "-0.4398324432476489878621537810397255512584110903388962591029029773506989984056853"); - EXPECT_EQ(Expression("tan(floor(E/3))").approximate().toString(), - "0"); - EXPECT_EQ(Expression("tan(ceil(-E/3))").approximate().toString(), - "0"); EXPECT_EQ(Expression("ln(floor(E^10))").approximate().toString(), "9.9999788527248892938130978462467834105024172271892998574080180654845967473754541"); EXPECT_EQ(Expression("root(ceil(E^10), 3)").approximate().toString(), @@ -1881,10 +1879,6 @@ TEST(ExpressionTests, approximateTest) { "23.978952727983705440619435779651292998217068539374171752185677091305736239132367"); EXPECT_EQ(Expression("root(ceil(11^10), 3)").approximate().toString(), "2960.117500547758958671098654417191228566388539497004587135829271326993708483441"); - EXPECT_EQ(Expression("ln(floor(E/3))").approximate().toString(), - "-Inf"); - EXPECT_EQ(Expression("root(ceil(-E/3), 3)").approximate().toString(), - "0"); EXPECT_EQ(Expression("(2/3)!").approximate().toString(), "0.90274529295093361129685868543634252367955151070452913226268164530918864360116169"); diff --git a/tests/src/expressions/unary/RoundExpressionTests.cpp b/tests/src/expressions/unary/RoundExpressionTests.cpp new file mode 100644 index 000000000..e7149f8a8 --- /dev/null +++ b/tests/src/expressions/unary/RoundExpressionTests.cpp @@ -0,0 +1,10 @@ +#include + +#include "fintamath/functions/ntheory/Floor.hpp" +#include "fintamath/numbers/Integer.hpp" + +using namespace fintamath; + +TEST(RoundExpressionTests, getTypeTest) { + EXPECT_EQ(floorExpr(Integer(0).clone())->getType(), MathObjectType::RoundExpression); +}