From ed2aaf49454058fe5853dafcb32c185622d6537e Mon Sep 17 00:00:00 2001 From: fintarin Date: Mon, 31 Jul 2023 14:39:27 +0300 Subject: [PATCH] Implement logarithms simplify --- .../fintamath/functions/logarithms/Log.hpp | 11 ++ .../expressions/binary/LogExpression.cpp | 30 ++--- .../expressions/binary/LogExpression.hpp | 4 +- src/fintamath/functions/logarithms/Log.cpp | 123 +++++++++++++++++- .../expressions/ExpressionFunctionsTests.cpp | 6 +- tests/src/expressions/ExpressionTests.cpp | 63 +++++---- tests/src/functions/logarithms/LogTests.cpp | 42 +++++- tests/src/functions/powers/PowTests.cpp | 4 +- 8 files changed, 229 insertions(+), 54 deletions(-) diff --git a/include/fintamath/functions/logarithms/Log.hpp b/include/fintamath/functions/logarithms/Log.hpp index ac8fd19fb..7e448c96b 100644 --- a/include/fintamath/functions/logarithms/Log.hpp +++ b/include/fintamath/functions/logarithms/Log.hpp @@ -2,6 +2,9 @@ #include "fintamath/functions/IFunction.hpp" #include "fintamath/numbers/INumber.hpp" +#include "fintamath/numbers/Integer.hpp" +#include "fintamath/numbers/Rational.hpp" +#include "fintamath/numbers/Real.hpp" namespace fintamath { @@ -19,6 +22,14 @@ class Log : public IFunctionCRTP { protected: std::unique_ptr call(const ArgumentsRefVector &argsVect) const override; + + static std::unique_ptr multiLogSimpl(const INumber &lhs, const INumber &rhs); + + static std::unique_ptr logSimpl(const Integer &lhs, const Integer &rhs); + + static std::unique_ptr logSimpl(const Rational &lhs, const Rational &rhs); + + static std::unique_ptr logSimpl(const Real &lhs, const Real &rhs); }; } diff --git a/src/fintamath/expressions/binary/LogExpression.cpp b/src/fintamath/expressions/binary/LogExpression.cpp index e1e4e803e..53878024c 100644 --- a/src/fintamath/expressions/binary/LogExpression.cpp +++ b/src/fintamath/expressions/binary/LogExpression.cpp @@ -50,43 +50,35 @@ ArgumentPtr LogExpression::preciseSimplify() const { LogExpression::SimplifyFunctionsVector LogExpression::getFunctionsForPreSimplify() const { static const LogExpression::SimplifyFunctionsVector simplifyFunctions = { - &LogExpression::numSimplify, // - &LogExpression::equalSimplify, // - &LogExpression::powSimplify, // + &LogExpression::callFuncSimplify, // + &LogExpression::equalSimplify, // + &LogExpression::powSimplify, // }; return simplifyFunctions; } LogExpression::SimplifyFunctionsVector LogExpression::getFunctionsForPostSimplify() const { static const LogExpression::SimplifyFunctionsVector simplifyFunctions = { + &LogExpression::constSimplify, // &LogExpression::powSimplify, // - &LogExpression::numSimplify, // &LogExpression::equalSimplify, // }; return simplifyFunctions; } -ArgumentPtr LogExpression::numSimplify(const IFunction & /*func*/, const ArgumentPtr &lhs, const ArgumentPtr &rhs) { - if (*lhs == Integer(1)) { - throw UndefinedFunctionException(Log().toString(), {lhs->toString(), rhs->toString()}); +ArgumentPtr LogExpression::callFuncSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs) { + return callFunction(func, {lhs, rhs}); +} + +ArgumentPtr LogExpression::constSimplify(const IFunction & /*func*/, const ArgumentPtr &lhs, const ArgumentPtr &rhs) { + if (*rhs == Integer(1)) { + return Integer(0).clone(); } if (*lhs == E()) { return callFunction(Ln(), {rhs}); } - if (Log().doArgsMatch({*lhs, *rhs})) { - if (*lhs == Integer(2)) { - return callFunction(Lb(), {rhs}); - } - - if (*lhs == Integer(10)) { - return callFunction(Lg(), {rhs}); - } - - return callFunction(Log(), {lhs, rhs}); - } - return {}; } diff --git a/src/fintamath/expressions/binary/LogExpression.hpp b/src/fintamath/expressions/binary/LogExpression.hpp index c3a8704c9..da01eb4eb 100644 --- a/src/fintamath/expressions/binary/LogExpression.hpp +++ b/src/fintamath/expressions/binary/LogExpression.hpp @@ -24,7 +24,9 @@ class LogExpression : public IBinaryExpressionCRTP { SimplifyFunctionsVector getFunctionsForPostSimplify() const override; private: - static ArgumentPtr numSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); + static ArgumentPtr callFuncSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); + + static ArgumentPtr constSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); static ArgumentPtr equalSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); diff --git a/src/fintamath/functions/logarithms/Log.cpp b/src/fintamath/functions/logarithms/Log.cpp index 5d485491b..ff969acb3 100644 --- a/src/fintamath/functions/logarithms/Log.cpp +++ b/src/fintamath/functions/logarithms/Log.cpp @@ -1,11 +1,132 @@ #include "fintamath/functions/logarithms/Log.hpp" +#include "fintamath/exceptions/UndefinedException.hpp" +#include "fintamath/functions/arithmetic/Neg.hpp" +#include "fintamath/literals/constants/ComplexInf.hpp" +#include "fintamath/literals/constants/Inf.hpp" +#include "fintamath/literals/constants/NegInf.hpp" +#include "fintamath/literals/constants/Undefined.hpp" #include "fintamath/numbers/RealFunctions.hpp" namespace fintamath { std::unique_ptr Log::call(const ArgumentsRefVector &argsVect) const { - return log(convert(argsVect.front().get()), convert(argsVect.back().get())).toMinimalObject(); + const auto &lhs = cast(argsVect.front().get()); + const auto &rhs = cast(argsVect.back().get()); + + if (lhs == Integer(1)) { + if (rhs == Integer(1)) { + return Undefined().clone(); + } + + return ComplexInf().clone(); + } + + if (lhs < Integer(0) || rhs < Integer(0)) { + // TODO: cast to Complex, when it is implemented + throw UndefinedFunctionException(toString(), {lhs.toString(), rhs.toString()}); + } + + if (lhs == Integer(0)) { + if (rhs == Integer(0)) { + return Undefined().clone(); + } + + return Integer(0).clone(); + } + + if (rhs == Integer(0)) { + if (lhs > Integer(1)) { + return NegInf().clone(); + } + + return Inf().clone(); + } + + if (rhs == Integer(1)) { + return Integer(0).clone(); + } + + if (lhs == rhs) { + return Integer(1).clone(); + } + + if (lhs < Integer(1)) { + auto newLhs = Rational(1) / lhs; + + if (rhs < Integer(1)) { + auto newRhs = Rational(1) / rhs; + return multiLogSimpl(*newLhs, *newRhs); + } + + return Neg()(*multiLogSimpl(*newLhs, rhs)); + } + + if (rhs < Integer(1)) { + auto newRhs = Rational(1) / rhs; + return Neg()(*multiLogSimpl(lhs, *newRhs)); + } + + return multiLogSimpl(lhs, rhs); +} + +std::unique_ptr Log::multiLogSimpl(const INumber &lhs, const INumber &rhs) { + static const auto multiLog = [] { + static MultiMethod(const INumber &, const INumber &)> outMultiPow; + + outMultiPow.add([](const Integer &inLhs, const Integer &inRhs) { + return logSimpl(inLhs, inRhs); + }); + + outMultiPow.add([](const Rational &inLhs, const Rational &inRhs) { + return logSimpl(inLhs, inRhs); + }); + + outMultiPow.add([](const Real &inLhs, const Real &inRhs) { + return logSimpl(inLhs, inRhs); + }); + + return outMultiPow; + }(); + + if (auto rhsConv = cast(convert(lhs, rhs))) { + return multiLog(lhs, *rhsConv); + } + + auto lhsConv = cast(convert(rhs, lhs)); + return multiLog(*lhsConv, rhs); +} + +std::unique_ptr Log::logSimpl(const Integer &lhs, const Integer &rhs) { + return logSimpl(Rational(lhs), Rational(rhs)); +} + +std::unique_ptr Log::logSimpl(const Rational &lhs, const Rational &rhs) { + const bool isResInverted = lhs > rhs; + const Rational divider = isResInverted ? rhs : lhs; + Rational remainder = isResInverted ? lhs : rhs; + Rational res = 0; + + while (remainder > divider) { + res += 1; + remainder /= divider; + } + + if (remainder == divider) { + res += 1; + + if (isResInverted) { + return (Rational(1) / res).toMinimalObject(); + } + + return res.toMinimalObject(); + } + + return logSimpl(Real(lhs), Real(rhs)); +} + +std::unique_ptr Log::logSimpl(const Real &lhs, const Real &rhs) { + return log(lhs, rhs).toMinimalObject(); } } diff --git a/tests/src/expressions/ExpressionFunctionsTests.cpp b/tests/src/expressions/ExpressionFunctionsTests.cpp index db8359a06..deb1510c8 100644 --- a/tests/src/expressions/ExpressionFunctionsTests.cpp +++ b/tests/src/expressions/ExpressionFunctionsTests.cpp @@ -123,7 +123,7 @@ TEST(ExpressionFunctionsTests, expTest) { } TEST(ExpressionFunctionsTests, logTest) { - EXPECT_EQ(log(Expression("a+b"), Expression("1")).toString(), "log(a + b, 1)"); + EXPECT_EQ(log(Expression("a+b"), Expression("1")).toString(), "0"); EXPECT_EQ(log(Expression("2*a"), Expression("a+b")).toString(), "log(2 a, a + b)"); EXPECT_EQ(log(Expression("a"), Expression("a^5")).toString(), "5"); } @@ -134,8 +134,8 @@ TEST(ExpressionFunctionsTests, lnTest) { } TEST(ExpressionFunctionsTests, lbTest) { - EXPECT_EQ(lb(Expression("1024*a")).toString(), "log(2, 1024 a)"); // TODO logarithms - EXPECT_EQ(lb(Expression("2+a")).toString(), "log(2, a + 2)"); // TODO logarithms + EXPECT_EQ(lb(Expression("1024*a")).toString(), "log(2, 1024 a)"); + EXPECT_EQ(lb(Expression("2+a")).toString(), "log(2, a + 2)"); } TEST(ExpressionFunctionsTests, lgTest) { diff --git a/tests/src/expressions/ExpressionTests.cpp b/tests/src/expressions/ExpressionTests.cpp index 64fe178a9..bcac1a559 100644 --- a/tests/src/expressions/ExpressionTests.cpp +++ b/tests/src/expressions/ExpressionTests.cpp @@ -30,6 +30,8 @@ TEST(ExpressionTests, copyTest) { } TEST(ExpressionTests, stringConstructorTest) { + // TODO! split these tests + EXPECT_EQ(Expression("2").toString(), "2"); EXPECT_EQ(Expression("2 + 2").toString(), "4"); EXPECT_EQ(Expression(" 2 + 2 ").toString(), "4"); @@ -142,22 +144,6 @@ TEST(ExpressionTests, stringConstructorTest) { EXPECT_EQ(Expression("exp100").toString(), "E^100"); EXPECT_EQ(Expression("E^101").toString(), "E^101"); EXPECT_EQ(Expression("E^(-101)").toString(), "1/(E^101)"); - EXPECT_EQ(Expression("log(E,E)").toString(), "1"); - EXPECT_EQ(Expression("log(Pi, Pi^10)").toString(), "10"); - EXPECT_EQ(Expression("log(E,E^3)").toString(), "3"); - EXPECT_EQ(Expression("log((Pi),(E)^((Pi)))").toString(), "Pi log(Pi, E)"); - EXPECT_EQ(Expression("log(E^3, E)").toString(), "1/3"); - EXPECT_EQ(Expression("log(E^Pi, E)").toString(), "1/Pi"); - EXPECT_EQ(Expression("ln3").toString(), "ln(3)"); - EXPECT_EQ(Expression("ln2").toString(), "ln(2)"); - EXPECT_EQ(Expression("ln100").toString(), "ln(100)"); - EXPECT_EQ(Expression("ln(E)").toString(), "1"); - EXPECT_EQ(Expression("lg99").toString(), "log(10, 99)"); - EXPECT_EQ(Expression("lg100").toString(), "2"); - EXPECT_EQ(Expression("lb100").toString(), "log(2, 100)"); - EXPECT_EQ(Expression("lb4").toString(), "2"); - EXPECT_EQ(Expression("ln(ln(E))").toString(), "0"); - EXPECT_EQ(Expression("ln(E)!").toString(), "1"); EXPECT_EQ(Expression("sin10").toString(), "sin(10)"); EXPECT_EQ(Expression("cos10").toString(), "cos(10)"); EXPECT_EQ(Expression("tan10").toString(), "tan(10)"); @@ -188,7 +174,6 @@ TEST(ExpressionTests, stringConstructorTest) { EXPECT_EQ(Expression("sqrt((1-cos(2*(Pi/3)))/2)").toString(), "sqrt(-cos((2 Pi)/3)/2 + 1/2)"); EXPECT_EQ(Expression("2*sqrt((1-cos(2*(Pi/3)))/2)*cos(Pi/3)").toString(), "2 sqrt(-cos((2 Pi)/3)/2 + 1/2) cos(Pi/3)"); EXPECT_EQ(Expression("-sin(2)").toString(), "-sin(2)"); - EXPECT_EQ(Expression("log(2, 256)").toString(), "8"); EXPECT_EQ(Expression("2^(3/2)").toString(), "2 sqrt(2)"); EXPECT_EQ(Expression("sqrt(sqrt5)").toString(), "root(5, 4)"); EXPECT_EQ(Expression("sqrt4!").toString(), "2"); @@ -377,6 +362,33 @@ TEST(ExpressionTests, stringConstructorTest) { EXPECT_EQ(Expression("(x-1)/(x^(4/3) - x)").toString(), "(x - 1)/(x^(4/3) - x)"); EXPECT_EQ(Expression("(x-1)/(2 x^(4/3) - x)").toString(), "(x - 1)/(2 x^(4/3) - x)"); + EXPECT_EQ(Expression("log(2, 2)").toString(), "1"); + EXPECT_EQ(Expression("log(2, 256)").toString(), "8"); + EXPECT_EQ(Expression("log(3, 515377520732011331036461129765621272702107522001)").toString(), "100"); + EXPECT_EQ(Expression("log(515377520732011331036461129765621272702107522001, 3)").toString(), "1/100"); + EXPECT_EQ(Expression("log(2/3, 4/9)").toString(), "2"); + EXPECT_EQ(Expression("log(9/4, 3/2)").toString(), "1/2"); + EXPECT_EQ(Expression("log(4/9, 2/3)").toString(), "1/2"); + EXPECT_EQ(Expression("log(4/11, 2/3)").toString(), "log(4/11, 2/3)"); + EXPECT_EQ(Expression("ln1").toString(), "0"); + EXPECT_EQ(Expression("ln3").toString(), "ln(3)"); + EXPECT_EQ(Expression("ln2").toString(), "ln(2)"); + EXPECT_EQ(Expression("ln100").toString(), "ln(100)"); + EXPECT_EQ(Expression("ln(E)").toString(), "1"); + EXPECT_EQ(Expression("lg99").toString(), "log(10, 99)"); + EXPECT_EQ(Expression("lg100").toString(), "2"); + EXPECT_EQ(Expression("lb100").toString(), "log(2, 100)"); + EXPECT_EQ(Expression("lb4").toString(), "2"); + EXPECT_EQ(Expression("ln(ln(E))").toString(), "0"); + EXPECT_EQ(Expression("ln(E)!").toString(), "1"); + EXPECT_EQ(Expression("log(0, 1)").toString(), "0"); + EXPECT_EQ(Expression("log(E,E)").toString(), "1"); + EXPECT_EQ(Expression("log(Pi, Pi^10)").toString(), "10"); + EXPECT_EQ(Expression("log(E,E^3)").toString(), "3"); + EXPECT_EQ(Expression("log((Pi),(E)^((Pi)))").toString(), "Pi log(Pi, E)"); + EXPECT_EQ(Expression("log(E^3, E)").toString(), "1/3"); + EXPECT_EQ(Expression("log(E^Pi, E)").toString(), "1/Pi"); + // TODO! implement this // EXPECT_EQ(Expression("sqrt(x^2)").toString(), "abs(x)"); // EXPECT_EQ(Expression("(x^10)^(1/10))").toString(), "abs(x)"); @@ -722,6 +734,10 @@ TEST(ExpressionTests, stringConstructorTest) { EXPECT_EQ(Expression("x = -Inf").toString(), "False"); EXPECT_EQ(Expression("Inf = Inf").toString(), "True"); EXPECT_EQ(Expression("Inf = -Inf").toString(), "False"); + EXPECT_EQ(Expression("log(1, 0)").toString(), "ComplexInf"); + EXPECT_EQ(Expression("log(1, 10)").toString(), "ComplexInf"); + EXPECT_EQ(Expression("log(10, 0)").toString(), "-Inf"); + EXPECT_EQ(Expression("log(1/10, 0)").toString(), "Inf"); EXPECT_EQ(Expression("0*Inf").toString(), "Undefined"); EXPECT_EQ(Expression("0*-Inf").toString(), "Undefined"); @@ -770,6 +786,8 @@ TEST(ExpressionTests, stringConstructorTest) { EXPECT_EQ(Expression("ComplexInf = -Inf").toString(), "Undefined"); EXPECT_EQ(Expression("Inf = ComplexInf").toString(), "Undefined"); EXPECT_EQ(Expression("-Inf = ComplexInf").toString(), "Undefined"); + EXPECT_EQ(Expression("log(1, 1)").toString(), "Undefined"); + EXPECT_EQ(Expression("log(0, 0)").toString(), "Undefined"); EXPECT_EQ(Expression("Undefined").toString(), "Undefined"); EXPECT_EQ(Expression("-Undefined").toString(), "Undefined"); @@ -1051,21 +1069,14 @@ TEST(ExpressionTests, stringConstructorNegativeTest) { EXPECT_THROW(Expression("(-1)!!"), UndefinedException); EXPECT_THROW(Expression("(2/3)!!"), UndefinedException); EXPECT_THROW(Expression("sqrt(-1)"), UndefinedException); - EXPECT_THROW(Expression("ln(0)"), UndefinedException); - EXPECT_THROW(Expression("ln(-1)"), UndefinedException); - EXPECT_THROW(Expression("log(-1, 1)"), UndefinedException); - EXPECT_THROW(Expression("log(0, 1)"), UndefinedException); - EXPECT_THROW(Expression("log(1, 0)"), UndefinedException); - EXPECT_THROW(Expression("lb(-1)"), UndefinedException); - EXPECT_THROW(Expression("lg(-1)"), UndefinedException); EXPECT_THROW(Expression("sqrt(-1)"), UndefinedException); EXPECT_THROW(Expression("(-1)^(2/3)"), UndefinedException); EXPECT_THROW(Expression("ln(0)"), UndefinedException); EXPECT_THROW(Expression("ln(-1)"), UndefinedException); EXPECT_THROW(Expression("log(-1, 1)"), UndefinedException); - EXPECT_THROW(Expression("log(0, 1)"), UndefinedException); - EXPECT_THROW(Expression("log(1, 0)"), UndefinedException); EXPECT_THROW(Expression("lb(-1)"), UndefinedException); + EXPECT_THROW(Expression("lg(-1)"), UndefinedException); + EXPECT_THROW(Expression("log(-1, 1)"), UndefinedException); // TODO constants // EXPECT_THROW(Expression("E!"), UndefinedException); // EXPECT_THROW(Expression("tan(Pi/2)"), UndefinedException); diff --git a/tests/src/functions/logarithms/LogTests.cpp b/tests/src/functions/logarithms/LogTests.cpp index d32c4ca1a..e3ed4f48b 100644 --- a/tests/src/functions/logarithms/LogTests.cpp +++ b/tests/src/functions/logarithms/LogTests.cpp @@ -22,16 +22,54 @@ TEST(LogTests, getFunctionTypeTest) { TEST(LogTests, callTest) { EXPECT_EQ(f(Integer(10), Integer(1))->toString(), "0"); + EXPECT_EQ(f(Integer(0), Integer(10))->toString(), "0"); + + EXPECT_EQ(f(Integer(10), Integer(10))->toString(), "1"); + EXPECT_EQ(f(Integer(10), Rational(1, 10))->toString(), "-1"); + EXPECT_EQ(f(Rational(1, 10), Integer(10))->toString(), "-1"); + EXPECT_EQ(f(Rational(1, 10), Rational(1, 10))->toString(), "1"); + + EXPECT_EQ(f(Integer(11), Integer(11))->toString(), "1"); + EXPECT_EQ(f(Integer(11), Rational(1, 11))->toString(), "-1"); + EXPECT_EQ(f(Rational(1, 11), Integer(11))->toString(), "-1"); + EXPECT_EQ(f(Rational(1, 11), Rational(1, 11))->toString(), "1"); + + EXPECT_EQ(f(Integer(10), Integer("10000000000000000000000000000000000000000000000000000000000"))->toString(), "58"); + EXPECT_EQ(f(Integer("10000000000000000000000000000000000000000000000000000000000"), Integer(10))->toString(), "1/58"); + + EXPECT_EQ(f(Integer(121), Integer(11))->toString(), "1/2"); + EXPECT_EQ(f(Rational(1, 11), Integer(121))->toString(), "-2"); + EXPECT_EQ(f(Rational(1, 121), Integer(11))->toString(), "-1/2"); + EXPECT_EQ(f(Integer(121), Rational(1, 11))->toString(), "-1/2"); + EXPECT_EQ(f(Integer(11), Rational(1, 121))->toString(), "-2"); + + EXPECT_EQ(f(Rational(7, 9), Rational(40353607, 387420489))->toString(), "9"); + EXPECT_EQ(f(Rational(40353607, 387420489), Rational(7, 9))->toString(), "1/9"); + EXPECT_EQ(f(Rational(387420489, 40353607), Rational(7, 9))->toString(), "-1/9"); + EXPECT_EQ(f(Integer(2), Integer(10))->toString(), "3.3219280948873623478703194294893901758648313930245806120547563958159347766086252"); EXPECT_EQ(f(Integer(2), Integer(3))->toString(), "1.5849625007211561814537389439478165087598144076924810604557526545410982277943586"); - EXPECT_EQ(f(Rational(1, 10), Integer(10))->toString(), "-1"); + EXPECT_EQ(f(Integer(10), Real(121))->toString(), + "2.0827853703164500815003999424860484834134043809329061891930780373595060644664987"); + EXPECT_EQ(f(Real(121), Integer(10))->toString(), + "0.4801262838945637487030558225096301948381401591993519366116255938360392246042024"); + EXPECT_EQ(f(1 / Real(121), Integer(10))->toString(), + "-0.4801262838945637487030558225096301948381401591993519366116255938360392246042024"); + EXPECT_EQ(f(Integer(10), 1 / Real(121))->toString(), + "-2.0827853703164500815003999424860484834134043809329061891930780373595060644664987"); + + EXPECT_EQ(f(Integer(10), Integer(0))->toString(), "-Inf"); + EXPECT_EQ(f(Rational(1, 10), Integer(0))->toString(), "Inf"); + EXPECT_EQ(f(Integer(1), Integer(10))->toString(), "ComplexInf"); + EXPECT_EQ(f(Integer(1), Integer(1))->toString(), "Undefined"); + EXPECT_EQ(f(Integer(0), Integer(0))->toString(), "Undefined"); EXPECT_EQ(f(Variable("a"), Variable("b"))->toString(), "log(a, b)"); EXPECT_THROW(f(Integer(-10), Integer(10)), UndefinedFunctionException); - EXPECT_THROW(f(Integer(1), Integer(10)), UndefinedFunctionException); + EXPECT_THROW(f(Integer(10), Integer(-10)), UndefinedFunctionException); EXPECT_THROW(f(), InvalidInputFunctionException); EXPECT_THROW(f(Integer(10)), InvalidInputFunctionException); diff --git a/tests/src/functions/powers/PowTests.cpp b/tests/src/functions/powers/PowTests.cpp index 331b776e4..933e74cf7 100644 --- a/tests/src/functions/powers/PowTests.cpp +++ b/tests/src/functions/powers/PowTests.cpp @@ -75,12 +75,12 @@ TEST(PowTests, callTest) { EXPECT_EQ(f(Real("2.2"), Real("0.5"))->toString(), "1.48323969741913258974227948816014261219598086381950031974652465286876603686277"); + EXPECT_EQ(f(Integer(0), Integer(0))->toString(), "Undefined"); + EXPECT_EQ(f(Integer(3), Variable("a"))->toString(), "3^a"); EXPECT_EQ(f(Variable("a"), Rational(1, 2))->toString(), "sqrt(a)"); EXPECT_EQ(f(Variable("a"), Rational(3, 2))->toString(), "a^(3/2)"); - EXPECT_EQ(f(Integer(0), Integer(0))->toString(), "Undefined"); - EXPECT_THROW(f(Rational("0"), Rational("-10")), UndefinedException); EXPECT_THROW(f(Rational("-10"), Rational("-1.5")), UndefinedException);