[poincare] Implement factorial

Change-Id: I2344d12fdc9084db84247a096110efe0e909e32a
This commit is contained in:
Émilie Feral
2017-04-17 17:15:40 +02:00
parent ec746f3223
commit f3da453fc0
7 changed files with 82 additions and 1 deletions

View File

@@ -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\

View File

@@ -19,6 +19,7 @@
#include <poincare/division_quotient.h>
#include <poincare/division_remainder.h>
#include <poincare/expression.h>
#include <poincare/factorial.h>
#include <poincare/floor.h>
#include <poincare/frac_part.h>
#include <poincare/fraction.h>

View File

@@ -27,6 +27,7 @@ public:
Determinant,
DivisionQuotient,
DivisionRemainder,
Factorial,
Float,
Floor,
FracPart,

View File

@@ -0,0 +1,21 @@
#ifndef POINCARE_FACTORIAL_H
#define POINCARE_FACTORIAL_H
#include <poincare/function.h>
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

View File

@@ -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; }

View File

@@ -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 <expression> 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; }

View File

@@ -0,0 +1,53 @@
#include <poincare/factorial.h>
#include "layout/string_layout.h"
#include "layout/horizontal_layout.h"
extern "C" {
#include <assert.h>
#include <math.h>
}
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);
}
}