From 5dcdaf3a6b68231b706a0244e486ae4b55be023c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 27 Aug 2018 17:38:07 +0200 Subject: [PATCH] [poincare] Fix LCM --- poincare/Makefile | 1 + poincare/include/poincare.h | 1 + .../include/poincare/least_common_multiple.h | 39 +++++-- poincare/src/expression_lexer.l | 2 +- poincare/src/least_common_multiple.cpp | 102 +++++++++--------- poincare/test/function.cpp | 10 +- poincare/test/tree/helpers.h | 6 +- 7 files changed, 96 insertions(+), 65 deletions(-) diff --git a/poincare/Makefile b/poincare/Makefile index c765fe78f..a0ac80ba4 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -80,6 +80,7 @@ objs += $(addprefix poincare/src/,\ infinity.o\ integer.o\ layout_helper.o\ + least_common_multiple.o\ logarithm.o\ opposite.o\ matrix.o\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index 518d4e7b9..4f7df1d40 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -144,6 +144,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/include/poincare/least_common_multiple.h b/poincare/include/poincare/least_common_multiple.h index c4d8ea7be..4b9f34290 100644 --- a/poincare/include/poincare/least_common_multiple.h +++ b/poincare/include/poincare/least_common_multiple.h @@ -1,21 +1,29 @@ #ifndef POINCARE_LEAST_COMMON_MULTIPLE_H #define POINCARE_LEAST_COMMON_MULTIPLE_H -#include -#include -#include +#include +#include namespace Poincare { -class LeastCommonMultiple : public StaticHierarchy<2> { - using StaticHierarchy<2>::StaticHierarchy; +class LeastCommonMultipleNode : public ExpressionNode { public: - Type type() const override; + static LeastCommonMultipleNode * FailedAllocationStaticNode(); + LeastCommonMultipleNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); } + + // TreeNode + size_t size() const override { return sizeof(LeastCommonMultipleNode); } + int numberOfChildren() const override { return 2; } +#if POINCARE_TREE_LOG + virtual void logNodeName(std::ostream & stream) const override { + stream << "LeastCommonMultiple"; + } +#endif + // ExpressionNode + Type type() const override { return Type::LeastCommonMultiple; } private: /* Layout */ - LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { - return LayoutHelper::Prefix(this, floatDisplayMode, numberOfSignificantDigits, name()); - } + LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, name()); } @@ -28,6 +36,19 @@ private: template Evaluation templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const; }; +class LeastCommonMultiple : public Expression { +public: + LeastCommonMultiple() : Expression(TreePool::sharedPool()->createTreeNode()) {} + LeastCommonMultiple(const LeastCommonMultipleNode * n) : Expression(n) {} + LeastCommonMultiple(Expression child1, Expression child2) : LeastCommonMultiple() { + replaceChildAtIndexInPlace(0, child1); + replaceChildAtIndexInPlace(1, child2); + } + + // Expression + Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const; +}; + } #endif diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index d8f27bb4b..e19f6abba 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -137,8 +137,8 @@ gcd { poincare_expression_yylval.expression = GreatCommonDivisor(); return FUNCT im { poincare_expression_yylval.expression = ImaginaryPart(); return FUNCTION; } /*int { poincare_expression_yylval.expression = new Integral(); return FUNCTION; } inverse { poincare_expression_yylval.expression = new MatrixInverse(); return FUNCTION; } -lcm { poincare_expression_yylval.expression = new LeastCommonMultiple(); return FUNCTION; } */ +lcm { poincare_expression_yylval.expression = LeastCommonMultiple(); return FUNCTION; } ln { poincare_expression_yylval.expression = NaperianLogarithm(); return FUNCTION; } log { return LOGFUNCTION; } /*permute { poincare_expression_yylval.expression = new PermuteCoefficient(); return FUNCTION; } diff --git a/poincare/src/least_common_multiple.cpp b/poincare/src/least_common_multiple.cpp index 51b2e1c1a..a6600a0b8 100644 --- a/poincare/src/least_common_multiple.cpp +++ b/poincare/src/least_common_multiple.cpp @@ -2,6 +2,7 @@ #include #include #include +#include extern "C" { #include @@ -10,64 +11,31 @@ extern "C" { namespace Poincare { -ExpressionNode::Type LeastCommonMultiple::type() const { - return Type::LeastCommonMultiple; +LeastCommonMultipleNode * LeastCommonMultipleNode::FailedAllocationStaticNode() { + static AllocationFailureExpressionNode failure; + TreePool::sharedPool()->registerStaticNodeIfRequired(&failure); + return &failure; } -Expression * LeastCommonMultiple::clone() const { - LeastCommonMultiple * a = new LeastCommonMultiple(m_operands, true); - return a; +LayoutReference LeastCommonMultipleNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + return LayoutHelper::Prefix(LeastCommonMultiple(this), floatDisplayMode, numberOfSignificantDigits, name()); } -Expression LeastCommonMultiple::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const { - Expression e = Expression::defaultShallowReduce(context, angleUnit); - if (e.isUndefinedOrAllocationFailure()) { - return e; - } - Expression * op0 = childAtIndex(0); - Expression * op1 = childAtIndex(1); -#if MATRIX_EXACT_REDUCING - if (op0->type() == Type::Matrix || op1->type() == Type::Matrix) { - return replaceWith(new Undefined(), true); - } -#endif - if (op0->type() == Type::Rational) { - Rational * r0 = static_cast(op0); - if (!r0->denominator().isOne()) { - return replaceWith(new Undefined(), true); - } - } - if (op1->type() == Type::Rational) { - Rational * r1 = static_cast(op1); - if (!r1->denominator().isOne()) { - return replaceWith(new Undefined(), true); - } - } - if (op0->type() != Type::Rational || op1->type() != Type::Rational) { - return this; - } - Rational * r0 = static_cast(op0); - Rational * r1 = static_cast(op1); - - Integer a = r0->numerator(); - Integer b = r1->numerator(); - Integer lcm = Arithmetic::LCM(&a, &b); - return replaceWith(new Rational(lcm), true); +Expression LeastCommonMultipleNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const { + return LeastCommonMultiple(this).shallowReduce(context, angleUnit); } template -Complex * LeastCommonMultiple::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { - Evaluation * f1Input = childAtIndex(0)->privateApproximate(T(), context, angleUnit); - Evaluation * f2Input = childAtIndex(1)->privateApproximate(T(), context, angleUnit); - T f1 = f1Input->toScalar(); - T f2 = f2Input->toScalar(); - delete f1Input; - delete f2Input; +Evaluation LeastCommonMultipleNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { + Evaluation f1Input = childAtIndex(0)->approximate(T(), context, angleUnit); + Evaluation f2Input = childAtIndex(1)->approximate(T(), context, angleUnit); + T f1 = f1Input.toScalar(); + T f2 = f2Input.toScalar(); if (std::isnan(f1) || std::isnan(f2) || f1 != (int)f1 || f2 != (int)f2) { - return new Complex(Complex::Undefined()); + return Complex::Undefined(); } if (f1 == 0.0f || f2 == 0.0f) { - return new Complex(0); + return Complex(0.0); } int a = (int)f2; int b = (int)f1; @@ -82,7 +50,43 @@ Complex * LeastCommonMultiple::templatedApproximate(Context& context, Prefere a = b; b = r; } - return new Complex(product/a); + return Complex(product/a); +} + +Expression LeastCommonMultiple::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const { + Expression e = Expression::defaultShallowReduce(context, angleUnit); + if (e.isUndefinedOrAllocationFailure()) { + return e; + } + Expression op0 = childAtIndex(0); + Expression op1 = childAtIndex(1); +#if MATRIX_EXACT_REDUCING + if (op0.type() == Type::Matrix || op1.type() == Type::Matrix) { + return Undefined(); + } +#endif + if (op0.type() == ExpressionNode::Type::Rational) { + Rational r0 = static_cast(op0); + if (!r0.integerDenominator().isOne()) { + return Undefined(); + } + } + if (op1.type() == ExpressionNode::Type::Rational) { + Rational r1 = static_cast(op1); + if (!r1.integerDenominator().isOne()) { + return Undefined(); + } + } + if (op0.type() != ExpressionNode::Type::Rational || op1.type() != ExpressionNode::Type::Rational) { + return *this; + } + Rational r0 = static_cast(op0); + Rational r1 = static_cast(op1); + + Integer a = r0.signedIntegerNumerator(); + Integer b = r1.signedIntegerNumerator(); + Integer lcm = Arithmetic::LCM(a, b); + return Rational(lcm); } } diff --git a/poincare/test/function.cpp b/poincare/test/function.cpp index 9aea6c9c2..e82b2fe4c 100644 --- a/poincare/test/function.cpp +++ b/poincare/test/function.cpp @@ -34,12 +34,12 @@ QUIZ_CASE(poincare_parse_function) { assert_parsed_expression_type("frac(2.3)", ExpressionNode::Type::FracPart); assert_parsed_expression_type("gcd(2,3)", ExpressionNode::Type::GreatCommonDivisor); assert_parsed_expression_type("im(2+I)", ExpressionNode::Type::ImaginaryPart); + assert_parsed_expression_type("lcm(2,3)", ExpressionNode::Type::LeastCommonMultiple); #if 0 assert_parsed_expression_type("int(x, 2, 3)", ExpressionNode::Type::Integral); #if MATRICES_ARE_DEFINED assert_parsed_expression_type("inverse([[1,2,3][4,5,6][7,8,9]])", ExpressionNode::Type::MatrixInverse); #endif - assert_parsed_expression_type("lcm(2,3)", ExpressionNode::Type::LeastCommonMultiple); assert_parsed_expression_type("ln(2)", ExpressionNode::Type::NaperianLogarithm); assert_parsed_expression_type("log(2)", ExpressionNode::Type::Logarithm); assert_parsed_expression_type("permute(10, 4)", ExpressionNode::Type::PermuteCoefficient); @@ -109,14 +109,14 @@ QUIZ_CASE(poincare_function_evaluate) { assert_parsed_expression_evaluates_to("im(2+3I)", "3"); assert_parsed_expression_evaluates_to("im(2+3I)", "3"); + + assert_parsed_expression_evaluates_to("lcm(234,394)", "46098"); + assert_parsed_expression_evaluates_to("lcm(234,394)", "46098"); #if 0 assert_parsed_expression_evaluates_to("int(x, 1, 2)", "1.5"); assert_parsed_expression_evaluates_to("int(x, 1, 2)", "1.5"); - assert_parsed_expression_evaluates_to("lcm(234,394)", "46098"); - assert_parsed_expression_evaluates_to("lcm(234,394)", "46098"); - assert_parsed_expression_evaluates_to("ln(2)", "0.6931472"); assert_parsed_expression_evaluates_to("ln(2)", "6.9314718055995E-1"); @@ -275,9 +275,9 @@ QUIZ_CASE(poincare_function_simplify) { assert_parsed_expression_simplify_to("frac(-1.3)", "7/10"); assert_parsed_expression_simplify_to("gcd(123,278)", "1"); assert_parsed_expression_simplify_to("gcd(11,121)", "11"); -#if 0 assert_parsed_expression_simplify_to("lcm(123,278)", "34194"); assert_parsed_expression_simplify_to("lcm(11,121)", "121"); +#if 0 assert_parsed_expression_simplify_to("R(4)", "2"); assert_parsed_expression_simplify_to("root(4,3)", "root(4,3)"); assert_parsed_expression_simplify_to("root(4,P)", "4^(1/P)"); diff --git a/poincare/test/tree/helpers.h b/poincare/test/tree/helpers.h index 4d6914f69..bb55e0547 100644 --- a/poincare/test/tree/helpers.h +++ b/poincare/test/tree/helpers.h @@ -10,8 +10,12 @@ static inline int pool_size() { } #if POINCARE_TREE_LOG static inline void log_pool() { - Poincare::TreePool::sharedPool()->flatLog(std::cout); + Poincare::TreePool::sharedPool()->treeLog(std::cout); } +static void log_pool_tree() { + Poincare::TreePool::sharedPool()->treeLog(std::cout); +} + #endif static void assert_pool_size(int i) {