From c59d8d7bd53dbd1eeabafae86067acaeeb2ba960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 27 Oct 2017 11:47:24 +0200 Subject: [PATCH] [poincare] Imporve tangent to resolve tan/sin = 1/cos Change-Id: I7e23c7f680b6702c373bcc78f553bcb0c22bd574 --- poincare/include/poincare/multiplication.h | 4 ++++ poincare/include/poincare/rational.h | 1 + poincare/include/poincare/trigonometry.h | 1 + poincare/src/tangent.cpp | 14 +++++++++++++- poincare/src/trigonometry.cpp | 17 ++++++++++++++++- 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/poincare/include/poincare/multiplication.h b/poincare/include/poincare/multiplication.h index f9ce6c1bf..717aeea45 100644 --- a/poincare/include/poincare/multiplication.h +++ b/poincare/include/poincare/multiplication.h @@ -40,6 +40,7 @@ private: int writeTextInBuffer(char * buffer, int bufferSize) const override; /* Simplification */ void factorize(Context & context, AngleUnit angleUnit); + bool resolveSquareRootAtDenominator(Context & context, AngleUnit angleUnit); void factorizeBase(Expression * e1, Expression * e2, Context & context, AngleUnit angleUnit); void factorizeExponent(Expression * e1, Expression * e2, Context & context, AngleUnit angleUnit); Expression * distributeOnChildAtIndex(int index, Context & context, AngleUnit angleUnit); @@ -47,6 +48,9 @@ private: static bool TermsHaveIdenticalNonUnitaryExponent(const Expression * e1, const Expression * e2); static bool TermHasRationalBase(const Expression * e); static bool TermHasIntegerExponent(const Expression * e); + static bool TermIsARationalSquareRootOrRational(const Expression * e); + static const Rational * RadicandInExpression(const Expression * e); + static const Rational * RationalFactorInExpression(const Expression * e); static const Expression * CreateExponent(Expression * e); bool isUselessOperand(const Rational * r) override; // Warning: mergeNegativePower not always returns a multiplication: *(b^-1,c^-1) -> (bc)^-1 diff --git a/poincare/include/poincare/rational.h b/poincare/include/poincare/rational.h index 735ed549b..8c01e43d0 100644 --- a/poincare/include/poincare/rational.h +++ b/poincare/include/poincare/rational.h @@ -31,6 +31,7 @@ public: bool isZero() const { return m_numerator.isZero(); } bool isOne() const { return m_numerator.isOne() && m_denominator.isOne(); } bool isMinusOne() const { return m_numerator.isMinusOne() && m_denominator.isOne(); } + bool isHalf() const { return m_numerator.isOne() && m_denominator.isTwo(); } bool isMinusHalf() const { return m_numerator.isMinusOne() && m_denominator.isTwo(); } // Arithmetic diff --git a/poincare/include/poincare/trigonometry.h b/poincare/include/poincare/trigonometry.h index f295a3939..382bd6fec 100644 --- a/poincare/include/poincare/trigonometry.h +++ b/poincare/include/poincare/trigonometry.h @@ -13,6 +13,7 @@ public: }; static Expression * immediateSimplifyDirectFunction(Expression * e, Context& context, Expression::AngleUnit angleUnit); static Expression * immediateSimplifyInverseFunction(Expression * e, Context& context, Expression::AngleUnit angleUnit); + static bool ExpressionIsEquivalentToTangent(const Expression * e); constexpr static int k_numberOfEntries = 31; static Expression * table(const Expression * e, Expression::Type type, Context & context, Expression::AngleUnit angleUnit); // , Function f, bool inverse }; diff --git a/poincare/src/tangent.cpp b/poincare/src/tangent.cpp index 42d5ccde9..c8b01593b 100644 --- a/poincare/src/tangent.cpp +++ b/poincare/src/tangent.cpp @@ -23,7 +23,19 @@ Expression * Tangent::clone() const { } Expression * Tangent::immediateSimplify(Context& context, AngleUnit angleUnit) { - return Trigonometry::immediateSimplifyDirectFunction(this, context, angleUnit); + Expression * newExpression = Trigonometry::immediateSimplifyDirectFunction(this, context, angleUnit); + if (newExpression->type() == Type::Tangent) { + const Expression * op[1] = {newExpression->operand(0)}; + Sine * s = new Sine(op, true); + Cosine * c = new Cosine(op, true); + const Expression * divisionOperands[2] = {s, c}; + Division * d = new Division(divisionOperands, false); + c->immediateSimplify(context, angleUnit); + s->immediateSimplify(context, angleUnit); + newExpression = newExpression->replaceWith(d, true); + return newExpression->simplify(context, angleUnit); + } + return newExpression; } template diff --git a/poincare/src/trigonometry.cpp b/poincare/src/trigonometry.cpp index 24648ff99..ec104e592 100644 --- a/poincare/src/trigonometry.cpp +++ b/poincare/src/trigonometry.cpp @@ -75,6 +75,14 @@ Expression * Trigonometry::immediateSimplifyDirectFunction(Expression * e, Conte return e; } +bool Trigonometry::ExpressionIsEquivalentToTangent(const Expression * e) { + assert(Expression::Type::Power < Expression::Type::Sine); + if (e->type() == Expression::Type::Multiplication && e->operand(1)->type() == Expression::Type::Sine && e->operand(0)->type() == Expression::Type::Power && e->operand(0)->operand(0)->type() == Expression::Type::Cosine && e->operand(0)->operand(1)->type() == Expression::Type::Rational && static_cast(e->operand(0)->operand(1))->isMinusOne()) { + return true; + } + return false; +} + Expression * Trigonometry::immediateSimplifyInverseFunction(Expression * e, Context& context, Expression::AngleUnit angleUnit) { assert(e->type() == Expression::Type::ArcCosine || e->type() == Expression::Type::ArcSine || e->type() == Expression::Type::ArcTangent); if (e->type() != Expression::Type::ArcTangent) { @@ -84,15 +92,22 @@ Expression * Trigonometry::immediateSimplifyInverseFunction(Expression * e, Cont } } Expression::Type correspondingType = e->type() == Expression::Type::ArcCosine ? Expression::Type::Cosine : (e->type() == Expression::Type::ArcSine ? Expression::Type::Sine : Expression::Type::Tangent); + float pi = angleUnit == Expression::AngleUnit::Radian ? M_PI : 180; if (e->operand(0)->type() == correspondingType) { float trigoOp = e->operand(0)->operand(0)->approximate(context, angleUnit); - float pi = angleUnit == Expression::AngleUnit::Radian ? M_PI : 180; if ((e->type() == Expression::Type::ArcCosine && trigoOp >= 0.0f && trigoOp <= pi) || (e->type() == Expression::Type::ArcSine && trigoOp >= -pi/2.0f && trigoOp <= pi/2.0f) || (e->type() == Expression::Type::ArcTangent && trigoOp >= -pi/2.0f && trigoOp <= pi/2.0f)) { return e->replaceWith(const_cast(e->operand(0)->operand(0)), true); } } + // Special case for arctan(sin(x)/cos(x)) + if (e->type() == Expression::Type::ArcTangent && ExpressionIsEquivalentToTangent(e->operand(0))) { + float trigoOp = e->operand(0)->operand(1)->operand(0)->approximate(context, angleUnit); + if (trigoOp >= -pi/2.0f && trigoOp <= pi/2.0f) { + return e->replaceWith(const_cast(e->operand(0)->operand(1)->operand(0)), true); + } + } Expression * lookup = Trigonometry::table(e->operand(0), e->type(), context, angleUnit); if (lookup != nullptr) { return e->replaceWith(lookup, true);