diff --git a/poincare/Makefile b/poincare/Makefile index 274c9282d..5c26cd00a 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -102,6 +102,7 @@ objs += $(addprefix poincare/src/,\ product.o\ rational.o\ real_part.o\ + round.o\ sequence.o\ serialization_helper.o\ simplification_helper.o\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index 0496ba502..86f6eb247 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -158,6 +158,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/include/poincare/power.h b/poincare/include/poincare/power.h index 04932102c..3b5daaac1 100644 --- a/poincare/include/poincare/power.h +++ b/poincare/include/poincare/power.h @@ -68,6 +68,7 @@ private: class Power : public Expression { friend class PowerNode; + friend class Round; public: Power(Expression base, Expression exponent) : Expression(TreePool::sharedPool()->createTreeNode()) { replaceChildAtIndexInPlace(0, base); diff --git a/poincare/include/poincare/real_part.h b/poincare/include/poincare/real_part.h index d64a7d918..081f45a0c 100644 --- a/poincare/include/poincare/real_part.h +++ b/poincare/include/poincare/real_part.h @@ -8,7 +8,6 @@ namespace Poincare { - class RealPartNode : public ExpressionNode { public: // Allocation Failure diff --git a/poincare/include/poincare/round.h b/poincare/include/poincare/round.h index e15ab81a5..3965830ad 100644 --- a/poincare/include/poincare/round.h +++ b/poincare/include/poincare/round.h @@ -2,34 +2,56 @@ #define POINCARE_ROUND_H #include -#include +#include #include +#include namespace Poincare { -class Round : public StaticHierarchy<2> { - using StaticHierarchy<2>::StaticHierarchy; +class RoundNode : public ExpressionNode { public: - Type type() const override; -private: - /* Layout */ - LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { - return LayoutHelper::Prefix(this, floatDisplayMode, numberOfSignificantDigits, name()); + // Allocation Failure + static RoundNode * FailedAllocationStaticNode(); + RoundNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); } + + // TreeNode + size_t size() const override { return sizeof(RoundNode); } + int numberOfChildren() const override { return 2; } +#if POINCARE_TREE_LOG + virtual void logNodeName(std::ostream & stream) const override { + stream << "Round"; } +#endif + + // Properties + Type type() const override { return Type::Round; } +private: + // Layout + LayoutReference 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()); } const char * name() const { return "round"; } - /* Simplification */ + // Simplification Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const override; - /* Complex */ + // 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; }; +class Round : public Expression { +public: + Round() : Expression(TreePool::sharedPool()->createTreeNode()) {} + Round(const RoundNode * n) : Expression(n) {} + Round(Expression operand0, Expression operand1) : Round() { + replaceChildAtIndexInPlace(0, operand0); + replaceChildAtIndexInPlace(1, operand1); + } + + Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit) const; +}; + } #endif - - diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index 929ce2812..f59910109 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -151,8 +151,7 @@ randint { poincare_expression_yylval.expression = new Randint(); return FUNCTION re { poincare_expression_yylval.expression = RealPart(); return FUNCTION; } rem { poincare_expression_yylval.expression = DivisionRemainder(); return FUNCTION; } root { poincare_expression_yylval.expression = NthRoot(); return FUNCTION; } - /*round { poincare_expression_yylval.expression = new Round(); return FUNCTION; } -*/ +round { poincare_expression_yylval.expression = Round(); return FUNCTION; } sin { poincare_expression_yylval.expression = Sine(); return FUNCTION; } sinh { poincare_expression_yylval.expression = HyperbolicSine(); return FUNCTION; } sum { poincare_expression_yylval.expression = Sum(); return FUNCTION; } diff --git a/poincare/src/round.cpp b/poincare/src/round.cpp index f1d79d6f2..5c2d6990c 100644 --- a/poincare/src/round.cpp +++ b/poincare/src/round.cpp @@ -10,13 +10,31 @@ extern "C" { namespace Poincare { -ExpressionNode::Type Round::type() const { - return Type::Round; +RoundNode * RoundNode::FailedAllocationStaticNode() { + static AllocationFailureExpressionNode failure; + TreePool::sharedPool()->registerStaticNodeIfRequired(&failure); + return &failure; } -Expression * Round::clone() const { - Round * c = new Round(m_operands, true); - return c; +LayoutReference RoundNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + return LayoutHelper::Prefix(Round(this), floatDisplayMode, numberOfSignificantDigits, name()); +} + +Expression RoundNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const { + return Round(this).shallowReduce(context, angleUnit); +} + +template +Evaluation RoundNode::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(f2) || f2 != std::round(f2)) { + return Complex::Undefined(); + } + T err = std::pow(10, std::floor(f2)); + return Complex(std::round(f1*err)/err); } Expression Round::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const { @@ -25,46 +43,30 @@ Expression Round::shallowReduce(Context& context, Preferences::AngleUnit angleUn return e; } #if MATRIX_EXACT_REDUCING - if (childAtIndex(0)->type() == Type::Matrix || childAtIndex(1)->type() == Type::Matrix) { - return replaceWith(new Undefined(), true); + if (childAtIndex(0).type() == ExpressionNode::Type::Matrix || childAtIndex(1).type() == ExpressionNode::Type::Matrix) { + return Undefined(); } #endif - if (childAtIndex(0)->type() == Type::Rational && childAtIndex(1)->type() == Type::Rational) { - Rational * r1 = static_cast(childAtIndex(0)); - Rational * r2 = static_cast(childAtIndex(1)); - if (!r2->denominator().isOne()) { - return replaceWith(new Undefined(), true); + if (childAtIndex(0).type() == ExpressionNode::Type::Rational && childAtIndex(1).type() == ExpressionNode::Type::Rational) { + Rational r1 = static_cast(childAtIndex(0)); + Rational r2 = static_cast(childAtIndex(1)); + if (!r2.integerDenominator().isOne()) { + return Undefined(); } const Rational ten(10); - if (Power::RationalExponentShouldNotBeReduced(&ten, r2)) { - return this; + if (Power::RationalExponentShouldNotBeReduced(ten, r2)) { + return *this; } - Rational err = Rational::Power(ten, r2->numerator()); - Rational mult = Rational::Multiplication(*r1, err); - IntegerDivision d = Integer::Division(mult.numerator(), mult.denominator()); + Rational err = Rational::IntegerPower(ten, r2.signedIntegerNumerator()); + Rational mult = Rational::Multiplication(r1, err); + IntegerDivision d = Integer::Division(mult.signedIntegerNumerator(), mult.integerDenominator()); Integer rounding = d.quotient; - if (Rational::NaturalOrder(Rational(d.remainder, mult.denominator()), Rational(1,2)) >= 0) { + if (Rational::NaturalOrder(Rational(d.remainder, mult.integerDenominator()), Rational(1,2)) >= 0) { rounding = Integer::Addition(rounding, Integer(1)); } - Rational result = Rational::Multiplication(rounding, Rational::Power(Rational(1,10), r2->numerator())); - return replaceWith(new Rational(result), true); + return Rational::Multiplication(rounding, Rational::IntegerPower(Rational(1,10), r2.signedIntegerNumerator())); } - return this; // TODO: implement for rationals! -} - -template -Complex * Round::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(); - delete f1Input; - delete f2Input; - if (std::isnan(f2) || f2 != std::round(f2)) { - return new Complex(Complex::Undefined()); - } - T err = std::pow(10, std::floor(f2)); - return new Complex(std::round(f1*err)/err); + return *this; } } diff --git a/poincare/test/function.cpp b/poincare/test/function.cpp index a8fd207b7..5c92a39e7 100644 --- a/poincare/test/function.cpp +++ b/poincare/test/function.cpp @@ -56,9 +56,7 @@ QUIZ_CASE(poincare_parse_function) { assert_parsed_expression_type("rem(29, 10)", ExpressionNode::Type::DivisionRemainder); assert_parsed_expression_type("root(2,3)", ExpressionNode::Type::NthRoot); assert_parsed_expression_type("R(2)", ExpressionNode::Type::SquareRoot); -#if 0 assert_parsed_expression_type("round(2,3)", ExpressionNode::Type::Round); -#endif assert_parsed_expression_type("sum(n, 4, 10)", ExpressionNode::Type::Sum); #if MATRICES_ARE_DEFINED assert_parsed_expression_type("trace([[1,2,3][4,5,6][7,8,9]])", ExpressionNode::Type::MatrixTrace); @@ -208,11 +206,9 @@ QUIZ_CASE(poincare_function_evaluate) { assert_parsed_expression_evaluates_to("transpose([[1,2][4,5][7,8]])", "[[1,4,7][2,5,8]]"); #endif -#if 0 assert_parsed_expression_evaluates_to("round(2.3246,3)", "2.325"); assert_parsed_expression_evaluates_to("round(2.3245,3)", "2.325"); -#endif assert_parsed_expression_evaluates_to("6!", "720"); assert_parsed_expression_evaluates_to("6!", "720"); @@ -273,12 +269,12 @@ QUIZ_CASE(poincare_function_simplify) { assert_parsed_expression_simplify_to("root(4,3)", "root(4,3)"); assert_parsed_expression_simplify_to("root(4,P)", "4^(1/P)"); assert_parsed_expression_simplify_to("root(27,3)", "3"); -#if 0 assert_parsed_expression_simplify_to("round(4.235,2)", "106/25"); assert_parsed_expression_simplify_to("round(4.23,0)", "4"); assert_parsed_expression_simplify_to("round(4.9,0)", "5"); assert_parsed_expression_simplify_to("round(12.9,-1)", "10"); assert_parsed_expression_simplify_to("round(12.9,-2)", "0"); +#if 0 assert_parsed_expression_simplify_to("permute(99,4)", "90345024"); assert_parsed_expression_simplify_to("permute(20,-10)", "undef"); #endif