diff --git a/include/fintamath/functions/powers/Pow.hpp b/include/fintamath/functions/powers/Pow.hpp index 8c58012c6..22878cc34 100644 --- a/include/fintamath/functions/powers/Pow.hpp +++ b/include/fintamath/functions/powers/Pow.hpp @@ -5,6 +5,10 @@ namespace fintamath { +class Integer; +class Rational; +class Real; + class Pow : public IOperatorCRTP { public: Pow() : IOperatorCRTP(IOperator::Priority::Exponentiation, false) { @@ -20,6 +24,12 @@ class Pow : public IOperatorCRTP { protected: std::unique_ptr call(const ArgumentsRefVector &argsVect) const override; + + static std::unique_ptr powSimpl(const Integer &lhs, const Integer &rhs); + + static std::unique_ptr powSimpl(const Rational &lhs, const Rational &rhs); + + static std::unique_ptr powSimpl(const Real &lhs, const Real &rhs); }; } diff --git a/include/fintamath/functions/powers/Root.hpp b/include/fintamath/functions/powers/Root.hpp new file mode 100644 index 000000000..f6809e281 --- /dev/null +++ b/include/fintamath/functions/powers/Root.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "fintamath/functions/IFunction.hpp" +#include "fintamath/numbers/INumber.hpp" + +namespace fintamath { + +class Integer; +class Rational; +class Real; + +class Root : public IFunctionCRTP { +public: + Root() = default; + + std::string toString() const override { + return "root"; + } + +protected: + std::unique_ptr call(const ArgumentsRefVector &argsVect) const override; + +private: + static std::unique_ptr rootSimpl(const Integer &lhs, const Integer &rhs); + + static std::unique_ptr rootSimpl(const Rational &lhs, const Integer &rhs); + + static std::unique_ptr rootSimpl(const Real &lhs, const Integer &rhs); + + static std::map roots(const Integer &lhs, const Integer &rhs); + + static std::unique_ptr perfectRoot(const Integer &lhs, const Integer &rhs); +}; + +} diff --git a/include/fintamath/numbers/IntegerFunctions.hpp b/include/fintamath/numbers/IntegerFunctions.hpp index 48d6c7b72..c84f81192 100644 --- a/include/fintamath/numbers/IntegerFunctions.hpp +++ b/include/fintamath/numbers/IntegerFunctions.hpp @@ -48,6 +48,8 @@ Integer factorial(const Integer &rhs); Integer factorial(const Integer &rhs, size_t order); +std::map factors(Integer rhs, Integer limit = -1); + Integer combinations(const Integer &totalNumber, const Integer &choosedNumber); Integer multinomialCoefficient(const Integer &totalNumber, const std::vector &groupNumbers); diff --git a/src/fintamath/config/ExpressionConfig.cpp b/src/fintamath/config/ExpressionConfig.cpp index ae187a78e..cf29f53c6 100644 --- a/src/fintamath/config/ExpressionConfig.cpp +++ b/src/fintamath/config/ExpressionConfig.cpp @@ -54,6 +54,7 @@ #include "fintamath/functions/other/Percent.hpp" #include "fintamath/functions/powers/Exp.hpp" #include "fintamath/functions/powers/Pow.hpp" +#include "fintamath/functions/powers/Root.hpp" #include "fintamath/functions/powers/Sqrt.hpp" #include "fintamath/functions/trigonometry/Acos.hpp" #include "fintamath/functions/trigonometry/Acot.hpp" @@ -291,6 +292,14 @@ struct ExpressionConfig { return makeExpr(Pow(), args.front(), std::make_shared(1, 2)); }); + Expression::registerFunctionExpressionMaker([](const ArgumentsPtrVector &args) { + if (const auto num = cast(args.back())) { + return makeExpr(Pow(), args.front(), Integer(1) / (*num)); + } + + return makeExpr(Pow(), args.front(), makeExpr(Div(), std::make_shared(1), args.back())); + }); + Expression::registerFunctionExpressionMaker([](const ArgumentsPtrVector &args) { return std::make_unique(Sin(), args.front()); }); diff --git a/src/fintamath/config/ParserConfig.cpp b/src/fintamath/config/ParserConfig.cpp index f85b0b114..ed8e1a7ba 100644 --- a/src/fintamath/config/ParserConfig.cpp +++ b/src/fintamath/config/ParserConfig.cpp @@ -46,6 +46,7 @@ #include "fintamath/functions/other/Percent.hpp" #include "fintamath/functions/powers/Exp.hpp" #include "fintamath/functions/powers/Pow.hpp" +#include "fintamath/functions/powers/Root.hpp" #include "fintamath/functions/powers/Sqrt.hpp" #include "fintamath/functions/trigonometry/Acos.hpp" #include "fintamath/functions/trigonometry/Acot.hpp" @@ -171,6 +172,7 @@ struct ParserConfig { IFunction::registerType(); IFunction::registerType(); IFunction::registerType(); + IFunction::registerType(); IFunction::registerType(); IFunction::registerType(); IFunction::registerType(); diff --git a/src/fintamath/expressions/binary/PowExpression.cpp b/src/fintamath/expressions/binary/PowExpression.cpp index 10f64db44..d4c341328 100644 --- a/src/fintamath/expressions/binary/PowExpression.cpp +++ b/src/fintamath/expressions/binary/PowExpression.cpp @@ -7,6 +7,7 @@ #include "fintamath/functions/arithmetic/Mul.hpp" #include "fintamath/functions/arithmetic/Neg.hpp" #include "fintamath/functions/powers/Pow.hpp" +#include "fintamath/functions/powers/Root.hpp" #include "fintamath/functions/powers/Sqrt.hpp" #include "fintamath/numbers/Integer.hpp" #include "fintamath/numbers/IntegerFunctions.hpp" @@ -23,13 +24,12 @@ std::string PowExpression::toString() const { const Integer &numerator = val->numerator(); const Integer &denominator = val->denominator(); - if (denominator == 2) { - if (numerator == 1) { + if (numerator == 1) { + if (denominator == 2) { return functionToString(Sqrt(), {lhsChild}); } - PowExpression res(std::make_shared(lhsChild, Rational(1, 2).clone()), numerator.clone()); - return res.IBinaryExpression::toString(); + return functionToString(Root(), {lhsChild, denominator.clone()}); } } @@ -45,7 +45,9 @@ std::shared_ptr PowExpression::getOutputFunction() const { } ArgumentPtr PowExpression::preciseSimplify() const { - if (*rhsChild == Rational(1, 2)) { + static const int64_t maxPreciseRoot = 9; + + if (const auto ratRhsChild = cast(rhsChild); ratRhsChild && ratRhsChild->denominator() <= maxPreciseRoot) { auto preciseExpr = cast(clone()); preciseSimplifyChild(preciseExpr->lhsChild); return preciseExpr; @@ -236,5 +238,4 @@ ArgumentPtr PowExpression::sumSimplify(const ArgumentPtr &lhs, const ArgumentPtr return {}; } - } diff --git a/src/fintamath/functions/arithmetic/Abs.cpp b/src/fintamath/functions/arithmetic/Abs.cpp index 4d59c98b1..85ac98e2e 100644 --- a/src/fintamath/functions/arithmetic/Abs.cpp +++ b/src/fintamath/functions/arithmetic/Abs.cpp @@ -28,9 +28,7 @@ std::unique_ptr Abs::call(const ArgumentsRefVector &argsVect) const return outMultiAbs; }(); - const auto &rhs = cast(argsVect.front().get()); - - return multiAbs(rhs); + return multiAbs(cast(argsVect.front().get())); } } diff --git a/src/fintamath/functions/powers/Pow.cpp b/src/fintamath/functions/powers/Pow.cpp index da92b22c7..ec0568dd5 100644 --- a/src/fintamath/functions/powers/Pow.cpp +++ b/src/fintamath/functions/powers/Pow.cpp @@ -1,5 +1,6 @@ #include "fintamath/functions/powers/Pow.hpp" +#include "fintamath/functions/powers/Root.hpp" #include "fintamath/functions/powers/Sqrt.hpp" #include "fintamath/numbers/Integer.hpp" #include "fintamath/numbers/IntegerFunctions.hpp" @@ -14,30 +15,15 @@ std::unique_ptr Pow::call(const ArgumentsRefVector &argsVect) const static MultiMethod(const INumber &, const INumber &)> outMultiPow; outMultiPow.add([](const Integer &lhs, const Integer &rhs) { - if (rhs < 0) { - return (Rational(1) / pow(lhs, -rhs)).toMinimalObject(); - } - - return pow(lhs, rhs).toMinimalObject(); + return powSimpl(lhs, rhs); }); outMultiPow.add([](const Rational &lhs, const Rational &rhs) { - const Integer &numerator = rhs.numerator(); - const Integer &denominator = rhs.denominator(); - - if (denominator == 1) { - return pow(lhs, numerator).toMinimalObject(); - } - - if (denominator == 2) { // TODO: implement nth root - return Pow()(*Sqrt()(lhs), numerator); - } - - return pow(convert(lhs), convert(rhs)).toMinimalObject(); + return powSimpl(lhs, rhs); }); outMultiPow.add([](const Real &lhs, const Real &rhs) { - return pow(lhs, rhs).toMinimalObject(); + return powSimpl(lhs, rhs); }); return outMultiPow; @@ -46,6 +32,10 @@ std::unique_ptr Pow::call(const ArgumentsRefVector &argsVect) const const auto &lhs = cast(argsVect.front().get()); const auto &rhs = cast(argsVect.back().get()); + if (rhs < Integer(0)) { + return Pow()(*(Rational(1) / lhs), *(-rhs)); + } + if (auto rhsConv = cast(convert(lhs, rhs))) { return multiPow(lhs, *rhsConv); } @@ -54,4 +44,38 @@ std::unique_ptr Pow::call(const ArgumentsRefVector &argsVect) const return multiPow(*lhsConv, rhs); } +std::unique_ptr Pow::powSimpl(const Integer &lhs, const Integer &rhs) { + return pow(lhs, rhs).toMinimalObject(); +} + +std::unique_ptr Pow::powSimpl(const Rational &lhs, const Rational &rhs) { + const Integer &lhsNumerator = lhs.numerator(); + const Integer &lhsDenominator = lhs.denominator(); + + const Integer &rhsNumerator = rhs.numerator(); + const Integer &rhsDenominator = rhs.denominator(); + + if (rhsDenominator == 1) { + if (lhsDenominator == 1) { + return pow(lhsNumerator, rhsNumerator).toMinimalObject(); + } + + return pow(lhs, rhsNumerator).toMinimalObject(); + } + + if (lhs < Integer(0)) { + throw UndefinedBinaryOperatorException(Pow().toString(), lhs.toString(), rhs.toString()); + } + + if (lhsDenominator == 1) { + return Root()(*Pow()(lhsNumerator, rhsNumerator), rhsDenominator); + } + + return Root()(*Pow()(lhs, rhsNumerator), rhsDenominator); +} + +std::unique_ptr Pow::powSimpl(const Real &lhs, const Real &rhs) { + return pow(lhs, rhs).toMinimalObject(); +} + } diff --git a/src/fintamath/functions/powers/Root.cpp b/src/fintamath/functions/powers/Root.cpp new file mode 100644 index 000000000..863f658db --- /dev/null +++ b/src/fintamath/functions/powers/Root.cpp @@ -0,0 +1,145 @@ +#include "fintamath/functions/powers/Root.hpp" + +#include "fintamath/functions/arithmetic/Add.hpp" +#include "fintamath/functions/arithmetic/Div.hpp" +#include "fintamath/functions/arithmetic/Mul.hpp" +#include "fintamath/functions/powers/Pow.hpp" +#include "fintamath/numbers/Integer.hpp" +#include "fintamath/numbers/IntegerFunctions.hpp" +#include "fintamath/numbers/Rational.hpp" +#include "fintamath/numbers/Real.hpp" +#include "fintamath/numbers/RealFunctions.hpp" + +namespace fintamath { + +std::unique_ptr Root::call(const ArgumentsRefVector &argsVect) const { + static const auto multiRoot = [] { + static MultiMethod(const INumber &, const INumber &)> outMultiRoot; + + outMultiRoot.add([](const Integer &lhs, const Integer &rhs) { + return rootSimpl(lhs, rhs); + }); + + outMultiRoot.add([](const Rational &lhs, const Integer &rhs) { + return rootSimpl(lhs, rhs); + }); + + outMultiRoot.add([](const Real &lhs, const Integer &rhs) { + return rootSimpl(lhs, rhs); + }); + + return outMultiRoot; + }(); + + const auto &lhs = cast(argsVect.front().get()); + const auto &rhs = cast(argsVect.back().get()); + + if (lhs == Integer(1)) { + return lhs.clone(); + } + + if (const auto *rhsIntPtr = cast(&rhs)) { + const auto &rhsInt = *rhsIntPtr; + + if (rhsInt > Integer(1)) { + // TODO: cast to Complex, when it is implemented + if (lhs < Integer(0)) { + throw UndefinedFunctionException(toString(), {lhs.toString(), rhs.toString()}); + } + + return multiRoot(lhs, rhsInt); + } + } + + return Pow()(lhs, *(Rational(1) / rhs)); +} + +std::unique_ptr Root::rootSimpl(const Integer &lhs, const Integer &rhs) { + if (auto res = perfectRoot(lhs, rhs)) { + return res; + } + + ArgumentsPtrVector mulChildren; + + std::map rootFactors = roots(lhs, rhs); + auto rootFactorIter = rootFactors.begin(); + + if (rootFactorIter->first == 1) { + if (rootFactorIter->second != 1) { + mulChildren.emplace_back(rootFactorIter->second.clone()); + } + + rootFactorIter++; + } + + for (; rootFactorIter != rootFactors.end(); rootFactorIter++) { + Integer root = rootFactorIter->first; + Integer factor = rootFactorIter->second; + + if (factor != 1) { + mulChildren.emplace_back(makeExpr(Root(), factor, root)); + } + } + + if (mulChildren.size() == 1) { + return mulChildren.front()->clone(); + } + + return makeExpr(Mul(), mulChildren); +} + +std::map Root::roots(const Integer &lhs, const Integer &rhs) { + static Integer factorLimit = pow(Integer(2), 15); + + std::map rootFactors{{1, 1}}; + std::map factorRates = factors(lhs, factorLimit); + + for (const auto &factorRate : factorRates) { + Rational power(factorRate.second, rhs); + Integer factor = factorRate.first; + + if (power.denominator() == 1) { + rootFactors[1] *= pow(factor, power.numerator()); + continue; + } + + if (power.numerator() > power.denominator()) { + rootFactors[1] *= pow(factor, power.numerator() / power.denominator()); + } + + factor = pow(factor, power.numerator() % power.denominator()); + + if (auto rootIter = rootFactors.find(power.denominator()); rootIter != rootFactors.end()) { + rootIter->second *= factor; + } + else { + rootFactors.insert({power.denominator(), factor}); + } + } + + return rootFactors; +} + +std::unique_ptr Root::perfectRoot(const Integer &lhs, const Integer &rhs) { + if (rhs == 2) { // TODO: implement perfect nth-roots minimization + Integer remainder; + Integer lhsSqrt = sqrt(lhs, remainder); + + if (remainder == 0) { + return lhsSqrt.clone(); + } + } + + return {}; +} + +std::unique_ptr Root::rootSimpl(const Rational &lhs, const Integer &rhs) { + return makeExpr(Div(), makeExpr(Root(), lhs.numerator(), rhs), makeExpr(Root(), lhs.denominator(), rhs)) + ->toMinimalObject(); +} + +std::unique_ptr Root::rootSimpl(const Real &lhs, const Integer &rhs) { + return Pow()(lhs, 1 / Rational(rhs)); +} + +} diff --git a/src/fintamath/functions/powers/Sqrt.cpp b/src/fintamath/functions/powers/Sqrt.cpp index 83635ffe8..e67eb8d2d 100644 --- a/src/fintamath/functions/powers/Sqrt.cpp +++ b/src/fintamath/functions/powers/Sqrt.cpp @@ -1,5 +1,6 @@ #include "fintamath/functions/powers/Sqrt.hpp" +#include "fintamath/functions/powers/Root.hpp" #include "fintamath/numbers/Integer.hpp" #include "fintamath/numbers/IntegerFunctions.hpp" #include "fintamath/numbers/Rational.hpp" @@ -9,46 +10,7 @@ namespace fintamath { std::unique_ptr Sqrt::call(const ArgumentsRefVector &argsVect) const { - static const auto multiSqrt = [] { - static MultiMethod(const INumber &)> outMultiSqrt; - - outMultiSqrt.add([](const Integer &rhs) { - Integer remainder; - - auto res = std::make_unique(sqrt(rhs, remainder)); - if (remainder == 0) { - return res->toMinimalObject(); - } - - return sqrt(convert(rhs)).toMinimalObject(); - }); - - outMultiSqrt.add([](const Rational &rhs) { - Integer remainder; - - Integer numerator = sqrt(rhs.numerator(), remainder); - if (remainder != 0) { - return sqrt(convert(rhs)).toMinimalObject(); - } - - Integer denominator = sqrt(rhs.denominator(), remainder); - if (remainder != 0) { - return sqrt(convert(rhs)).toMinimalObject(); - } - - return Rational(numerator, denominator).toMinimalObject(); - }); - - outMultiSqrt.add([](const Real &rhs) { - return std::make_unique(sqrt(rhs)); - }); - - return outMultiSqrt; - }(); - - const auto &rhs = cast(argsVect.front().get()); - - return multiSqrt(rhs); + return Root()(argsVect.front().get(), Integer(2)); } } diff --git a/src/fintamath/numbers/IntegerFunctions.cpp b/src/fintamath/numbers/IntegerFunctions.cpp index 35822c763..3891d615f 100644 --- a/src/fintamath/numbers/IntegerFunctions.cpp +++ b/src/fintamath/numbers/IntegerFunctions.cpp @@ -86,6 +86,40 @@ Integer factorial(const Integer &rhs, size_t order) { return res; } +std::map factors(Integer rhs, Integer limit) { + if (rhs < 2) { + throw UndefinedFunctionException("factors", {rhs.toString()}); + } + + std::map factorRates; + + while (rhs % 2 == 0) { + factorRates[2]++; + rhs /= 2; + } + + { + Integer rhsSqrt = sqrt(rhs); + + if (limit < 0 || limit > rhsSqrt) { + limit = rhsSqrt; + } + } + + for (Integer i = 3; i <= limit; i += 2) { + while (rhs % i == 0) { + factorRates[i]++; + rhs = rhs / i; + } + } + + if (rhs > 1) { + factorRates[rhs]++; + } + + return factorRates; +} + // Use number of combinations formula. // https://en.wikipedia.org/wiki/Combination#Number_of_k-combinations. Integer combinations(const Integer &totalNumber, const Integer &choosedNumber) { diff --git a/tests/src/FintamathTests.cpp b/tests/src/FintamathTests.cpp index 99763d93a..402d09cee 100644 --- a/tests/src/FintamathTests.cpp +++ b/tests/src/FintamathTests.cpp @@ -35,13 +35,11 @@ TEST(FintamathTests, fintamathTests) { expr = log(2, 256) + ln(pow(E(), 2)); EXPECT_EQ(expr.toString(), "10"); - // TODO: power simplify - // expr = sqrt(Expression(8)); - // EXPECT_EQ(expr.toString(), "2 sqrt(2)"); + expr = sqrt(Expression(8)); + EXPECT_EQ(expr.toString(), "2 sqrt(2)"); - // TODO: power simplify - // expr = root(Integer("244706656946119777797996531655819747089832578"), 4); - // EXPECT_EQ(expr.toString(), "sqrt(11) root(2022369065670411386760301914510907000742418, 4)"); + expr = pow(Expression("244706656946119777797996531655819747089832578"), Rational(1, 4)); + EXPECT_EQ(expr.toString(), "root(2022369065670411386760301914510907000742418, 4) sqrt(11)"); expr = Expression("(4x^4 + 1 + 3x^3 + 2x) / (x^2 + x + 2)"); EXPECT_EQ(expr.toString(), "4 x^2 - x - 7 + (11 x + 15)/(x^2 + x + 2)"); diff --git a/tests/src/expressions/ExpressionFunctionsTests.cpp b/tests/src/expressions/ExpressionFunctionsTests.cpp index 1644246d6..6be38965e 100644 --- a/tests/src/expressions/ExpressionFunctionsTests.cpp +++ b/tests/src/expressions/ExpressionFunctionsTests.cpp @@ -232,11 +232,12 @@ TEST(ExpressionFunctionsTests, solveTest) { EXPECT_EQ(solve(Expression("x^2 + 12x + 36 = 0")).toString(), "x = -6"); EXPECT_EQ(solve(Expression("x^2 + 12x = 0")).toString(), "x = -12 | x = 0"); EXPECT_EQ(solve(Expression("x^2 - 23x - 3 = 0")).toString(), "x = -1/2 sqrt(541) + 23/2 | x = 1/2 sqrt(541) + 23/2"); + // TODO! x = -sqrt(1969)/24 - 23/24 | x = sqrt(1969)/24 - 23/24 EXPECT_EQ(solve(Expression("-12x^2 - 23x + 30 = 0")).toString(), - "x = -1/2 sqrt(1969/144) - 23/24 | x = 1/2 sqrt(1969/144) - 23/24"); + "x = -1/24 sqrt(1969) - 23/24 | x = 1/24 sqrt(1969) - 23/24"); EXPECT_EQ(solve(Expression("-33x^2 - x + 34 = 0")).toString(), "x = -34/33 | x = 1"); EXPECT_EQ(solve(Expression("2x^2 + 2sqrt(2)x + 1 = 0")).toString(), - "x = -1/4 sqrt(2)^3"); // TODO: x = -1/sqrt(2) + "x = -1/2 sqrt(2)"); // TODO! x = -sqrt(2)/2 // TODO: implement cubic equations EXPECT_EQ(solve(Expression("x^3 - 3x^2 + 3x - 1 = 0")).toString(), "x^3 - 3 x^2 + 3 x - 1 = 0"); // TODO: x = 1 @@ -271,7 +272,7 @@ TEST(ExpressionFunctionsTests, solveTest) { EXPECT_EQ(solve(Expression("x^2 - 2*sin(2) = 0")).toString(), "x = -sqrt(2) sqrt(sin(2)) | x = sqrt(2) sqrt(sin(2))"); EXPECT_EQ(solve(Expression("E >= Ey")).toString(), "E y - E <= 0"); - EXPECT_EQ(solve(Expression("x >= x sqrt(x)")).toString(), "sqrt(x)^3 - x <= 0"); - EXPECT_EQ(solve(Expression("x >= x^(1/100)")).toString(), "x^(1/100) - x <= 0"); + EXPECT_EQ(solve(Expression("x >= x sqrt(x)")).toString(), "x^(3/2) - x <= 0"); + EXPECT_EQ(solve(Expression("x >= x^(1/100)")).toString(), "root(x, 100) - x <= 0"); EXPECT_EQ(solve(Expression("E^Pi > Pi^E")).toString(), "E^Pi - Pi^E > 0"); } diff --git a/tests/src/expressions/ExpressionTests.cpp b/tests/src/expressions/ExpressionTests.cpp index 0cf846489..fdf69f3eb 100644 --- a/tests/src/expressions/ExpressionTests.cpp +++ b/tests/src/expressions/ExpressionTests.cpp @@ -115,12 +115,20 @@ TEST(ExpressionTests, stringConstructorTest) { EXPECT_EQ(Expression("sqrt0").toString(), "0"); EXPECT_EQ(Expression("sqrt(25)").toString(), "5"); EXPECT_EQ(Expression("sqrt(144/25)").toString(), "12/5"); - EXPECT_EQ(Expression("sqrt4!").toString(), "2"); - EXPECT_EQ(Expression("(sqrt4)!").toString(), "2"); - EXPECT_EQ(Expression("sqrt4*2!").toString(), "4"); - EXPECT_EQ(Expression("abs(-5)").toString(), "5"); - EXPECT_EQ(Expression("abs((-5))").toString(), "5"); - EXPECT_EQ(Expression("sign(10)").toString(), "1"); + EXPECT_EQ(Expression("sqrt(50)").toString(), "5 sqrt(2)"); + EXPECT_EQ(Expression("root(4, 2)").toString(), "2"); + EXPECT_EQ(Expression("root(8, 3)").toString(), "2"); + EXPECT_EQ(Expression("root(16, 4)").toString(), "2"); + EXPECT_EQ(Expression("root(27, 3)").toString(), "3"); + EXPECT_EQ(Expression("4^(1/2)").toString(), "2"); + EXPECT_EQ(Expression("8^(1/3)").toString(), "2"); + EXPECT_EQ(Expression("8^(4/3)").toString(), "16"); + EXPECT_EQ(Expression("7 2^(2/3)").toString(), "7 root(4, 3)"); + EXPECT_EQ(Expression("2^(2/3) 3^(2/3)").toString(), "root(9, 3) root(4, 3)"); // TODO! root(36, 3) + EXPECT_EQ(Expression("2^(2/3) 7^(2/3) 3^(3/4)").toString(), + "root(49, 3) root(27, 4) root(4, 3)"); // TODO! 12 root(27, 4) root(80, 3) + EXPECT_EQ(Expression("2^(2/3) 1/7^(2/3) 3^(3/4)").toString(), + "(root(27, 4) root(4, 3))/root(49, 3)"); // TODO! root(27, 4) root(4/49, 3) EXPECT_EQ(Expression("E").toString(), "E"); EXPECT_EQ(Expression("Pi").toString(), "Pi"); @@ -165,8 +173,8 @@ TEST(ExpressionTests, stringConstructorTest) { EXPECT_EQ(Expression("acosh1.9").toString(), "acosh(19/10)"); EXPECT_EQ(Expression("atanh0.9").toString(), "atanh(9/10)"); EXPECT_EQ(Expression("acoth1.9").toString(), "acoth(19/10)"); - EXPECT_EQ(Expression("((2))*sqrt2").toString(), "sqrt(2)^3"); - EXPECT_EQ(Expression("sqrt2*((2))").toString(), "sqrt(2)^3"); + EXPECT_EQ(Expression("((2))*sqrt2").toString(), "2 sqrt(2)"); + EXPECT_EQ(Expression("sqrt2*((2))").toString(), "2 sqrt(2)"); EXPECT_EQ(Expression("sin(1)^2").toString(), "sin(1)^2"); EXPECT_EQ(Expression("sin(-1)^2").toString(), "sin(-1)^2"); EXPECT_EQ(Expression("sin1^2").toString(), "sin(1)^2"); @@ -181,12 +189,18 @@ TEST(ExpressionTests, stringConstructorTest) { "2 sqrt(-1/2 cos(2/3 Pi) + 1/2) cos(1/3 Pi)"); EXPECT_EQ(Expression("-sin(2)").toString(), "-sin(2)"); EXPECT_EQ(Expression("sqrt(26)").toString(), "sqrt(26)"); - EXPECT_EQ(Expression("sqrt(145/26)").toString(), "sqrt(145/26)"); - EXPECT_EQ(Expression("sqrt(169/3)").toString(), "sqrt(169/3)"); - EXPECT_EQ(Expression("sqrt(168/25)").toString(), "sqrt(168/25)"); + EXPECT_EQ(Expression("sqrt(145/26)").toString(), "sqrt(145)/sqrt(26)"); + EXPECT_EQ(Expression("sqrt(169/3)").toString(), "13/sqrt(3)"); + EXPECT_EQ(Expression("sqrt(168/25)").toString(), "2/5 sqrt(42)"); EXPECT_EQ(Expression("log(2, 256)").toString(), "8"); - EXPECT_EQ(Expression("2^(3/2)").toString(), "sqrt(2)^3"); - EXPECT_EQ(Expression("sqrt(sqrt5)").toString(), "5^(1/4)"); + 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"); + EXPECT_EQ(Expression("(sqrt4)!").toString(), "2"); + EXPECT_EQ(Expression("sqrt4*2!").toString(), "4"); + EXPECT_EQ(Expression("abs(-5)").toString(), "5"); + EXPECT_EQ(Expression("abs((-5))").toString(), "5"); + EXPECT_EQ(Expression("sign(10)").toString(), "1"); EXPECT_EQ(Expression("a*0").toString(), "0"); EXPECT_EQ(Expression("0*a").toString(), "0"); @@ -387,6 +401,17 @@ TEST(ExpressionTests, stringConstructorTest) { EXPECT_EQ(Expression("2 a^5 b - 4 a b^5 = 0").toString(), "a^5 b - 2 a b^5 = 0"); EXPECT_EQ(Expression("-2 a^5 b + 4 a b^5 = 0").toString(), "a^5 b - 2 a b^5 = 0"); + EXPECT_EQ(Expression("sin(E)=sin(E)").toString(), "True"); + EXPECT_EQ(Expression("sin(E)>sin(E)").toString(), "False"); + EXPECT_EQ(Expression("sin(E)>=sin(E)").toString(), "True"); + EXPECT_EQ(Expression("sin(E)ln(5)").toString(), "False"); + EXPECT_EQ(Expression("log(E,5)<=ln(5)").toString(), "True"); + EXPECT_EQ(Expression("log(E,5)>=ln(5)").toString(), "True"); + EXPECT_EQ(Expression("derivative(a, a)").toString(), "1"); EXPECT_EQ(Expression("derivative(a+a, a)").toString(), "derivative(2 a, a)"); EXPECT_EQ(Expression("derivative(a, a) + derivative(b, b)").toString(), "2"); @@ -883,7 +908,14 @@ TEST(ExpressionTests, stringConstructorNegativeTest) { 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); // TODO constants // EXPECT_THROW(Expression("E!"), UndefinedException); // EXPECT_THROW(Expression("tan(Pi/2)"), UndefinedException); @@ -918,17 +950,12 @@ TEST(ExpressionTests, preciseTest) { "73070599793680672726476826340615135890078390.083960707616445859670987728609198428"); EXPECT_EQ(Expression("E^(-101)").precise().toString(), "1.3685394711738530002470557302322944177986775531612023009807438134142551921153897*10^-44"); - EXPECT_EQ(Expression("log(E,E)").precise().toString(), "1"); - EXPECT_EQ(Expression("log(2, 256)").precise().toString(), "8"); - EXPECT_EQ(Expression("log(Pi, Pi^10)").precise().toString(), "10"); - EXPECT_EQ(Expression("log(E,E^3)").precise().toString(), "3"); EXPECT_EQ(Expression("ln3").precise().toString(), "1.098612288668109691395245236922525704647490557822749451734694333637494293218609"); EXPECT_EQ(Expression("ln2").precise().toString(), "0.69314718055994530941723212145817656807550013436025525412068000949339362196969472"); EXPECT_EQ(Expression("ln100").precise().toString(), "4.605170185988091368035982909368728415202202977257545952066655801935145219354705"); - EXPECT_EQ(Expression("ln(E)").precise().toString(), "1"); EXPECT_EQ(Expression("lg99").precise().toString(), "1.9956351945975499153402557777532548601069599188478448242562702992902113378005716"); EXPECT_EQ(Expression("lg100").precise().toString(), "2"); @@ -979,10 +1006,10 @@ TEST(ExpressionTests, preciseTest) { "0.70807341827357119349878411475038109488300038553777244537757498689098246806203958"); EXPECT_EQ(Expression("sin(10^30)").precise().toString(), "-0.090116901912138058030386428952987330274396332993043449885460666579773983476795775"); - EXPECT_EQ(Expression("sin(1)^2+cos(1)^2").precise().toString(), "1"); + EXPECT_EQ(Expression("sin(1)^2+cos(1)^2").precise().toString(), "1"); // TODO: move to str constructor tests EXPECT_EQ(Expression("sin(Pi/3)").precise().toString(), "0.86602540378443864676372317075293618347140262690519031402790348972596650845440002"); - EXPECT_EQ(Expression("cos(Pi/3)").precise().toString(), "0.5"); + EXPECT_EQ(Expression("cos(Pi/3)").precise().toString(), "0.5"); // TODO: move to str constructor tests EXPECT_EQ(Expression("2!*E").precise().toString(), "5.4365636569180904707205749427053249955144941873999191499339352554481532607070952"); EXPECT_EQ(Expression("E*2!").precise().toString(), @@ -991,43 +1018,24 @@ TEST(ExpressionTests, preciseTest) { "0.86602540378443864676372317075293618347140262690519031402790348972596650845440002"); EXPECT_EQ(Expression("2*sqrt((1-cos(2*(Pi/3)))/2)*cos(Pi/3)").precise().toString(), "0.86602540378443864676372317075293618347140262690519031402790348972596650845440002"); - EXPECT_EQ(Expression("sin(60Deg)").precise().toString(), - "0.86602540378443864676372317075293618347140262690519031402790348972596650845440002"); - - EXPECT_EQ(Expression("sin(E)=sin(E)").precise().toString(), "True"); - EXPECT_EQ(Expression("sin(E)>sin(E)").precise().toString(), "False"); - EXPECT_EQ(Expression("sin(E)>=sin(E)").precise().toString(), "True"); - EXPECT_EQ(Expression("sin(E)ln(5)").precise().toString(), "False"); - EXPECT_EQ(Expression("log(E,5)<=ln(5)").precise().toString(), "True"); - EXPECT_EQ(Expression("log(E,5)>=ln(5)").precise().toString(), "True"); + EXPECT_EQ(Expression("sin(60Deg)").precise().toString(), + "0.86602540378443864676372317075293618347140262690519031402790348972596650845440002"); EXPECT_EQ(Expression("ln(x)").precise().toString(), "ln(x)"); EXPECT_EQ(Expression("sqrt(x)").precise().toString(), "sqrt(x)"); - // TODO: to uncomment when the root is implemented - // EXPECT_EQ(Expression("root(x, 3)").precise().toString(), "root(x, 3)"); + EXPECT_EQ(Expression("root(x, 3)").precise().toString(), "root(x, 3)"); + EXPECT_EQ(Expression("root(x, 10)").precise().toString(), "x^0.1"); + EXPECT_EQ(Expression("root(x, 33)").precise().toString(), + "x^0.03030303030303030303030303030303030303030303030303030303030303030303030303030303"); + // TODO: move to str constructor tests EXPECT_EQ(Expression("derivative(sqrt((1-cos(2*(Pi/3)))/2), x)").precise().toString(), "0"); } TEST(ExpressionTests, preciseNegativeTest) { - EXPECT_THROW(Expression("ln(ln(ln(ln(E))))").precise(), UndefinedException); - EXPECT_THROW(Expression("ln(ln(ln(ln(ln(E)))))").precise(), UndefinedException); - EXPECT_THROW(Expression("E!").precise(), UndefinedException); - EXPECT_THROW(Expression("sqrt(-1)").precise(), UndefinedException); - EXPECT_THROW(Expression("ln(0)").precise(), UndefinedException); - EXPECT_THROW(Expression("ln(-1)").precise(), UndefinedException); - EXPECT_THROW(Expression("log(-1, 1)").precise(), UndefinedException); - EXPECT_THROW(Expression("log(0, 1)").precise(), UndefinedException); - EXPECT_THROW(Expression("log(1, 0)").precise(), UndefinedException); - EXPECT_THROW(Expression("lb(-1)").precise(), UndefinedException); - EXPECT_THROW(Expression("lg(-1)").precise(), UndefinedException); - EXPECT_THROW(Expression("(-1)^(2/3)").precise(), UndefinedException); + // TODO: move to str constructor negative tests EXPECT_THROW(Expression("tan(Pi/2)").precise(), UndefinedException); EXPECT_THROW(Expression("cot(0)").precise(), UndefinedException); EXPECT_THROW(Expression("asin(2)").precise(), UndefinedException); diff --git a/tests/src/functions/powers/PowTests.cpp b/tests/src/functions/powers/PowTests.cpp index 5c45d460f..4cdeb1370 100644 --- a/tests/src/functions/powers/PowTests.cpp +++ b/tests/src/functions/powers/PowTests.cpp @@ -8,6 +8,7 @@ #include "fintamath/functions/arithmetic/UnaryPlus.hpp" #include "fintamath/literals/Variable.hpp" #include "fintamath/numbers/Rational.hpp" +#include "fintamath/numbers/Real.hpp" using namespace fintamath; @@ -28,57 +29,55 @@ TEST(PowTests, getOperatorPriorityTest) { TEST(PowTests, callTest) { EXPECT_EQ(f(Integer(3), Integer(2))->toString(), "9"); EXPECT_EQ(f(Integer(-3), Integer(2))->toString(), "9"); + EXPECT_EQ(f(Integer(3), Integer(-2))->toString(), "1/9"); EXPECT_EQ(f(Rational(5, 2), Integer(2))->toString(), "25/4"); EXPECT_EQ(f(Integer(11), Integer(200))->toString(), "1899052764604618242121820463954116340585832240009877848127251456103762646167989140750662066593328455813588" "1805238401044949435868367905913020005911442340062387227375955664576836341689587626164144676307968892001"); EXPECT_EQ(f(Integer(4), Rational(1, 2))->toString(), "2"); - EXPECT_EQ(f(Integer(4), Rational(1, 3))->toString(), - "1.5874010519681994747517056392723082603914933278998530098082857618252165056242192"); - EXPECT_EQ(f(Integer(4), Rational(1, 4))->toString(), - "1.414213562373095048801688724209698078569671875376948073176679737990732478462107"); + EXPECT_EQ(f(Integer(4), Rational(1, 3))->toString(), "root(4, 3)"); + EXPECT_EQ(f(Integer(4), Rational(1, 4))->toString(), "sqrt(2)"); EXPECT_EQ(f(Integer(8), Rational(1, 3))->toString(), "2"); EXPECT_EQ(f(Integer(16), Rational(1, 4))->toString(), "2"); - EXPECT_EQ(f(Integer(7), Rational(1, 1000))->toString(), - "1.0019478046608600325035566282397824682830146541368868842018499358998331147926632"); - EXPECT_EQ(f(*f(Integer(10), Integer(100)), Rational(1, 100))->toString(), "10"); + EXPECT_EQ(f(Integer(7), Rational(1, 1000))->toString(), "root(7, 1000)"); EXPECT_EQ(f(Integer(4), Rational(5, 2))->toString(), "32"); - EXPECT_EQ(f(Integer(4), Rational(5, 3))->toString(), - "10.079368399158985318137684858225826804562011717612063840655800897242397412111676"); - EXPECT_EQ(f(Integer(4), Rational(5, 4))->toString(), - "5.6568542494923801952067548968387923142786875015077922927067189519629299138484282"); + EXPECT_EQ(f(Integer(4), Rational(5, 3))->toString(), "8 root(2, 3)"); + EXPECT_EQ(f(Integer(4), Rational(5, 4))->toString(), "4 sqrt(2)"); EXPECT_EQ(f(Integer(8), Rational(5, 3))->toString(), "32"); EXPECT_EQ(f(Integer(16), Rational(5, 4))->toString(), "32"); - EXPECT_EQ(f(Integer(7), Rational(3, 1000))->toString(), - "1.0058548032014305540462802938447452087153844969521205792334942435663538095322262"); - EXPECT_EQ(f(*f(Integer(10), Integer(300)), Rational(1, 100))->toString(), "1000"); + EXPECT_EQ(f(Integer(7), Rational(3, 1000))->toString(), "root(343, 1000)"); EXPECT_EQ(f(Integer(1), Rational(1, 1234))->toString(), "1"); - EXPECT_EQ(f(Integer(10000000000), Rational(1, 100))->toString(), - "1.258925411794167210423954106395800606093617409466931069107923019526647615782502"); + EXPECT_EQ(f(Integer(10000000000), Rational(1, 100))->toString(), "root(10, 10)"); + EXPECT_EQ(f(Integer(-4), Rational(1))->toString(), "-4"); + + EXPECT_EQ(f(*f(Integer(10), Integer(100)), Rational(1, 100))->toString(), "10"); + EXPECT_EQ(f(*f(Integer(10), Integer(300)), Rational(1, 100))->toString(), "1000"); EXPECT_EQ(f(Integer(4), Rational(-1, 2))->toString(), "1/2"); - EXPECT_EQ(f(Integer(4), Rational(-1, 3))->toString(), - "0.62996052494743658238360530363911417528512573235075399004098755607764983825697974"); - EXPECT_EQ(f(Integer(4), Rational(-1, 4))->toString(), - "0.70710678118654752440084436210484903928483593768847403658833986899536623923105352"); - EXPECT_EQ(f(Integer(8), Rational(-1, 3))->toString(), "0.5"); - EXPECT_EQ(f(Integer(16), Rational(-1, 4))->toString(), "0.5"); + EXPECT_EQ(f(Integer(4), Rational(-1, 3))->toString(), "1/root(4, 3)"); + EXPECT_EQ(f(Integer(4), Rational(-1, 4))->toString(), "1/sqrt(2)"); + EXPECT_EQ(f(Integer(8), Rational(-1, 3))->toString(), "1/2"); + EXPECT_EQ(f(Integer(16), Rational(-1, 4))->toString(), "1/2"); EXPECT_EQ(f(Integer(4), Rational(-5, 2))->toString(), "1/32"); - EXPECT_EQ(f(Integer(4), Rational(-5, 3))->toString(), - "0.099212565748012467171981602454519266274468332993740813113017860114076031601513698"); - EXPECT_EQ(f(Integer(4), Rational(-5, 4))->toString(), - "0.17677669529663688110021109052621225982120898442211850914708496724884155980776338"); - EXPECT_EQ(f(Integer(8), Rational(-5, 3))->toString(), "0.03125"); - EXPECT_EQ(f(Integer(16), Rational(-5, 4))->toString(), "0.03125"); - EXPECT_EQ(f(Integer(7), Rational(-3, 1000))->toString(), - "0.99417927599212539388309345602974534386950277212157482682781039330883285005190623"); - - EXPECT_EQ(f(Rational("-10"), Rational("-3"))->toString(), "-1/1000"); - EXPECT_EQ(f(Rational("-1"), Rational("-25"))->toString(), "-1"); - EXPECT_EQ(f(Rational("-2.2"), Rational("-5"))->toString(), "-3125/161051"); + EXPECT_EQ(f(Integer(4), Rational(-5, 3))->toString(), "1/(8 root(2, 3))"); + EXPECT_EQ(f(Integer(4), Rational(-5, 4))->toString(), "1/(4 sqrt(2))"); + EXPECT_EQ(f(Integer(8), Rational(-5, 3))->toString(), "1/32"); + EXPECT_EQ(f(Integer(16), Rational(-5, 4))->toString(), "1/32"); + EXPECT_EQ(f(Integer(7), Rational(-3, 1000))->toString(), "1/root(343, 1000)"); + + EXPECT_EQ(f(Rational(-10), Rational(-3))->toString(), "-1/1000"); + EXPECT_EQ(f(Rational(-1), Rational(-25))->toString(), "-1"); + EXPECT_EQ(f(Rational("-2.2"), Rational(-5))->toString(), "-3125/161051"); + EXPECT_EQ(f(Rational("2.2"), Rational(-5, 2))->toString(), "(25 sqrt(5))/(121 sqrt(11))"); + + EXPECT_EQ(f(Real("2.2"), Real("2"))->toString(), "4.84"); + EXPECT_EQ(f(Real("2.2"), Real("0.5"))->toString(), + "1.48323969741913258974227948816014261219598086381950031974652465286876603686277"); 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_THROW(f(Integer(0), Integer(0)), UndefinedException); EXPECT_THROW(f(Rational("0"), Rational("-10")), UndefinedException); diff --git a/tests/src/functions/powers/RootTests.cpp b/tests/src/functions/powers/RootTests.cpp new file mode 100644 index 000000000..367678137 --- /dev/null +++ b/tests/src/functions/powers/RootTests.cpp @@ -0,0 +1,101 @@ +#include "gtest/gtest.h" + +#include "fintamath/exceptions/UndefinedException.hpp" +#include "fintamath/functions/powers/Root.hpp" + +#include "fintamath/literals/Variable.hpp" +#include "fintamath/numbers/Rational.hpp" +#include "fintamath/numbers/Real.hpp" + +using namespace fintamath; + +const Root f; + +TEST(RootTests, toStringTest) { + EXPECT_EQ(f.toString(), "root"); +} + +TEST(RootTests, getFunctionTypeTest) { + EXPECT_EQ(f.getFunctionType(), IFunction::Type::Binary); +} + +TEST(RootTests, callTest) { + EXPECT_EQ(f(Integer(10), Integer(1))->toString(), "10"); + EXPECT_EQ(f(Integer(-10), Integer(1))->toString(), "-10"); + EXPECT_EQ(f(Integer(100), Integer(2))->toString(), "10"); + EXPECT_EQ(f(Integer(25), Integer(2))->toString(), "5"); + EXPECT_EQ(f(Integer(144), Integer(2))->toString(), "12"); + EXPECT_EQ(f(Integer("10000000000000000000000000000000000000000000000000000"), Integer(2))->toString(), + "100000000000000000000000000"); + EXPECT_EQ(f(Integer(10), Integer(2))->toString(), "sqrt(10)"); + EXPECT_EQ(f(Integer(35), Integer(2))->toString(), "sqrt(35)"); + EXPECT_EQ(f(Integer(4212), Integer(2))->toString(), "18 sqrt(13)"); + EXPECT_EQ(f(Integer("992188888888"), Integer(2))->toString(), "2 sqrt(248047222222)"); + EXPECT_EQ(f(Integer("68732648273642987365932706179432649827364"), Integer(2))->toString(), + "2 sqrt(17183162068410746841483176544858162456841)"); + EXPECT_EQ(f(Integer(100), Integer(3))->toString(), "root(100, 3)"); + EXPECT_EQ(f(Integer(25), Integer(3))->toString(), "root(25, 3)"); + EXPECT_EQ(f(Integer(144), Integer(3))->toString(), "2 root(18, 3)"); + EXPECT_EQ(f(Integer("10000000000000000000000000000000000000000000000000000"), Integer(3))->toString(), + "100000000000000000 root(10, 3)"); + EXPECT_EQ(f(Integer(10), Integer(3))->toString(), "root(10, 3)"); + EXPECT_EQ(f(Integer(35), Integer(3))->toString(), "root(35, 3)"); + EXPECT_EQ(f(Integer(4212), Integer(3))->toString(), "3 root(156, 3)"); + EXPECT_EQ(f(Integer("992188888888"), Integer(3))->toString(), "2 root(124023611111, 3)"); + EXPECT_EQ(f(Integer("68732648273642987365932706179432649827364"), Integer(3))->toString(), + "root(68732648273642987365932706179432649827364, 3)"); + EXPECT_EQ(f(Integer(1024), Integer(3))->toString(), "8 root(2, 3)"); + EXPECT_EQ(f(Integer(1024), Integer(5))->toString(), "4"); + EXPECT_EQ(f(Integer(1024), Integer(10))->toString(), "2"); + + EXPECT_EQ(f(Rational(25), Integer(4))->toString(), "sqrt(5)"); + EXPECT_EQ(f(Rational(25, 169), Integer(4))->toString(), "sqrt(5)/sqrt(13)"); + EXPECT_EQ(f(Rational(144, 49), Integer(4))->toString(), "(2 sqrt(3))/sqrt(7)"); + EXPECT_EQ(f(Rational("1.44"), Integer(4))->toString(), "sqrt(6)/sqrt(5)"); + EXPECT_EQ(f(Rational(1, 10), Integer(4))->toString(), "1/root(10, 4)"); + EXPECT_EQ(f(Rational(25, 48), Integer(4))->toString(), "sqrt(5)/(2 root(3, 4))"); + EXPECT_EQ(f(Rational(26, 49), Integer(4))->toString(), "root(26, 4)/sqrt(7)"); + EXPECT_EQ(f(Rational(45, 67), Integer(4))->toString(), "(sqrt(3) root(5, 4))/root(67, 4)"); + EXPECT_EQ(f(Rational("68732648273642987365932706179432649827364.144"), Integer(4))->toString(), + "root(8591581034205373420741588272429081228420518, 4)/root(125, 4)"); + + EXPECT_EQ(f(Rational(25), Rational(4, 3))->toString(), "5 sqrt(5)"); + EXPECT_EQ(f(Rational(25, 169), Rational(4, 3))->toString(), "(5 sqrt(5))/(13 sqrt(13))"); + EXPECT_EQ(f(Rational(144, 49), Rational(4, 3))->toString(), "(24 sqrt(3))/(7 sqrt(7))"); + EXPECT_EQ(f(Rational("1.44"), Rational(4, 3))->toString(), "(6 sqrt(6))/(5 sqrt(5))"); + EXPECT_EQ(f(Rational(1, 10), Rational(4, 3))->toString(), "1/root(1000, 4)"); + EXPECT_EQ(f(Rational(25, 48), Rational(4, 3))->toString(), "(5 sqrt(5))/(8 root(27, 4))"); + EXPECT_EQ(f(Rational(26, 49), Rational(4, 3))->toString(), "root(17576, 4)/(7 sqrt(7))"); + EXPECT_EQ(f(Rational(45, 67), Rational(4, 3))->toString(), "(3 sqrt(3) root(125, 4))/root(300763, 4)"); + EXPECT_EQ(f(Rational("68732648273642987365932706179432649827364.144"), Rational(4, 3))->toString(), + "root(" + "6341898279505748220737558733036392804899042006384472743062801876828565493307610084438050180592269960571521" + "04826353254809443231832, 4)/(25 root(5, 4))"); + + EXPECT_EQ(f(Real(144), Integer(2))->toString(), "12"); + EXPECT_EQ(f(Real(144), Integer(4))->toString(), + "3.4641016151377545870548926830117447338856105076207612561116139589038660338176001"); + EXPECT_EQ(f(Real(2), Integer(3))->toString(), + "1.2599210498948731647672106072782283505702514647015079800819751121552996765139595"); + + EXPECT_EQ(f(Real(144), Rational(2, 3))->toString(), "1728"); + EXPECT_EQ(f(Real(144), Rational(4, 3))->toString(), + "41.569219381653055044658712196140936806627326091449135073339367506846392405811201"); + EXPECT_EQ(f(Real(2), Rational(3, 5))->toString(), + "3.1748021039363989495034112785446165207829866557997060196165715236504330112484383"); + + EXPECT_EQ(f(Real(2), Real("2.33"))->toString(), + "1.3464722988167144947473840795888543539968696938592078715906325948094320119117764"); + + EXPECT_EQ(f(Variable("a"), Integer(2))->toString(), "sqrt(a)"); + EXPECT_EQ(f(Variable("a"), Integer(3))->toString(), "root(a, 3)"); + EXPECT_EQ(f(Variable("a"), Integer(123))->toString(), "root(a, 123)"); + EXPECT_EQ(f(Integer(2), Variable("a"))->toString(), "2^(1/a)"); + + EXPECT_THROW(f(Integer(-10), Integer(2)), UndefinedException); + EXPECT_THROW(f(Rational(-9289, 10), Rational(2, 3)), UndefinedException); + EXPECT_THROW(f(Real(-9289), Rational(2, 3)), UndefinedException); + + EXPECT_THROW(f(), InvalidInputFunctionException); + EXPECT_THROW(f(Integer(1), Integer(1), Integer(1)), InvalidInputFunctionException); +} diff --git a/tests/src/functions/powers/SqrtTests.cpp b/tests/src/functions/powers/SqrtTests.cpp index 280236dd4..7fcfc0c88 100644 --- a/tests/src/functions/powers/SqrtTests.cpp +++ b/tests/src/functions/powers/SqrtTests.cpp @@ -24,36 +24,26 @@ TEST(SqrtTests, getFunctionTypeTest) { TEST(SqrtTests, callTest) { EXPECT_EQ(f(Integer(100))->toString(), "10"); EXPECT_EQ(f(Integer(25))->toString(), "5"); - EXPECT_EQ(f(Integer(100))->toString(), "10"); EXPECT_EQ(f(Integer(144))->toString(), "12"); EXPECT_EQ(f(Integer("10000000000000000000000000000000000000000000000000000"))->toString(), "100000000000000000000000000"); - EXPECT_EQ(f(Integer(10))->toString(), - "3.1622776601683793319988935444327185337195551393252168268575048527925944386392382"); - EXPECT_EQ(f(Integer(35))->toString(), - "5.916079783099616042567328291561617048415501230794340322879719669142822459105653"); - EXPECT_EQ(f(Integer(4212))->toString(), - "64.899922958351807276145982814468927032523338329214431828788155012089005069274188"); - EXPECT_EQ(f(Integer("992188888888"))->toString(), - "996086.7878292533601855411744463733737437739712744225743190752774953323543572221"); + EXPECT_EQ(f(Integer(10))->toString(), "sqrt(10)"); + EXPECT_EQ(f(Integer(35))->toString(), "sqrt(35)"); + EXPECT_EQ(f(Integer(4212))->toString(), "18 sqrt(13)"); + EXPECT_EQ(f(Integer("992188888888"))->toString(), "2 sqrt(248047222222)"); EXPECT_EQ(f(Integer("68732648273642987365932706179432649827364"))->toString(), - "262169121510606178721.58566765529332797469887558257026225414531129497927294552571"); + "2 sqrt(17183162068410746841483176544858162456841)"); EXPECT_EQ(f(Rational(25))->toString(), "5"); EXPECT_EQ(f(Rational(25, 169))->toString(), "5/13"); EXPECT_EQ(f(Rational(144, 49))->toString(), "12/7"); - EXPECT_EQ(f(Rational(144, 49))->toString(), "12/7"); EXPECT_EQ(f(Rational("1.44"))->toString(), "6/5"); - EXPECT_EQ(f(Rational(1, 10))->toString(), - "0.31622776601683793319988935444327185337195551393252168268575048527925944386392382"); - EXPECT_EQ(f(Rational(25, 48))->toString(), - "0.72168783648703220563643597562744681955950218908765859502325290810497209037866668"); - EXPECT_EQ(f(Rational(26, 49))->toString(), - "0.72843135908468354714688915843182599850911013515708520108356725777513337600888917"); - EXPECT_EQ(f(Rational(45, 67))->toString(), - "0.81953754706222955297929294102425245239518786681123328404647027909565181499392632"); + EXPECT_EQ(f(Rational(1, 10))->toString(), "1/sqrt(10)"); + EXPECT_EQ(f(Rational(25, 48))->toString(), "5/(4 sqrt(3))"); + EXPECT_EQ(f(Rational(26, 49))->toString(), "1/7 sqrt(26)"); + EXPECT_EQ(f(Rational(45, 67))->toString(), "(3 sqrt(5))/sqrt(67)"); // TODO! 3 sqrt(5/67) EXPECT_EQ(f(Rational("68732648273642987365932706179432649827364.144"))->toString(), - "262169121510606178721.5856676552933279746991502144551506779910090326304113931067"); + "sqrt(8591581034205373420741588272429081228420518)/(5 sqrt(5))"); EXPECT_EQ(f(Real(144))->toString(), "12"); EXPECT_EQ(f(Real(2))->toString(), "1.414213562373095048801688724209698078569671875376948073176679737990732478462107"); diff --git a/tests/src/numbers/IntegerFunctionsTests.cpp b/tests/src/numbers/IntegerFunctionsTests.cpp index de756856f..7f045e2de 100644 --- a/tests/src/numbers/IntegerFunctionsTests.cpp +++ b/tests/src/numbers/IntegerFunctionsTests.cpp @@ -140,6 +140,54 @@ TEST(IntegerFunctionsTests, factorialTest) { EXPECT_THROW(factorial(Integer(-1)), UndefinedUnaryOperatorException); } +TEST(IntegerFunctionsTests, factorsTest) { + std::map factorRates; + + factorRates = factors(2); + EXPECT_EQ(factorRates.size(), 1); + EXPECT_EQ(factorRates[2], 1); + + factorRates = factors(32); + EXPECT_EQ(factorRates.size(), 1); + EXPECT_EQ(factorRates[2], 5); + + factorRates = factors(144); + EXPECT_EQ(factorRates.size(), 2); + EXPECT_EQ(factorRates[2], 4); + EXPECT_EQ(factorRates[3], 2); + + factorRates = factors(123); + EXPECT_EQ(factorRates.size(), 2); + EXPECT_EQ(factorRates[3], 1); + EXPECT_EQ(factorRates[41], 1); + + factorRates = factors(Integer("139826427468275632"), 1000); + EXPECT_EQ(factorRates.size(), 5); + EXPECT_EQ(factorRates[2], 4); + EXPECT_EQ(factorRates[7], 1); + EXPECT_EQ(factorRates[17], 1); + EXPECT_EQ(factorRates[31], 1); + EXPECT_EQ(factorRates[Integer("2368975797443")], 1); + + factorRates = factors(Integer("139826427468275632"), 10000); + EXPECT_EQ(factorRates[2], 4); + EXPECT_EQ(factorRates[7], 1); + EXPECT_EQ(factorRates[17], 1); + EXPECT_EQ(factorRates[31], 1); + EXPECT_EQ(factorRates[1093], 1); + EXPECT_EQ(factorRates[Integer("2167406951")], 1); + + factorRates = factors(Integer("13982642746827562949728"), 1000); + EXPECT_EQ(factorRates.size(), 3); + EXPECT_EQ(factorRates[2], 5); + EXPECT_EQ(factorRates[59], 1); + EXPECT_EQ(factorRates[Integer("7406060776921378681")], 1); + + EXPECT_THROW(factors(-1), UndefinedFunctionException); + EXPECT_THROW(factors(0), UndefinedFunctionException); + EXPECT_THROW(factors(1), UndefinedFunctionException); +} + TEST(IntegerFunctionsTests, combinationsTest) { EXPECT_EQ(combinations(Integer(6), Integer(2)), 15); EXPECT_EQ(combinations(Integer(10), Integer(7)), 120); diff --git a/tests/src/parser/ParserTests.cpp b/tests/src/parser/ParserTests.cpp index 31e93b64c..214435175 100644 --- a/tests/src/parser/ParserTests.cpp +++ b/tests/src/parser/ParserTests.cpp @@ -43,6 +43,7 @@ #include "fintamath/functions/other/Percent.hpp" #include "fintamath/functions/powers/Exp.hpp" #include "fintamath/functions/powers/Pow.hpp" +#include "fintamath/functions/powers/Root.hpp" #include "fintamath/functions/powers/Sqrt.hpp" #include "fintamath/functions/trigonometry/Acos.hpp" #include "fintamath/functions/trigonometry/Acot.hpp" @@ -188,6 +189,7 @@ TEST(ParseTests, parseConstantTest) { TEST(ParserTests, parseFunctionTest) { EXPECT_TRUE(is(IFunction::parse("sqrt"))); + EXPECT_TRUE(is(IFunction::parse("root"))); EXPECT_TRUE(is(IFunction::parse("exp"))); EXPECT_TRUE(is(IFunction::parse("log"))); EXPECT_TRUE(is(IFunction::parse("ln")));