diff --git a/include/fintamath/core/MathObjectTypes.hpp b/include/fintamath/core/MathObjectTypes.hpp index 65fba4677..b175cfb63 100644 --- a/include/fintamath/core/MathObjectTypes.hpp +++ b/include/fintamath/core/MathObjectTypes.hpp @@ -113,6 +113,8 @@ class MathObjectType { Integral, Frac, PowF, + Floor, + Ceil, IOperator = 12000, @@ -140,6 +142,7 @@ class MathObjectType { Index, Deg, Comma, + Mod, None = std::numeric_limits::max(), }; diff --git a/include/fintamath/expressions/ExpressionFunctions.hpp b/include/fintamath/expressions/ExpressionFunctions.hpp index f65a6ab54..eaf3ff1bf 100644 --- a/include/fintamath/expressions/ExpressionFunctions.hpp +++ b/include/fintamath/expressions/ExpressionFunctions.hpp @@ -16,6 +16,8 @@ Expression sub(const Expression &lhs, const Expression &rhs); Expression div(const Expression &lhs, const Expression &rhs); +Expression mod(const Expression &lhs, const Expression &rhs); + Expression neg(const Expression &rhs); Expression eqv(const Expression &lhs, const Expression &rhs); @@ -30,6 +32,10 @@ Expression lessEqv(const Expression &lhs, const Expression &rhs); Expression moreEqv(const Expression &lhs, const Expression &rhs); +Expression floor(const Expression &rhs); + +Expression ceil(const Expression &rhs); + Expression abs(const Expression &rhs); Expression factorial(const Expression &rhs); diff --git a/include/fintamath/functions/IOperator.hpp b/include/fintamath/functions/IOperator.hpp index 4e8af1a9f..54bf23e5f 100644 --- a/include/fintamath/functions/IOperator.hpp +++ b/include/fintamath/functions/IOperator.hpp @@ -15,6 +15,7 @@ class IOperator : public IFunction { PrefixUnary, // e.g. -a Multiplication, // e.g. a * b Addition, // e.g. a + b + Modulo, // e.g. a mod b Comparison, // e.g. a = b Conjunction, // e.g. a & b Disjunction, // e.g. a | b diff --git a/include/fintamath/functions/ntheory/Ceil.hpp b/include/fintamath/functions/ntheory/Ceil.hpp new file mode 100644 index 000000000..3a3eb030c --- /dev/null +++ b/include/fintamath/functions/ntheory/Ceil.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "fintamath/functions/IFunction.hpp" +#include "fintamath/numbers/INumber.hpp" + +namespace fintamath { + +class Ceil : public IFunctionCRTP { +public: + Ceil() = default; + + std::string toString() const override { + return "ceil"; + } + + static MathObjectType getTypeStatic() { + return MathObjectType::Ceil; + } + +protected: + std::unique_ptr call(const ArgumentRefVector &argsVect) const override; + +private: + static std::unique_ptr multiCeilSimplify(const INumber &rhs); +}; + +FINTAMATH_FUNCTION_EXPRESSION(Ceil, ceilExpr); + +} diff --git a/include/fintamath/functions/ntheory/Floor.hpp b/include/fintamath/functions/ntheory/Floor.hpp new file mode 100644 index 000000000..6041ed6ad --- /dev/null +++ b/include/fintamath/functions/ntheory/Floor.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "fintamath/functions/IFunction.hpp" +#include "fintamath/numbers/INumber.hpp" + +namespace fintamath { + +class Floor : public IFunctionCRTP { +public: + Floor() = default; + + std::string toString() const override { + return "floor"; + } + + static MathObjectType getTypeStatic() { + return MathObjectType::Floor; + } + +protected: + std::unique_ptr call(const ArgumentRefVector &argsVect) const override; + +private: + static std::unique_ptr multiFloorSimplify(const INumber &rhs); +}; + +FINTAMATH_FUNCTION_EXPRESSION(Floor, floorExpr); + +} diff --git a/include/fintamath/functions/ntheory/Mod.hpp b/include/fintamath/functions/ntheory/Mod.hpp new file mode 100644 index 000000000..72cdfe142 --- /dev/null +++ b/include/fintamath/functions/ntheory/Mod.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "fintamath/functions/IOperator.hpp" +#include "fintamath/numbers/INumber.hpp" +#include "fintamath/numbers/Integer.hpp" + +namespace fintamath { + +class Mod : public IOperatorCRTP { +public: + Mod() : IOperatorCRTP(IOperator::Priority::Modulo) { + } + + std::string toString() const override { + return "mod"; + } + + static MathObjectType getTypeStatic() { + return MathObjectType::Mod; + } + +protected: + std::unique_ptr call(const ArgumentRefVector &argsVect) const override; + +private: + static std::unique_ptr multiModSimplify(const INumber &lhs, const INumber &rhs); +}; + +FINTAMATH_FUNCTION_EXPRESSION(Mod, modExpr); + +} diff --git a/src/fintamath/config/ParserConfig.cpp b/src/fintamath/config/ParserConfig.cpp index 7308e22b6..162db00ca 100644 --- a/src/fintamath/config/ParserConfig.cpp +++ b/src/fintamath/config/ParserConfig.cpp @@ -46,6 +46,9 @@ #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/ntheory/Mod.hpp" #include "fintamath/functions/other/Comma.hpp" #include "fintamath/functions/other/Deg.hpp" #include "fintamath/functions/other/Factorial.hpp" @@ -223,6 +226,8 @@ struct ParserConfig { IFunction::registerType(); IFunction::registerType(); IFunction::registerType(); + IFunction::registerType(); + IFunction::registerType(); IOperator::registerType(); IOperator::registerType(); @@ -248,6 +253,7 @@ struct ParserConfig { IOperator::registerType(); IOperator::registerType(); IOperator::registerType(); + IOperator::registerType(); IExpression::registerType(); } diff --git a/src/fintamath/expressions/ExpressionFunctions.cpp b/src/fintamath/expressions/ExpressionFunctions.cpp index e0851f139..5fef19934 100644 --- a/src/fintamath/expressions/ExpressionFunctions.cpp +++ b/src/fintamath/expressions/ExpressionFunctions.cpp @@ -24,6 +24,9 @@ #include "fintamath/functions/logic/And.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/ntheory/Mod.hpp" #include "fintamath/functions/other/Factorial.hpp" #include "fintamath/functions/powers/Exp.hpp" #include "fintamath/functions/powers/Pow.hpp" @@ -53,6 +56,10 @@ Expression div(const Expression &lhs, const Expression &rhs) { return lhs / rhs; } +Expression mod(const Expression &lhs, const Expression &rhs) { + return Expression(modExpr(lhs, rhs)); +} + Expression neg(const Expression &rhs) { return -rhs; } @@ -81,6 +88,14 @@ Expression moreEqv(const Expression &lhs, const Expression &rhs) { return Expression(moreEqvExpr(lhs, rhs)); } +Expression floor(const Expression &rhs) { + return Expression(floorExpr(rhs)); +} + +Expression ceil(const Expression &rhs) { + return Expression(ceilExpr(rhs)); +} + Expression abs(const Expression &rhs) { return Expression(absExpr(rhs)); } diff --git a/src/fintamath/functions/ntheory/Ceil.cpp b/src/fintamath/functions/ntheory/Ceil.cpp new file mode 100644 index 000000000..d24492b22 --- /dev/null +++ b/src/fintamath/functions/ntheory/Ceil.cpp @@ -0,0 +1,48 @@ +#include "fintamath/functions/ntheory/Ceil.hpp" + +#include "fintamath/functions/powers/Sqrt.hpp" +#include "fintamath/numbers/Complex.hpp" +#include "fintamath/numbers/Integer.hpp" +#include "fintamath/numbers/IntegerFunctions.hpp" +#include "fintamath/numbers/Rational.hpp" +#include "fintamath/numbers/RationalFunctions.hpp" +#include "fintamath/numbers/Real.hpp" +#include "fintamath/numbers/RealFunctions.hpp" + +namespace fintamath { + +std::unique_ptr Ceil::call(const ArgumentRefVector &argsVect) const { + const auto &rhs = cast(argsVect.front().get()); + + return multiCeilSimplify(rhs); +} + +std::unique_ptr Ceil::multiCeilSimplify(const INumber &rhs) { + static const auto multiCeil = [] { + static MultiMethod(const INumber &)> outMultiCeil; + + outMultiCeil.add([](const Integer &inRhs) { + return inRhs.clone(); + }); + + outMultiCeil.add([](const Rational &inRhs) { + return ceil(inRhs).clone(); + }); + + outMultiCeil.add([](const Real &inRhs) { + return ceil(inRhs).clone(); + }); + + outMultiCeil.add([](const Complex &inRhs) { + const auto re = cast(multiCeilSimplify(inRhs.real())); + const auto im = cast(multiCeilSimplify(inRhs.imag())); + return Complex(*re, *im).toMinimalObject(); + }); + + return outMultiCeil; + }(); + + return multiCeil(rhs); +} + +} diff --git a/src/fintamath/functions/ntheory/Floor.cpp b/src/fintamath/functions/ntheory/Floor.cpp new file mode 100644 index 000000000..f80478236 --- /dev/null +++ b/src/fintamath/functions/ntheory/Floor.cpp @@ -0,0 +1,48 @@ +#include "fintamath/functions/ntheory/Floor.hpp" + +#include "fintamath/functions/powers/Sqrt.hpp" +#include "fintamath/numbers/Complex.hpp" +#include "fintamath/numbers/Integer.hpp" +#include "fintamath/numbers/IntegerFunctions.hpp" +#include "fintamath/numbers/Rational.hpp" +#include "fintamath/numbers/RationalFunctions.hpp" +#include "fintamath/numbers/Real.hpp" +#include "fintamath/numbers/RealFunctions.hpp" + +namespace fintamath { + +std::unique_ptr Floor::call(const ArgumentRefVector &argsVect) const { + const auto &rhs = cast(argsVect.front().get()); + + return multiFloorSimplify(rhs); +} + +std::unique_ptr Floor::multiFloorSimplify(const INumber &rhs) { + static const auto multiFloor = [] { + static MultiMethod(const INumber &)> outMultiFloor; + + outMultiFloor.add([](const Integer &inRhs) { + return inRhs.clone(); + }); + + outMultiFloor.add([](const Rational &inRhs) { + return floor(inRhs).clone(); + }); + + outMultiFloor.add([](const Real &inRhs) { + return floor(inRhs).clone(); + }); + + outMultiFloor.add([](const Complex &inRhs) { + const auto re = cast(multiFloorSimplify(inRhs.real())); + const auto im = cast(multiFloorSimplify(inRhs.imag())); + return Complex(*re, *im).toMinimalObject(); + }); + + return outMultiFloor; + }(); + + return multiFloor(rhs); +} + +} diff --git a/src/fintamath/functions/ntheory/Mod.cpp b/src/fintamath/functions/ntheory/Mod.cpp new file mode 100644 index 000000000..2c9fce5d3 --- /dev/null +++ b/src/fintamath/functions/ntheory/Mod.cpp @@ -0,0 +1,45 @@ +#include "fintamath/functions/ntheory/Mod.hpp" + +#include "fintamath/literals/constants/Undefined.hpp" +#include "fintamath/numbers/IntegerFunctions.hpp" + +namespace fintamath { + +std::unique_ptr Mod::call(const ArgumentRefVector &argsVect) const { + const auto &lhs = cast(argsVect.front().get()); + const auto &rhs = cast(argsVect.back().get()); + + if (rhs == Integer(0)) { + return Undefined().clone(); + } + + return multiModSimplify(lhs, rhs); +} + +std::unique_ptr Mod::multiModSimplify(const INumber &lhs, const INumber &rhs) { + // TODO: implement non-integer modulo + + static const auto multiMod = [] { + static MultiMethod(const INumber &, const INumber &)> outMultiMod; + + outMultiMod.add([](const Integer &inLhs, const Integer &inRhs) { + if (inLhs == 0 || abs(inRhs) == 1) { + return Integer(0).clone(); + } + + Integer mod = inLhs % inRhs; + + if (inLhs.sign() != inRhs.sign()) { + mod += inRhs; + } + + return std::move(mod).clone(); + }); + + return outMultiMod; + }(); + + return multiMod(lhs, rhs); +} + +} diff --git a/tests/src/functions/ntheory/CeilTests.cpp b/tests/src/functions/ntheory/CeilTests.cpp new file mode 100644 index 000000000..d98715237 --- /dev/null +++ b/tests/src/functions/ntheory/CeilTests.cpp @@ -0,0 +1,92 @@ +#include "gtest/gtest.h" + +#include "fintamath/functions/ntheory/Ceil.hpp" + +#include "fintamath/functions/arithmetic/Sub.hpp" +#include "fintamath/functions/trigonometry/Sin.hpp" +#include "fintamath/literals/Variable.hpp" +#include "fintamath/numbers/Complex.hpp" +#include "fintamath/numbers/Rational.hpp" +#include "fintamath/numbers/Real.hpp" + +using namespace fintamath; + +const Ceil f; + +TEST(CeilTests, toStringTest) { + EXPECT_EQ(f.toString(), "ceil"); +} + +TEST(CeilTests, getFunctionTypeTest) { + EXPECT_EQ(f.getFunctionType(), IFunction::Type::Unary); +} + +TEST(CeilTests, callTest) { + EXPECT_EQ(f(Integer(0))->toString(), "0"); + EXPECT_EQ(f(Integer(10))->toString(), "10"); + EXPECT_EQ(f(Integer(-10))->toString(), "-10"); + + EXPECT_EQ(f(Rational("-2.9"))->toString(), "-2"); + EXPECT_EQ(f(Rational("-2.2"))->toString(), "-2"); + EXPECT_EQ(f(Rational("-2"))->toString(), "-2"); + EXPECT_EQ(f(Rational("0"))->toString(), "0"); + EXPECT_EQ(f(Rational("2"))->toString(), "2"); + EXPECT_EQ(f(Rational("2.2"))->toString(), "3"); + EXPECT_EQ(f(Rational("2.9"))->toString(), "3"); + + EXPECT_EQ(f(Real("-2.9"))->toString(), "-2"); + EXPECT_EQ(f(Real("-2.2"))->toString(), "-2"); + EXPECT_EQ(f(Real("-2"))->toString(), "-2"); + EXPECT_EQ(f(Real("0"))->toString(), "0"); + EXPECT_EQ(f(Real("2"))->toString(), "2"); + EXPECT_EQ(f(Real("2.2"))->toString(), "3"); + EXPECT_EQ(f(Real("2.9"))->toString(), "3"); + + EXPECT_EQ(f(Complex(0, 0))->toString(), "0"); + EXPECT_EQ(f(Complex(2, 0))->toString(), "2"); + EXPECT_EQ(f(Complex(0, 2))->toString(), "2 I"); + EXPECT_EQ(f(Complex(2, 2))->toString(), "2 + 2 I"); + EXPECT_EQ(f(Complex(Rational("1.1"), Rational("2.2")))->toString(), "2 + 3 I"); + EXPECT_EQ(f(Complex(Rational("1.1"), Rational("-2.2")))->toString(), "2 - 2 I"); + EXPECT_EQ(f(Complex(Rational("-1.1"), Rational("2.2")))->toString(), "-1 + 3 I"); + EXPECT_EQ(f(Complex(Rational("-1.1"), Rational("-2.2")))->toString(), "-1 - 2 I"); + EXPECT_EQ(f(Complex(Real("1.1"), Real("2.2")))->toString(), "2 + 3 I"); + EXPECT_EQ(f(Complex(Real("1.1"), Real("-2.2")))->toString(), "2 - 2 I"); + EXPECT_EQ(f(Complex(Real("-1.1"), Real("2.2")))->toString(), "-1 + 3 I"); + EXPECT_EQ(f(Complex(Real("-1.1"), Real("-2.2")))->toString(), "-1 - 2 I"); + + EXPECT_EQ(f(Variable("a"))->toString(), "ceil(a)"); + + EXPECT_THROW(f(), InvalidInputFunctionException); + EXPECT_THROW(f(Integer(1), Integer(1), Integer(1)), InvalidInputFunctionException); +} + +TEST(CeilTests, exprTest) { + EXPECT_EQ(ceilExpr(Integer(10))->toString(), "ceil(10)"); +} + +TEST(CeilTests, doArgsMatchTest) { + Integer a; + + EXPECT_FALSE(f.doArgsMatch({})); + EXPECT_TRUE(f.doArgsMatch({a})); + EXPECT_FALSE(f.doArgsMatch({a, a})); + EXPECT_FALSE(f.doArgsMatch({a, a, a})); +} + +TEST(CeilTests, equalsTest) { + EXPECT_EQ(f, f); + EXPECT_EQ(f, Ceil()); + EXPECT_EQ(Ceil(), f); + EXPECT_EQ(f, cast(Ceil())); + EXPECT_EQ(cast(Ceil()), f); + EXPECT_NE(f, Sin()); + EXPECT_NE(Sin(), f); + EXPECT_NE(f, Sub()); + EXPECT_NE(Sub(), f); +} + +TEST(CeilTests, getTypeTest) { + EXPECT_EQ(Ceil::getTypeStatic(), MathObjectType::Ceil); + EXPECT_EQ(Ceil().getType(), MathObjectType::Ceil); +} diff --git a/tests/src/functions/ntheory/FloorTests.cpp b/tests/src/functions/ntheory/FloorTests.cpp new file mode 100644 index 000000000..b1c0cebf1 --- /dev/null +++ b/tests/src/functions/ntheory/FloorTests.cpp @@ -0,0 +1,92 @@ +#include "gtest/gtest.h" + +#include "fintamath/functions/ntheory/Floor.hpp" + +#include "fintamath/functions/arithmetic/Sub.hpp" +#include "fintamath/functions/trigonometry/Sin.hpp" +#include "fintamath/literals/Variable.hpp" +#include "fintamath/numbers/Complex.hpp" +#include "fintamath/numbers/Rational.hpp" +#include "fintamath/numbers/Real.hpp" + +using namespace fintamath; + +const Floor f; + +TEST(FloorTests, toStringTest) { + EXPECT_EQ(f.toString(), "floor"); +} + +TEST(FloorTests, getFunctionTypeTest) { + EXPECT_EQ(f.getFunctionType(), IFunction::Type::Unary); +} + +TEST(FloorTests, callTest) { + EXPECT_EQ(f(Integer(0))->toString(), "0"); + EXPECT_EQ(f(Integer(10))->toString(), "10"); + EXPECT_EQ(f(Integer(-10))->toString(), "-10"); + + EXPECT_EQ(f(Rational("-2.9"))->toString(), "-3"); + EXPECT_EQ(f(Rational("-2.2"))->toString(), "-3"); + EXPECT_EQ(f(Rational("-2"))->toString(), "-2"); + EXPECT_EQ(f(Rational("0"))->toString(), "0"); + EXPECT_EQ(f(Rational("2"))->toString(), "2"); + EXPECT_EQ(f(Rational("2.2"))->toString(), "2"); + EXPECT_EQ(f(Rational("2.9"))->toString(), "2"); + + EXPECT_EQ(f(Real("-2.9"))->toString(), "-3"); + EXPECT_EQ(f(Real("-2.2"))->toString(), "-3"); + EXPECT_EQ(f(Real("-2"))->toString(), "-2"); + EXPECT_EQ(f(Real("0"))->toString(), "0"); + EXPECT_EQ(f(Real("2"))->toString(), "2"); + EXPECT_EQ(f(Real("2.2"))->toString(), "2"); + EXPECT_EQ(f(Real("2.9"))->toString(), "2"); + + EXPECT_EQ(f(Complex(0, 0))->toString(), "0"); + EXPECT_EQ(f(Complex(2, 0))->toString(), "2"); + EXPECT_EQ(f(Complex(0, 2))->toString(), "2 I"); + EXPECT_EQ(f(Complex(2, 2))->toString(), "2 + 2 I"); + EXPECT_EQ(f(Complex(Rational("1.1"), Rational("2.2")))->toString(), "1 + 2 I"); + EXPECT_EQ(f(Complex(Rational("1.1"), Rational("-2.2")))->toString(), "1 - 3 I"); + EXPECT_EQ(f(Complex(Rational("-1.1"), Rational("2.2")))->toString(), "-2 + 2 I"); + EXPECT_EQ(f(Complex(Rational("-1.1"), Rational("-2.2")))->toString(), "-2 - 3 I"); + EXPECT_EQ(f(Complex(Real("1.1"), Real("2.2")))->toString(), "1 + 2 I"); + EXPECT_EQ(f(Complex(Real("1.1"), Real("-2.2")))->toString(), "1 - 3 I"); + EXPECT_EQ(f(Complex(Real("-1.1"), Real("2.2")))->toString(), "-2 + 2 I"); + EXPECT_EQ(f(Complex(Real("-1.1"), Real("-2.2")))->toString(), "-2 - 3 I"); + + EXPECT_EQ(f(Variable("a"))->toString(), "floor(a)"); + + EXPECT_THROW(f(), InvalidInputFunctionException); + EXPECT_THROW(f(Integer(1), Integer(1), Integer(1)), InvalidInputFunctionException); +} + +TEST(FloorTests, exprTest) { + EXPECT_EQ(floorExpr(Integer(10))->toString(), "floor(10)"); +} + +TEST(FloorTests, doArgsMatchTest) { + Integer a; + + EXPECT_FALSE(f.doArgsMatch({})); + EXPECT_TRUE(f.doArgsMatch({a})); + EXPECT_FALSE(f.doArgsMatch({a, a})); + EXPECT_FALSE(f.doArgsMatch({a, a, a})); +} + +TEST(FloorTests, equalsTest) { + EXPECT_EQ(f, f); + EXPECT_EQ(f, Floor()); + EXPECT_EQ(Floor(), f); + EXPECT_EQ(f, cast(Floor())); + EXPECT_EQ(cast(Floor()), f); + EXPECT_NE(f, Sin()); + EXPECT_NE(Sin(), f); + EXPECT_NE(f, Sub()); + EXPECT_NE(Sub(), f); +} + +TEST(FloorTests, getTypeTest) { + EXPECT_EQ(Floor::getTypeStatic(), MathObjectType::Floor); + EXPECT_EQ(Floor().getType(), MathObjectType::Floor); +} diff --git a/tests/src/functions/ntheory/ModTests.cpp b/tests/src/functions/ntheory/ModTests.cpp new file mode 100644 index 000000000..b3d81a26e --- /dev/null +++ b/tests/src/functions/ntheory/ModTests.cpp @@ -0,0 +1,108 @@ +#include "gtest/gtest.h" + +#include "fintamath/functions/ntheory/Mod.hpp" + +#include "fintamath/exceptions/InvalidInputException.hpp" +#include "fintamath/functions/arithmetic/Sub.hpp" +#include "fintamath/functions/arithmetic/UnaryPlus.hpp" +#include "fintamath/literals/Boolean.hpp" +#include "fintamath/literals/Variable.hpp" +#include "fintamath/numbers/Complex.hpp" +#include "fintamath/numbers/Rational.hpp" + +using namespace fintamath; + +const Mod f; + +TEST(ModTests, toStringTest) { + EXPECT_EQ(f.toString(), "mod"); +} + +TEST(ModTests, getFunctionTypeTest) { + EXPECT_EQ(f.getFunctionType(), IFunction::Type::Binary); +} + +TEST(ModTests, getOperatorPriorityTest) { + EXPECT_EQ(f.getOperatorPriority(), IOperator::Priority::Modulo); +} + +TEST(ModTests, isAssociativeTest) { + EXPECT_FALSE(f.isAssociative()); +} + +TEST(ModTests, callTest) { + EXPECT_EQ(f(Integer(0), Integer(2))->toString(), "0"); + EXPECT_EQ(f(Integer(0), Integer(-2))->toString(), "0"); + EXPECT_EQ(f(Integer(10), Integer(1))->toString(), "0"); + EXPECT_EQ(f(Integer(10), Integer(-1))->toString(), "0"); + EXPECT_EQ(f(Integer(-10), Integer(1))->toString(), "0"); + EXPECT_EQ(f(Integer(-10), Integer(-1))->toString(), "0"); + EXPECT_EQ(f(Integer(2), Integer(3))->toString(), "2"); + EXPECT_EQ(f(Integer(2), Integer(-3))->toString(), "-1"); + EXPECT_EQ(f(Integer(-2), Integer(3))->toString(), "1"); + EXPECT_EQ(f(Integer(-2), Integer(-3))->toString(), "-2"); + EXPECT_EQ(f(Integer(19), Integer(11))->toString(), "8"); + EXPECT_EQ(f(Integer(19), Integer(-11))->toString(), "-3"); + EXPECT_EQ(f(Integer(-19), Integer(11))->toString(), "3"); + EXPECT_EQ(f(Integer(-19), Integer(-11))->toString(), "-8"); + EXPECT_EQ(f(Integer(25), Integer(368273929))->toString(), "25"); + EXPECT_EQ(f(Integer(25), Integer(-368273929))->toString(), "-368273904"); + EXPECT_EQ(f(Integer(-25), Integer(368273929))->toString(), "368273904"); + EXPECT_EQ(f(Integer(-25), Integer(-368273929))->toString(), "-25"); + EXPECT_EQ(f(Integer(25), Integer(3))->toString(), "1"); + EXPECT_EQ(f(Integer(25), Integer(-3))->toString(), "-2"); + EXPECT_EQ(f(Integer(-25), Integer(3))->toString(), "2"); + EXPECT_EQ(f(Integer(-25), Integer(-3))->toString(), "-1"); + EXPECT_EQ(f(Integer(2000), Integer(36))->toString(), "20"); + EXPECT_EQ(f(Integer(2000), Integer(-36))->toString(), "-16"); + EXPECT_EQ(f(Integer(-2000), Integer(36))->toString(), "16"); + EXPECT_EQ(f(Integer(-2000), Integer(-36))->toString(), "-20"); + + EXPECT_EQ(f(Rational(5, 2), Rational(2, 3))->toString(), "(5/2) mod (2/3)"); + + EXPECT_EQ(f(Real("12.2"), Real("-12.2"))->toString(), "12.2 mod -12.2"); + + EXPECT_EQ(f(Complex(1, 1), Complex(2, 2))->toString(), "(1 + I) mod (2 + 2 I)"); + + EXPECT_EQ(f(Integer(1), Integer(0))->toString(), "Undefined"); + EXPECT_EQ(f(Rational(-1, 2), Integer(0))->toString(), "Undefined"); + EXPECT_EQ(f(Real("1.6"), Integer(0))->toString(), "Undefined"); + EXPECT_EQ(f(Complex(2, 2), Integer(0))->toString(), "Undefined"); + + EXPECT_EQ(f(Integer(3), Variable("a"))->toString(), "3 mod a"); + + EXPECT_THROW(f(Integer(1)), InvalidInputFunctionException); + EXPECT_THROW(f(Rational(2, 3)), InvalidInputFunctionException); + EXPECT_THROW(f(), InvalidInputFunctionException); + EXPECT_THROW(f(Integer(1), Integer(1), Integer(1)), InvalidInputFunctionException); +} + +TEST(ModTests, exprTest) { + EXPECT_EQ(modExpr(Integer(10), Integer(10))->toString(), "10 mod 10"); +} + +TEST(ModTests, doArgsMatchTest) { + Integer a; + + EXPECT_FALSE(f.doArgsMatch({})); + EXPECT_FALSE(f.doArgsMatch({a})); + EXPECT_TRUE(f.doArgsMatch({a, a})); + EXPECT_FALSE(f.doArgsMatch({a, a, a})); +} + +TEST(ModTests, equalsTest) { + EXPECT_EQ(f, f); + EXPECT_EQ(f, Mod()); + EXPECT_EQ(Mod(), f); + EXPECT_EQ(f, cast(Mod())); + EXPECT_EQ(cast(Mod()), f); + EXPECT_NE(f, Sub()); + EXPECT_NE(Sub(), f); + EXPECT_NE(f, UnaryPlus()); + EXPECT_NE(UnaryPlus(), f); +} + +TEST(ModTests, getTypeTest) { + EXPECT_EQ(Mod::getTypeStatic(), MathObjectType::Mod); + EXPECT_EQ(Mod().getType(), MathObjectType::Mod); +} diff --git a/tests/src/parser/ParserTests.cpp b/tests/src/parser/ParserTests.cpp index 2acf3301e..b7e3ab92e 100644 --- a/tests/src/parser/ParserTests.cpp +++ b/tests/src/parser/ParserTests.cpp @@ -43,6 +43,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/Factorial.hpp" #include "fintamath/functions/other/Index.hpp" @@ -243,6 +245,8 @@ TEST(ParserTests, parseFunctionTest) { EXPECT_TRUE(is(IFunction::parse("integral"))); EXPECT_TRUE(is(IFunction::parse("frac"))); EXPECT_TRUE(is(IFunction::parse("pow"))); + EXPECT_TRUE(is(IFunction::parse("floor"))); + EXPECT_TRUE(is(IFunction::parse("ceil"))); EXPECT_TRUE(is(IFunction::parse("+", IFunction::Type::Binary))); EXPECT_TRUE(is(IFunction::parse("+", IFunction::Type::Unary)));