[poincare] Imporve tangent to resolve tan/sin = 1/cos

Change-Id: I7e23c7f680b6702c373bcc78f553bcb0c22bd574
This commit is contained in:
Émilie Feral
2017-10-27 11:47:24 +02:00
parent 7a54b2b0c4
commit c59d8d7bd5
5 changed files with 35 additions and 2 deletions

View File

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

View File

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

View File

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

View File

@@ -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<typename T>

View File

@@ -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<const Rational *>(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<float>(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<Expression *>(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<float>(context, angleUnit);
if (trigoOp >= -pi/2.0f && trigoOp <= pi/2.0f) {
return e->replaceWith(const_cast<Expression *>(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);