From 3f246d8b722b1300aef2ebe55e2e3440d102c809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 12 Apr 2017 10:33:31 +0200 Subject: [PATCH] [poincare] Cheat on trigonometric functions Change-Id: If49f6e25403dcf09736e1cd3e9c5f25bba140af3 --- poincare/Makefile | 1 + poincare/include/poincare/cosine.h | 8 ++-- poincare/include/poincare/sine.h | 8 ++-- poincare/include/poincare/tangent.h | 8 ++-- .../include/poincare/trigonometric_function.h | 20 ++++++++ poincare/src/cosine.cpp | 29 +++--------- poincare/src/sine.cpp | 37 ++++----------- poincare/src/tangent.cpp | 31 +++--------- poincare/src/trigonometric_function.cpp | 47 +++++++++++++++++++ 9 files changed, 103 insertions(+), 86 deletions(-) create mode 100644 poincare/include/poincare/trigonometric_function.h create mode 100644 poincare/src/trigonometric_function.cpp diff --git a/poincare/Makefile b/poincare/Makefile index 937f3e2a9..1fe6ef78a 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -67,6 +67,7 @@ objs += $(addprefix poincare/src/,\ sum.o\ symbol.o\ tangent.o\ + trigonometric_function.o\ variable_context.o\ ) objs += $(addprefix poincare/src/layout/,\ diff --git a/poincare/include/poincare/cosine.h b/poincare/include/poincare/cosine.h index 5277d9a33..aa9a03a4f 100644 --- a/poincare/include/poincare/cosine.h +++ b/poincare/include/poincare/cosine.h @@ -1,19 +1,19 @@ #ifndef POINCARE_COSINE_H #define POINCARE_COSINE_H -#include +#include namespace Poincare { -class Cosine : public Function { +class Cosine : public TrigonometricFunction { public: Cosine(); Type type() const override; Expression * cloneWithDifferentOperands(Expression ** newOperands, int numberOfOperands, bool cloneOperands = true) const override; private: - float privateApproximate(Context & context, AngleUnit angleUnit) const override; - Expression * privateEvaluate(Context& context, AngleUnit angleUnit) const override; + float trigonometricApproximation(float x) const override; + Expression * createComplexEvaluation(Expression * arg, Context & context, AngleUnit angleUnit) const override; }; } diff --git a/poincare/include/poincare/sine.h b/poincare/include/poincare/sine.h index e2c7bfe85..0d6eba683 100644 --- a/poincare/include/poincare/sine.h +++ b/poincare/include/poincare/sine.h @@ -1,19 +1,19 @@ #ifndef POINCARE_SINE_H #define POINCARE_SINE_H -#include +#include namespace Poincare { -class Sine : public Function { +class Sine : public TrigonometricFunction { public: Sine(); Type type() const override; Expression * cloneWithDifferentOperands(Expression ** newOperands, int numberOfOperands, bool cloneOperands = true) const override; private: - float privateApproximate(Context & context, AngleUnit angleUnit) const override; - Expression * privateEvaluate(Context& context, AngleUnit angleUnit) const override; + float trigonometricApproximation(float x) const override; + Expression * createComplexEvaluation(Expression * arg, Context & context, AngleUnit angleUnit) const override; }; } diff --git a/poincare/include/poincare/tangent.h b/poincare/include/poincare/tangent.h index c44ce6e3c..9da1383bf 100644 --- a/poincare/include/poincare/tangent.h +++ b/poincare/include/poincare/tangent.h @@ -1,19 +1,19 @@ #ifndef POINCARE_TANGENT_H #define POINCARE_TANGENT_H -#include +#include namespace Poincare { -class Tangent : public Function { +class Tangent : public TrigonometricFunction { public: Tangent(); Type type() const override; Expression * cloneWithDifferentOperands(Expression ** newOperands, int numnerOfOperands, bool cloneOperands = true) const override; private: - float privateApproximate(Context & context, AngleUnit angleUnit) const override; - Expression * privateEvaluate(Context& context, AngleUnit angleUnit) const override; + float trigonometricApproximation(float x) const override; + Expression * createComplexEvaluation(Expression * arg, Context & context, AngleUnit angleUnit) const override; }; } diff --git a/poincare/include/poincare/trigonometric_function.h b/poincare/include/poincare/trigonometric_function.h new file mode 100644 index 000000000..d20bcc877 --- /dev/null +++ b/poincare/include/poincare/trigonometric_function.h @@ -0,0 +1,20 @@ +#ifndef POINCARE_TRIGONOMETRIC_FUNCTION_H +#define POINCARE_TRIGONOMETRIC_FUNCTION_H + +#include + +namespace Poincare { + +class TrigonometricFunction : public Function { +public: + TrigonometricFunction(const char * name); +private: + float privateApproximate(Context & context, AngleUnit angleUnit) const override; + Expression * privateEvaluate(Context& context, AngleUnit angleUnit) const override; + virtual float trigonometricApproximation(float x) const = 0; + virtual Expression * createComplexEvaluation(Expression * arg, Context & context, AngleUnit angleUnit) const = 0; +}; + +} + +#endif diff --git a/poincare/src/cosine.cpp b/poincare/src/cosine.cpp index 181c9a6f2..84eef7922 100644 --- a/poincare/src/cosine.cpp +++ b/poincare/src/cosine.cpp @@ -9,7 +9,7 @@ extern "C" { namespace Poincare { Cosine::Cosine() : - Function("cos") + TrigonometricFunction("cos") { } @@ -25,32 +25,15 @@ Expression * Cosine::cloneWithDifferentOperands(Expression** newOperands, return c; } -float Cosine::privateApproximate(Context& context, AngleUnit angleUnit) const { - assert(angleUnit != AngleUnit::Default); - if (angleUnit == AngleUnit::Degree) { - return cosf(m_args[0]->approximate(context, angleUnit)*M_PI/180.0f); - } - return cosf(m_args[0]->approximate(context, angleUnit)); +float Cosine::trigonometricApproximation(float x) const { + return cosf(x); } -Expression * Cosine::privateEvaluate(Context& context, AngleUnit angleUnit) const { - assert(angleUnit != AngleUnit::Default); - Expression * evaluation = m_args[0]->evaluate(context, angleUnit); - assert(evaluation->type() == Type::Matrix || evaluation->type() == Type::Complex); - if (evaluation->type() == Type::Matrix) { - delete evaluation; - return new Complex(Complex::Float(NAN)); - } - /* Float case */ - if (((Complex *)evaluation)->b() == 0) { - delete evaluation; - return Function::privateEvaluate(context, angleUnit); - } - /* Complex case */ - Expression * arg = new Complex(Complex::Cartesian(-((Complex *)evaluation)->b(), ((Complex *)evaluation)->a())); +Expression * Cosine::createComplexEvaluation(Expression * exp, Context & context, AngleUnit angleUnit) const { + assert(exp->type() == Type::Complex); + Expression * arg = new Complex(Complex::Cartesian(-((Complex *)exp)->b(), ((Complex *)exp)->a())); Function * cosh = new HyperbolicCosine(); cosh->setArgument(&arg, 1, true); - delete evaluation; delete arg; Expression * resultEvaluation = cosh->evaluate(context, angleUnit); delete cosh; diff --git a/poincare/src/sine.cpp b/poincare/src/sine.cpp index 423bf2150..ab72a6e7c 100644 --- a/poincare/src/sine.cpp +++ b/poincare/src/sine.cpp @@ -10,10 +10,14 @@ extern "C" { namespace Poincare { Sine::Sine() : - Function("sin") + TrigonometricFunction("sin") { } +Expression::Type Sine::type() const { + return Expression::Type::Sine; +} + Expression * Sine::cloneWithDifferentOperands(Expression** newOperands, int numberOfOperands, bool cloneOperands) const { assert(newOperands != nullptr); @@ -22,36 +26,15 @@ Expression * Sine::cloneWithDifferentOperands(Expression** newOperands, return s; } -Expression::Type Sine::type() const { - return Expression::Type::Sine; +float Sine::trigonometricApproximation(float x) const { + return sinf(x); } -float Sine::privateApproximate(Context& context, AngleUnit angleUnit) const { - assert(angleUnit != AngleUnit::Default); - if (angleUnit == AngleUnit::Degree) { - return sinf(m_args[0]->approximate(context, angleUnit)*M_PI/180.0f); - } - return sinf(m_args[0]->approximate(context, angleUnit)); -} - -Expression * Sine::privateEvaluate(Context& context, AngleUnit angleUnit) const { - assert(angleUnit != AngleUnit::Default); - Expression * evaluation = m_args[0]->evaluate(context, angleUnit); - assert(evaluation->type() == Type::Matrix || evaluation->type() == Type::Complex); - if (evaluation->type() == Type::Matrix) { - delete evaluation; - return new Complex(Complex::Float(NAN)); - } - /* Float case */ - if (((Complex *)evaluation)->b() == 0) { - delete evaluation; - return Function::privateEvaluate(context, angleUnit); - } - /* Complex case */ - Expression * arg = new Complex(Complex::Cartesian(-((Complex *)evaluation)->b(), ((Complex *)evaluation)->a())); +Expression * Sine::createComplexEvaluation(Expression * exp, Context & context, AngleUnit angleUnit) const { + assert(exp->type() == Type::Complex); + Expression * arg = new Complex(Complex::Cartesian(-((Complex *)exp)->b(), ((Complex *)exp)->a())); Function * sinh = new HyperbolicSine(); sinh->setArgument(&arg, 1, true); - delete evaluation; delete arg; Expression * args[2]; args[0] = new Complex(Complex::Cartesian(0.0f, -1.0f)); diff --git a/poincare/src/tangent.cpp b/poincare/src/tangent.cpp index e1c709e65..03d964d7f 100644 --- a/poincare/src/tangent.cpp +++ b/poincare/src/tangent.cpp @@ -11,7 +11,7 @@ extern "C" { namespace Poincare { Tangent::Tangent() : - Function("tan") + TrigonometricFunction("tan") { } @@ -27,34 +27,17 @@ Expression::Type Tangent::type() const { return Expression::Type::Tangent; } -float Tangent::privateApproximate(Context& context, AngleUnit angleUnit) const { - assert(angleUnit != AngleUnit::Default); - if (angleUnit == AngleUnit::Degree) { - return tanf(m_args[0]->approximate(context, angleUnit)*M_PI/180.0f); - } - return tanf(m_args[0]->approximate(context, angleUnit)); +float Tangent::trigonometricApproximation(float x) const { + return tanf(x); } -Expression * Tangent::privateEvaluate(Context& context, AngleUnit angleUnit) const { - assert(angleUnit != AngleUnit::Default); - Expression * evaluation = m_args[0]->evaluate(context, angleUnit); - assert(evaluation->type() == Type::Matrix || evaluation->type() == Type::Complex); - if (evaluation->type() == Type::Matrix) { - delete evaluation; - return new Complex(Complex::Float(NAN)); - } - /* Float case */ - if (((Complex *)evaluation)->b() == 0) { - delete evaluation; - return Function::privateEvaluate(context, angleUnit); - } - /* Complex case */ +Expression * Tangent::createComplexEvaluation(Expression * exp, Context & context, AngleUnit angleUnit) const { + assert(exp->type() == Type::Complex); Expression * arguments[2]; arguments[0] = new Sine(); - ((Function *)arguments[0])->setArgument(&evaluation, 1, true); + ((Function *)arguments[0])->setArgument(&exp, 1, true); arguments[1] = new Cosine(); - ((Function *)arguments[1])->setArgument(&evaluation, 1, true); - delete evaluation; + ((Function *)arguments[1])->setArgument(&exp, 1, true); Expression * result = new Fraction(arguments, true); delete arguments[1]; delete arguments[0]; diff --git a/poincare/src/trigonometric_function.cpp b/poincare/src/trigonometric_function.cpp new file mode 100644 index 000000000..797a6825f --- /dev/null +++ b/poincare/src/trigonometric_function.cpp @@ -0,0 +1,47 @@ +#include +#include +extern "C" { +#include +#include +} + +namespace Poincare { + +TrigonometricFunction::TrigonometricFunction(const char * name) : + Function(name) +{ +} + +float TrigonometricFunction::privateApproximate(Context& context, AngleUnit angleUnit) const { + assert(angleUnit != AngleUnit::Default); + float input = m_args[0]->approximate(context, angleUnit); + if (angleUnit == AngleUnit::Degree) { + input *= M_PI/180.0f; + } + float result = trigonometricApproximation(input); + if (input != 0.0f && fabsf(result/input) <= 1E-7f) { + return 0.0f; + } + return result; +} + +Expression * TrigonometricFunction::privateEvaluate(Context& context, AngleUnit angleUnit) const { + assert(angleUnit != AngleUnit::Default); + Expression * evaluation = m_args[0]->evaluate(context, angleUnit); + assert(evaluation->type() == Type::Matrix || evaluation->type() == Type::Complex); + if (evaluation->type() == Type::Matrix) { + delete evaluation; + return new Complex(Complex::Float(NAN)); + } + /* Float case */ + if (((Complex *)evaluation)->b() == 0) { + delete evaluation; + return Function::privateEvaluate(context, angleUnit); + } + /* Complex case */ + Expression * resultEvaluation = createComplexEvaluation(evaluation, context, angleUnit); + delete evaluation; + return resultEvaluation; +} + +}