[poincare] Cheat on trigonometric functions

Change-Id: If49f6e25403dcf09736e1cd3e9c5f25bba140af3
This commit is contained in:
Émilie Feral
2017-04-12 10:33:31 +02:00
parent 8b355814ec
commit 3f246d8b72
9 changed files with 103 additions and 86 deletions

View File

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

View File

@@ -1,19 +1,19 @@
#ifndef POINCARE_COSINE_H
#define POINCARE_COSINE_H
#include <poincare/function.h>
#include <poincare/trigonometric_function.h>
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;
};
}

View File

@@ -1,19 +1,19 @@
#ifndef POINCARE_SINE_H
#define POINCARE_SINE_H
#include <poincare/function.h>
#include <poincare/trigonometric_function.h>
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;
};
}

View File

@@ -1,19 +1,19 @@
#ifndef POINCARE_TANGENT_H
#define POINCARE_TANGENT_H
#include <poincare/function.h>
#include <poincare/trigonometric_function.h>
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;
};
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,47 @@
#include <poincare/trigonometric_function.h>
#include <poincare/complex.h>
extern "C" {
#include <assert.h>
#include <math.h>
}
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;
}
}