diff --git a/poincare/Makefile b/poincare/Makefile index df1dbda4a..c765fe78f 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -61,6 +61,7 @@ objs += $(addprefix poincare/src/,\ expression_lexer.o\ expression_node.o\ expression_parser.o\ + factor.o\ factorial.o\ float.o\ floor.o\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index a60332ec7..518d4e7b9 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -122,6 +122,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/include/poincare/factor.h b/poincare/include/poincare/factor.h index c8ba14832..523aa2485 100644 --- a/poincare/include/poincare/factor.h +++ b/poincare/include/poincare/factor.h @@ -2,38 +2,57 @@ #define POINCARE_FACTOR_H #include -#include -#include +#include +#include #include +#include #include namespace Poincare { -class Factor : public StaticHierarchy<1> { - using StaticHierarchy<1>::StaticHierarchy; +class FactorNode : public ExpressionNode { public: - Type type() const override; + // Allocation Failure + static FactorNode * FailedAllocationStaticNode(); + FactorNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); } + // TreeNode + size_t size() const override { return sizeof(FactorNode); } + int numberOfChildren() const override { return 1; } +#if POINCARE_TREE_LOG + virtual void logNodeName(std::ostream & stream) const override { + stream << "Factor"; + } +#endif + Type type() const override { return Type::Factor; } 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; + /* Serialization */ int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, name()); } const char * name() const { return "factor"; } /* Simplification */ - Expression shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) override; - Expression * createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context & context, Preferences::AngleUnit angleUnit); + Expression shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) const override; /* Evaluation */ Evaluation approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } Evaluation approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } template Evaluation templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const { - return childAtIndex(0)->privateApproximate(T(), context, angleUnit); + return childAtIndex(0)->approximate(T(), context, angleUnit); } }; +class Factor : public Expression { +public: + Factor() : Expression(TreePool::sharedPool()->createTreeNode()) {} + Factor(const FactorNode * n) : Expression(n) {} + Factor(Expression operand) : Factor() { + replaceChildAtIndexInPlace(0, operand); + } + + Expression shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) const; + Multiplication createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context & context, Preferences::AngleUnit angleUnit) const; +}; + } - #endif - diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index 01293fff6..8aa94eaf0 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -130,8 +130,7 @@ conj { poincare_expression_yylval.expression = Conjugate(); return FUNCTION; } det { poincare_expression_yylval.expression = Determinant(); return FUNCTION; } cos { poincare_expression_yylval.expression = Cosine(); return FUNCTION; } cosh { poincare_expression_yylval.expression = HyperbolicCosine(); return FUNCTION; } - /*factor { poincare_expression_yylval.expression = new Factor(); return FUNCTION; } -*/ +factor { poincare_expression_yylval.expression = new Factor(); return FUNCTION; } floor { poincare_expression_yylval.expression = Floor(); return FUNCTION; } frac { poincare_expression_yylval.expression = FracPart(); return FUNCTION; } gcd { poincare_expression_yylval.expression = GreatCommonDivisor(); return FUNCTION; } diff --git a/poincare/src/factor.cpp b/poincare/src/factor.cpp index 14c4c40fb..3484b8ae3 100644 --- a/poincare/src/factor.cpp +++ b/poincare/src/factor.cpp @@ -13,74 +13,69 @@ extern "C" { namespace Poincare { -ExpressionNode::Type Factor::type() const { - return Type::Factor; +FactorNode * FactorNode::FailedAllocationStaticNode() { + static AllocationFailureExpressionNode failure; + TreePool::sharedPool()->registerStaticNodeIfRequired(&failure); + return &failure; } -Expression * Factor::clone() const { - Factor * b = new Factor(m_operands, true); - return b; +LayoutRef FactorNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + return LayoutHelper::Prefix(Factor(this), floatDisplayMode, numberOfSignificantDigits, name()); } -Expression Factor::shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) { - Expression * op = childAtIndex(0); - if (op->type() != Type::Rational) { - return new Undefined(); +Expression FactorNode::shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) const { + return Factor(this).shallowBeautify(context, angleUnit); +} + +Expression Factor::shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) const { + Expression op = childAtIndex(0); + if (op.type() != ExpressionNode::Type::Rational) { + return Undefined(); } - Rational * r = static_cast(op); - if (r->isZero()) { - return replaceWith(r, true); + Rational r = static_cast(op); + if (r.isZero()) { + return r; } - Expression * numeratorDecomp = createMultiplicationOfIntegerPrimeDecomposition(r->numerator(), context, angleUnit); - Expression * result = numeratorDecomp; - if (result->type() == Type::Undefined) { - return replaceWith(result, true); + Multiplication numeratorDecomp = createMultiplicationOfIntegerPrimeDecomposition(r.unsignedIntegerNumerator(), context, angleUnit); + if (numeratorDecomp.numberOfChildren() == 0) { + return Undefined(); } - assert(numeratorDecomp->type() == Type::Multiplication); - if (!r->denominator().isOne()) { - Expression * denominatorDecomp = createMultiplicationOfIntegerPrimeDecomposition(r->denominator(), context, angleUnit); - if (denominatorDecomp->type() == Type::Undefined) { - delete result; - return replaceWith(denominatorDecomp, true); + Expression result = numeratorDecomp.squashUnaryHierarchy(); + if (!r.integerDenominator().isOne()) { + Multiplication denominatorDecomp = createMultiplicationOfIntegerPrimeDecomposition(r.integerDenominator(), context, angleUnit); + if (denominatorDecomp.numberOfChildren() == 0) { + return Undefined(); } - assert(denominatorDecomp->type() == Type::Multiplication); - result = new Division(numeratorDecomp, denominatorDecomp, false); - static_cast(denominatorDecomp)->squashUnaryHierarchy(); + result = Division(numeratorDecomp, denominatorDecomp.squashUnaryHierarchy()); } - if (r->sign() == Sign::Negative) { - result = new Opposite(result, false); + if (r.sign() == ExpressionNode::Sign::Negative) { + result = Opposite(result); } - replaceWith(result, true); - if (result == numeratorDecomp) { - return static_cast(numeratorDecomp)->squashUnaryHierarchy(); - } - static_cast(numeratorDecomp)->squashUnaryHierarchy(); return result; } -Expression * Factor::createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context & context, Preferences::AngleUnit angleUnit) { +Multiplication Factor::createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context & context, Preferences::AngleUnit angleUnit) const { assert(!i.isZero()); - i.setNegative(false); - Multiplication * m = new Multiplication(); + assert(!i.isNegative()); + Multiplication m; if (i.isOne()) { - m->addOperand(new Rational(i)); + m.addChildAtIndexInPlace(Rational(i), 0, 0); return m; } Integer factors[Arithmetic::k_maxNumberOfPrimeFactors]; Integer coefficients[Arithmetic::k_maxNumberOfPrimeFactors]; - Arithmetic::PrimeFactorization(&i, factors, coefficients, Arithmetic::k_maxNumberOfPrimeFactors); + Arithmetic::PrimeFactorization(i, factors, coefficients, Arithmetic::k_maxNumberOfPrimeFactors); int index = 0; if (coefficients[0].isMinusOne()) { - delete m; - return new Undefined(); + // Exception: the decomposition failed + return m; } while (!coefficients[index].isZero() && index < Arithmetic::k_maxNumberOfPrimeFactors) { - Expression * factor = new Rational(factors[index]); + Expression factor = Rational(factors[index]); if (!coefficients[index].isOne()) { - Expression * exponent = new Rational(coefficients[index]); - factor = new Power(factor, exponent, false); + factor = Power(factor, Rational(coefficients[index])); } - m->addOperand(factor); + m.addChildAtIndexInPlace(factor, m.numberOfChildren(), m.numberOfChildren()); index++; } return m; diff --git a/poincare/test/function.cpp b/poincare/test/function.cpp index 81dae53cf..9aea6c9c2 100644 --- a/poincare/test/function.cpp +++ b/poincare/test/function.cpp @@ -29,9 +29,7 @@ QUIZ_CASE(poincare_parse_function) { #endif assert_parsed_expression_type("confidence(0.1, 100)", ExpressionNode::Type::ConfidenceInterval); assert_parsed_expression_type("conj(2)", ExpressionNode::Type::Conjugate); -#if 0 assert_parsed_expression_type("factor(23/42)", ExpressionNode::Type::Factor); -#endif assert_parsed_expression_type("floor(2.3)", ExpressionNode::Type::Floor); assert_parsed_expression_type("frac(2.3)", ExpressionNode::Type::FracPart); assert_parsed_expression_type("gcd(2,3)", ExpressionNode::Type::GreatCommonDivisor); @@ -173,6 +171,9 @@ QUIZ_CASE(poincare_function_evaluate) { assert_parsed_expression_evaluates_to("conj(3+2*I)", "3-2*I"); assert_parsed_expression_evaluates_to("conj(3+2*I)", "3-2*I"); + + assert_parsed_expression_evaluates_to("factor(-23/4)", "-5.75"); + assert_parsed_expression_evaluates_to("factor(-123/24)", "-5.125"); #if 0 #if MATRICES_ARE_DEFINED @@ -230,9 +231,6 @@ QUIZ_CASE(poincare_function_evaluate) { assert_parsed_expression_evaluates_to("root(-1,3)", "0.5+0.8660254*I"); assert_parsed_expression_evaluates_to("root(-1,3)", "0.5+8.6602540378444E-1*I"); - assert_parsed_expression_evaluates_to("factor(-23/4)", "-5.75"); - assert_parsed_expression_evaluates_to("factor(-123/24)", "-5.125"); - assert_parsed_expression_evaluates_to("int(int(x*x,0,x),0,4)", "21.33333"); assert_parsed_expression_evaluates_to("int(int(x*x,0,x),0,4)", "21.333333333333"); @@ -258,6 +256,10 @@ QUIZ_CASE(poincare_function_simplify) { assert_parsed_expression_simplify_to("binomial(20,10)", "184756"); assert_parsed_expression_simplify_to("ceil(-1.3)", "-1"); assert_parsed_expression_simplify_to("conj(1/2)", "1/2"); + assert_parsed_expression_simplify_to("factor(-10008/6895)", "-(2^3*3^2*139)/(5*7*197)"); + assert_parsed_expression_simplify_to("factor(1008/6895)", "(2^4*3^2)/(5*197)"); + assert_parsed_expression_simplify_to("factor(10007)", "10007"); + assert_parsed_expression_simplify_to("factor(10007^2)", "undef"); assert_parsed_expression_simplify_to("quo(19,3)", "6"); assert_parsed_expression_simplify_to("quo(19,0)", "inf"); assert_parsed_expression_simplify_to("quo(-19,3)", "-7"); @@ -265,12 +267,10 @@ QUIZ_CASE(poincare_function_simplify) { assert_parsed_expression_simplify_to("rem(-19,3)", "2"); assert_parsed_expression_simplify_to("rem(19,0)", "inf"); assert_parsed_expression_simplify_to("99!", "933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000"); -#if 0 assert_parsed_expression_simplify_to("factor(-10008/6895)", "-(2^3*3^2*139)/(5*7*197)"); assert_parsed_expression_simplify_to("factor(1008/6895)", "(2^4*3^2)/(5*197)"); assert_parsed_expression_simplify_to("factor(10007)", "10007"); assert_parsed_expression_simplify_to("factor(10007^2)", "undef"); -#endif assert_parsed_expression_simplify_to("floor(-1.3)", "-2"); assert_parsed_expression_simplify_to("frac(-1.3)", "7/10"); assert_parsed_expression_simplify_to("gcd(123,278)", "1");