From f3da453fc07dd9ccc27ec1d2b5d81a3f8eacb893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 17 Apr 2017 17:15:40 +0200 Subject: [PATCH] [poincare] Implement factorial Change-Id: I2344d12fdc9084db84247a096110efe0e909e32a --- poincare/Makefile | 1 + poincare/include/poincare.h | 1 + poincare/include/poincare/expression.h | 1 + poincare/include/poincare/factorial.h | 21 ++++++++++ poincare/src/expression_lexer.l | 1 + poincare/src/expression_parser.y | 5 ++- poincare/src/factorial.cpp | 53 ++++++++++++++++++++++++++ 7 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 poincare/include/poincare/factorial.h create mode 100644 poincare/src/factorial.cpp diff --git a/poincare/Makefile b/poincare/Makefile index 1fe6ef78a..7856f0252 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -23,6 +23,7 @@ objs += $(addprefix poincare/src/,\ expression.o\ expression_lexer.o\ expression_parser.o\ + factorial.o\ floor.o\ frac_part.o\ fraction.o\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index 651983e25..9fd9495dc 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index a97688441..8b3553954 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -27,6 +27,7 @@ public: Determinant, DivisionQuotient, DivisionRemainder, + Factorial, Float, Floor, FracPart, diff --git a/poincare/include/poincare/factorial.h b/poincare/include/poincare/factorial.h new file mode 100644 index 000000000..fa1e0bff3 --- /dev/null +++ b/poincare/include/poincare/factorial.h @@ -0,0 +1,21 @@ +#ifndef POINCARE_FACTORIAL_H +#define POINCARE_FACTORIAL_H + +#include + +namespace Poincare { + +class Factorial : public Function { +public: + Factorial(Expression * argument, bool clone = true); + Type type() const override; + Expression * cloneWithDifferentOperands(Expression ** newOperands, + int numberOfOperands, bool cloneOperands = true) const override; +private: + float privateApproximate(Context & context, AngleUnit angleUnit) const override; + ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; +}; + +} + +#endif diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index bea52a4a6..db3f93e61 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -145,6 +145,7 @@ inf { poincare_expression_yylval.expression = new Complex(Complex::Float(INFINIT \* { return MULTIPLY; } \/ { return DIVIDE; } \^ { return POW; } +\! { return BANG; } \( { return LEFT_PARENTHESIS; } \) { return RIGHT_PARENTHESIS; } \{ { return LEFT_BRACE; } diff --git a/poincare/src/expression_parser.y b/poincare/src/expression_parser.y index 23846942b..5f0f7f803 100644 --- a/poincare/src/expression_parser.y +++ b/poincare/src/expression_parser.y @@ -58,6 +58,7 @@ void poincare_expression_yyerror(Poincare::Expression ** expressionOutput, char %token MULTIPLY %token DIVIDE %token POW +%token BANG %token LEFT_PARENTHESIS %token RIGHT_PARENTHESIS %token LEFT_BRACE @@ -89,6 +90,7 @@ void poincare_expression_yyerror(Poincare::Expression ** expressionOutput, char %left MULTIPLY %left DIVIDE %left POW +%left BANG /* The "exp" symbol uses the "expression" part of the union. */ %type exp; @@ -131,7 +133,8 @@ symb: exp: UNDEFINED { $$ = $1; } - | exp STO symb {$$ = new Poincare::Store($3, $1, false); } + | exp BANG { $$ = new Poincare::Factorial($1, false); } + | exp STO symb { $$ = new Poincare::Store($3, $1, false); } | number { $$ = $1; } | ICOMPLEX { $$ = new Poincare::Complex(Poincare::Complex::Cartesian(0.0f, 1.0f)); } | symb { $$ = $1; } diff --git a/poincare/src/factorial.cpp b/poincare/src/factorial.cpp new file mode 100644 index 000000000..2a60f1cfc --- /dev/null +++ b/poincare/src/factorial.cpp @@ -0,0 +1,53 @@ +#include +#include "layout/string_layout.h" +#include "layout/horizontal_layout.h" +extern "C" { +#include +#include +} + +namespace Poincare { + +Factorial::Factorial(Expression * argument, bool clone) : + Function("fact") +{ + setArgument(&argument, 1, clone); +} + +Expression::Type Factorial::type() const { + return Type::Factorial; +} + +Expression * Factorial::cloneWithDifferentOperands(Expression** newOperands, + int numberOfOperands, bool cloneOperands) const { + assert(newOperands != nullptr); + Factorial * f = new Factorial(newOperands[0], cloneOperands); + return f; +} + +float Factorial::privateApproximate(Context& context, AngleUnit angleUnit) const { + assert(angleUnit != AngleUnit::Default); + float n = m_args[0]->approximate(context, angleUnit); + if (isnan(n) || n != (int)n || n < 0.0f) { + return NAN; + } + float result = 1.0f; + for (int i = 1; i <= (int)n; i++) { + result *= (float)i; + if (isinf(result)) { + return result; + } + } + return roundf(result); +} + +ExpressionLayout * Factorial::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { + assert(floatDisplayMode != FloatDisplayMode::Default); + assert(complexFormat != ComplexFormat::Default); + ExpressionLayout * childrenLayouts[2]; + childrenLayouts[0] = m_args[0]->createLayout(floatDisplayMode, complexFormat); + childrenLayouts[1] = new StringLayout("!", 1); + return new HorizontalLayout(childrenLayouts, 2); +} + +}