diff --git a/apps/calculation/app.cpp b/apps/calculation/app.cpp index 1ad45263a..701ce5926 100644 --- a/apps/calculation/app.cpp +++ b/apps/calculation/app.cpp @@ -54,4 +54,34 @@ Context * App::localContext() { return &m_localContext; } +bool App::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) { + if ((event == Ion::Events::Var || event == Ion::Events::XNT) && TextFieldDelegateApp::textFieldDidReceiveEvent(textField, event)) { + return true; + } + /* Here, we check that the expression entered by the user can be printed with + * less than k_printedExpressionLength characters. Otherwise, we prevent the + * user from adding this expression to the calculation store. */ + if (textField->isEditing() && textField->textFieldShouldFinishEditing(event)) { + Expression * exp = Expression::parse(textField->text()); + if (exp == nullptr) { + textField->app()->displayWarning(I18n::Message::SyntaxError); + return true; + } + char buffer[Calculation::k_printedExpressionSize]; + int length = exp->writeTextInBuffer(buffer, sizeof(buffer)); + delete exp; + /* if the buffer is totally full, it is VERY likely that writeTextInBuffer + * escaped before printing utterly the expression. */ + if (length >= Calculation::k_printedExpressionSize-1) { + displayWarning(I18n::Message::SyntaxError); + return true; + } + } + return false; +} + +const char * App::XNT() { + return "x"; +} + } diff --git a/apps/calculation/app.h b/apps/calculation/app.h index f44c97e3c..a9b616599 100644 --- a/apps/calculation/app.h +++ b/apps/calculation/app.h @@ -29,6 +29,8 @@ public: CalculationStore m_calculationStore; }; Poincare::Context * localContext() override; + bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override; + const char * XNT() override; private: App(Container * container, Snapshot * snapshot); LocalContext m_localContext; diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index 72a9ba3cf..d86664b0b 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -66,11 +66,13 @@ void Calculation::reset() { void Calculation::setContent(const char * c, Context * context) { reset(); m_input = Expression::parse(c); + /* We do not store directly the text enter by the user but its serialization + * to be able to compare it to the exact ouput text. */ m_input->writeTextInBuffer(m_inputText, sizeof(m_inputText)); m_exactOutput = input()->clone(); Expression::Simplify(&m_exactOutput, *context); m_exactOutput->writeTextInBuffer(m_exactOutputText, sizeof(m_exactOutputText)); - m_approximateOutput = m_exactOutput->evaluate(*context); + m_approximateOutput = m_exactOutput->approximate(*context); m_approximateOutput->writeTextInBuffer(m_approximateOutputText, sizeof(m_approximateOutputText)); } @@ -189,7 +191,7 @@ Expression * Calculation::approximateOutput(Context * context) { * call 'evaluate'. */ Expression * exp = Expression::parse(m_approximateOutputText); if (exp != nullptr) { - m_approximateOutput = exp->evaluate(*context); + m_approximateOutput = exp->approximate(*context); delete exp; } else { m_approximateOutput = new Complex(Complex::Float(NAN)); @@ -213,7 +215,7 @@ bool Calculation::shouldApproximateOutput() { return true; } return input()->recursivelyMatches([](const Expression * e) { - return e->type() == Expression::Type::Decimal || Expression::IsMatrix(e); + return e->type() == Expression::Type::Decimal || Expression::IsMatrix(e) || (e->type() == Expression::Type::Symbol && static_cast(e)->isScalarSymbol()); }); } diff --git a/apps/calculation/calculation.h b/apps/calculation/calculation.h index e85e4dc2b..58ebf6a35 100644 --- a/apps/calculation/calculation.h +++ b/apps/calculation/calculation.h @@ -31,11 +31,15 @@ public: bool isEmpty(); void tidy(); bool shouldApproximateOutput(); + constexpr static int k_printedExpressionSize = 2*::TextField::maxBufferSize(); private: Poincare::Expression * exactOutput(Poincare::Context * context); - char m_inputText[::TextField::maxBufferSize()]; - char m_exactOutputText[2*::TextField::maxBufferSize()]; - char m_approximateOutputText[2*::TextField::maxBufferSize()]; + /* Buffers holding text expressions have to be longer than the text written + * by user (of maximum length TextField::maxBufferSize()) because when we + * print an expression we add omitted signs (multiplications, parenthesis...) */ + char m_inputText[k_printedExpressionSize]; + char m_exactOutputText[k_printedExpressionSize]; + char m_approximateOutputText[k_printedExpressionSize]; Poincare::Expression * m_input; Poincare::ExpressionLayout * m_inputLayout; Poincare::Expression * m_exactOutput; diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index ca2b1e699..5214000b5 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -160,9 +160,14 @@ KDCoordinate HistoryController::rowHeight(int j) { Calculation * calculation = m_calculationStore->calculationAtIndex(j); KDCoordinate inputHeight = calculation->inputLayout()->size().height(); App * calculationApp = (App *)app(); - KDCoordinate exactOutputHeight = calculation->exactOutputLayout(calculationApp->localContext())->size().height(); - KDCoordinate approximateOutputHeight = calculation->approximateOutputLayout(calculationApp->localContext())->size().height(); - KDCoordinate outputHeight = calculation->shouldApproximateOutput() || approximateOutputHeight > exactOutputHeight ? approximateOutputHeight : exactOutputHeight; + Poincare::ExpressionLayout * approximateLayout = calculation->approximateOutputLayout(calculationApp->localContext()); + KDCoordinate approximateOutputHeight = approximateLayout->size().height(); + if (calculation->shouldApproximateOutput()) { + return inputHeight + approximateOutputHeight + 3*HistoryViewCell::k_digitVerticalMargin; + } + Poincare::ExpressionLayout * exactLayout = calculation->exactOutputLayout(calculationApp->localContext()); + KDCoordinate exactOutputHeight = exactLayout->size().height(); + KDCoordinate outputHeight = max(exactLayout->baseline(), approximateLayout->baseline()) + max(exactOutputHeight-exactLayout->baseline(), approximateOutputHeight-approximateLayout->baseline()); return inputHeight + outputHeight + 3*HistoryViewCell::k_digitVerticalMargin; } diff --git a/apps/calculation/output_expressions_view.cpp b/apps/calculation/output_expressions_view.cpp index e24bc7bf3..43caefc23 100644 --- a/apps/calculation/output_expressions_view.cpp +++ b/apps/calculation/output_expressions_view.cpp @@ -9,7 +9,7 @@ namespace Calculation { OutputExpressionsView::OutputExpressionsView(Responder * parentResponder) : Responder(parentResponder), m_approximateExpressionView(), - m_approximateSign(KDText::FontSize::Large, I18n::Message::AlmostEqual, 0.5f, 0.5f, Palette::GreyDark), + m_approximateSign(KDText::FontSize::Large, I18n::Message::AlmostEqual, 0.5f, 0.5f, Palette::GreyVeryDark), m_exactExpressionView(), m_selectedSubviewType(OutputExpressionsView::SubviewType::ExactOutput) { @@ -46,7 +46,7 @@ void OutputExpressionsView::reloadCell() { if (numberOfSubviews() == 1) { m_approximateExpressionView.setTextColor(KDColorBlack); } else { - m_approximateExpressionView.setTextColor(Palette::GreyDark); + m_approximateExpressionView.setTextColor(Palette::GreyVeryDark); } layoutSubviews(); } @@ -57,8 +57,11 @@ KDSize OutputExpressionsView::minimalSizeForOptimalDisplay() const { return approximateExpressionSize; } KDSize exactExpressionSize = m_exactExpressionView.minimalSizeForOptimalDisplay(); + KDCoordinate exactBaseline = m_exactExpressionView.expressionLayout()->baseline(); + KDCoordinate approximateBaseline = m_approximateExpressionView.expressionLayout()->baseline(); + KDCoordinate height = max(exactBaseline, approximateBaseline) + max(exactExpressionSize.height()-exactBaseline, approximateExpressionSize.height()-approximateBaseline); KDSize approximateSignSize = m_approximateSign.minimalSizeForOptimalDisplay(); - return KDSize(exactExpressionSize.width()+approximateSignSize.width()+approximateExpressionSize.width()+2*k_digitHorizontalMargin, exactExpressionSize.height() > approximateExpressionSize.height() ? exactExpressionSize.height() : approximateExpressionSize.height()); + return KDSize(exactExpressionSize.width()+approximateSignSize.width()+approximateExpressionSize.width()+2*k_digitHorizontalMargin, height); } void OutputExpressionsView::didBecomeFirstResponder() { @@ -115,11 +118,14 @@ void OutputExpressionsView::layoutSubviews() { m_approximateExpressionView.setFrame(KDRect(0, 0, approximateExpressionSize.width(), height)); return; } + KDCoordinate exactBaseline = m_exactExpressionView.expressionLayout()->baseline(); + KDCoordinate approximateBaseline = m_approximateExpressionView.expressionLayout()->baseline(); + KDCoordinate baseline = max(exactBaseline, approximateBaseline); KDSize exactExpressionSize = m_exactExpressionView.minimalSizeForOptimalDisplay(); - m_exactExpressionView.setFrame(KDRect(0, 0, exactExpressionSize.width(), height)); KDSize approximateSignSize = m_approximateSign.minimalSizeForOptimalDisplay(); - m_approximateSign.setFrame(KDRect(k_digitHorizontalMargin+exactExpressionSize.width(), 0, approximateSignSize.width(), height)); - m_approximateExpressionView.setFrame(KDRect(2*k_digitHorizontalMargin+exactExpressionSize.width()+approximateSignSize.width(), 0, approximateExpressionSize.width(), height)); + m_exactExpressionView.setFrame(KDRect(0, baseline-exactBaseline, exactExpressionSize)); + m_approximateExpressionView.setFrame(KDRect(2*k_digitHorizontalMargin+exactExpressionSize.width()+approximateSignSize.width(), baseline-approximateBaseline, approximateExpressionSize)); + m_approximateSign.setFrame(KDRect(k_digitHorizontalMargin+exactExpressionSize.width(), baseline-approximateSignSize.height()/2, approximateSignSize)); } } diff --git a/apps/graph/cartesian_function.cpp b/apps/graph/cartesian_function.cpp index 1f7077865..99a34cc6a 100644 --- a/apps/graph/cartesian_function.cpp +++ b/apps/graph/cartesian_function.cpp @@ -18,9 +18,12 @@ void CartesianFunction::setDisplayDerivative(bool display) { double CartesianFunction::approximateDerivative(double x, Poincare::Context * context) const { Poincare::Complex abscissa = Poincare::Complex::Float(x); - Poincare::Expression * args[2] = {expression(), &abscissa}; + Poincare::Expression * args[2] = {expression(context), &abscissa}; Poincare::Derivative derivative(args, true); - return derivative.approximate(*context); + /* TODO: when we will simplify derivative, we might want to simplify the + * derivative here. However, we might want to do it once for all x (to avoid + * lagging in the derivative table. */ + return derivative.approximateToScalar(*context); } char CartesianFunction::symbol() const { diff --git a/apps/probability/calculation_controller.cpp b/apps/probability/calculation_controller.cpp index c0fbbcc8f..be820cc8e 100644 --- a/apps/probability/calculation_controller.cpp +++ b/apps/probability/calculation_controller.cpp @@ -218,7 +218,7 @@ bool CalculationController::textFieldShouldFinishEditing(TextField * textField, bool CalculationController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { App * probaApp = (App *)app(); Context * globalContext = probaApp->container()->globalContext(); - double floatBody = Expression::approximate(text, *globalContext); + double floatBody = Expression::approximateToScalar(text, *globalContext); if (std::isnan(floatBody) || std::isinf(floatBody)) { app()->displayWarning(I18n::Message::UndefinedValue); return false; diff --git a/apps/probability/law/binomial_law.cpp b/apps/probability/law/binomial_law.cpp index b1adcdee3..5f973b4b4 100644 --- a/apps/probability/law/binomial_law.cpp +++ b/apps/probability/law/binomial_law.cpp @@ -102,7 +102,7 @@ double BinomialLaw::rightIntegralInverseForProbability(double * probability) { } template -T BinomialLaw::templatedEvaluateAtAbscissa(T x) const { +T BinomialLaw::templatedApproximateAtAbscissa(T x) const { if (m_parameter1 == 0) { if (m_parameter2 == 0 || m_parameter2 == 1) { return NAN; @@ -134,5 +134,5 @@ T BinomialLaw::templatedEvaluateAtAbscissa(T x) const { } -template float Probability::BinomialLaw::templatedEvaluateAtAbscissa(float x) const; -template double Probability::BinomialLaw::templatedEvaluateAtAbscissa(double x) const; +template float Probability::BinomialLaw::templatedApproximateAtAbscissa(float x) const; +template double Probability::BinomialLaw::templatedApproximateAtAbscissa(double x) const; diff --git a/apps/probability/law/binomial_law.h b/apps/probability/law/binomial_law.h index 2e81fa6cd..54efc013a 100644 --- a/apps/probability/law/binomial_law.h +++ b/apps/probability/law/binomial_law.h @@ -18,16 +18,16 @@ public: I18n::Message parameterNameAtIndex(int index) override; I18n::Message parameterDefinitionAtIndex(int index) override; float evaluateAtAbscissa(float x) const override { - return templatedEvaluateAtAbscissa(x); + return templatedApproximateAtAbscissa(x); } bool authorizedValueAtIndex(float x, int index) const override; double cumulativeDistributiveInverseForProbability(double * probability) override; double rightIntegralInverseForProbability(double * probability) override; protected: double evaluateAtDiscreteAbscissa(int k) const override { - return templatedEvaluateAtAbscissa((double)k); + return templatedApproximateAtAbscissa((double)k); } - template T templatedEvaluateAtAbscissa(T x) const; + template T templatedApproximateAtAbscissa(T x) const; }; } diff --git a/apps/probability/law/poisson_law.cpp b/apps/probability/law/poisson_law.cpp index fe1369d32..4cafce3e4 100644 --- a/apps/probability/law/poisson_law.cpp +++ b/apps/probability/law/poisson_law.cpp @@ -63,7 +63,7 @@ bool PoissonLaw::authorizedValueAtIndex(float x, int index) const { } template -T PoissonLaw::templatedEvaluateAtAbscissa(T x) const { +T PoissonLaw::templatedApproximateAtAbscissa(T x) const { if (x < 0) { return NAN; } @@ -73,5 +73,5 @@ T PoissonLaw::templatedEvaluateAtAbscissa(T x) const { } -template float Probability::PoissonLaw::templatedEvaluateAtAbscissa(float x) const; -template double Probability::PoissonLaw::templatedEvaluateAtAbscissa(double x) const; +template float Probability::PoissonLaw::templatedApproximateAtAbscissa(float x) const; +template double Probability::PoissonLaw::templatedApproximateAtAbscissa(double x) const; diff --git a/apps/probability/law/poisson_law.h b/apps/probability/law/poisson_law.h index d78399e51..3ae372a1b 100644 --- a/apps/probability/law/poisson_law.h +++ b/apps/probability/law/poisson_law.h @@ -18,14 +18,14 @@ public: I18n::Message parameterNameAtIndex(int index) override; I18n::Message parameterDefinitionAtIndex(int index) override; float evaluateAtAbscissa(float x) const override { - return templatedEvaluateAtAbscissa(x); + return templatedApproximateAtAbscissa(x); } bool authorizedValueAtIndex(float x, int index) const override; private: double evaluateAtDiscreteAbscissa(int k) const override { - return templatedEvaluateAtAbscissa((double)k); + return templatedApproximateAtAbscissa((double)k); } - template T templatedEvaluateAtAbscissa(T x) const; + template T templatedApproximateAtAbscissa(T x) const; }; } diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index 2e8b1aca0..ec79b0ecd 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -133,30 +133,44 @@ void Sequence::setType(Type type) { resetBuffer(); } -Poincare::Expression * Sequence::firstInitialConditionExpression() const { +Poincare::Expression * Sequence::firstInitialConditionExpression(Context * context) const { if (m_firstInitialConditionExpression == nullptr) { m_firstInitialConditionExpression = Poincare::Expression::parse(m_firstInitialConditionText); + if (m_firstInitialConditionExpression) { + Expression::Simplify(&m_firstInitialConditionExpression, *context); + } } return m_firstInitialConditionExpression; } -Poincare::Expression * Sequence::secondInitialConditionExpression() const { +Poincare::Expression * Sequence::secondInitialConditionExpression(Context * context) const { if (m_secondInitialConditionExpression == nullptr) { m_secondInitialConditionExpression = Poincare::Expression::parse(m_secondInitialConditionText); + if (m_secondInitialConditionExpression) { + Expression::Simplify(&m_secondInitialConditionExpression, *context); + } } return m_secondInitialConditionExpression; } Poincare::ExpressionLayout * Sequence::firstInitialConditionLayout() { - if (m_firstInitialConditionLayout == nullptr && firstInitialConditionExpression() != nullptr) { - m_firstInitialConditionLayout = firstInitialConditionExpression()->createLayout(Expression::FloatDisplayMode::Decimal); + if (m_firstInitialConditionLayout == nullptr) { + Expression * nonSimplifedExpression = Expression::parse(m_firstInitialConditionText); + if (nonSimplifedExpression) { + m_firstInitialConditionLayout = nonSimplifedExpression->createLayout(Expression::FloatDisplayMode::Decimal); + delete nonSimplifedExpression; + } } return m_firstInitialConditionLayout; } Poincare::ExpressionLayout * Sequence::secondInitialConditionLayout() { - if (m_secondInitialConditionLayout == nullptr && secondInitialConditionExpression()) { - m_secondInitialConditionLayout = secondInitialConditionExpression()->createLayout(Expression::FloatDisplayMode::Decimal); + if (m_secondInitialConditionLayout == nullptr) { + Expression * nonSimplifedExpression = Expression::parse(m_secondInitialConditionText); + if (nonSimplifedExpression) { + m_secondInitialConditionLayout = nonSimplifedExpression->createLayout(Expression::FloatDisplayMode::Decimal); + delete nonSimplifedExpression; + } } return m_secondInitialConditionLayout; } @@ -267,7 +281,7 @@ bool Sequence::isEmpty() { } template -T Sequence::templatedEvaluateAtAbscissa(T x, Poincare::Context * context) const { +T Sequence::templatedApproximateAtAbscissa(T x, Poincare::Context * context) const { T n = std::round(x); switch (m_type) { case Type::Explicite: @@ -282,18 +296,18 @@ T Sequence::templatedEvaluateAtAbscissa(T x, Poincare::Context * context) const } if (n == 0) { setBufferIndexValue(0,0); - setBufferValue(firstInitialConditionExpression()->approximate(*context), 0); + setBufferValue(firstInitialConditionExpression(context)->approximateToScalar(*context), 0); return bufferValue(0); } LocalContext subContext = LocalContext(context); Poincare::Symbol nSymbol(symbol()); int start = indexBuffer(0) < 0 || indexBuffer(0) > n ? 0 : indexBuffer(0); - T un = indexBuffer(0) < 0 || indexBuffer(0) > n ? firstInitialConditionExpression()->approximate(*context) : bufferValue(0); + T un = indexBuffer(0) < 0 || indexBuffer(0) > n ? firstInitialConditionExpression(context)->approximateToScalar(*context) : bufferValue(0); for (int i = start; i < n; i++) { subContext.setValueForSequenceRank(un, name(), 0); Poincare::Complex e = Poincare::Complex::Float(i); subContext.setExpressionForSymbolName(&e, &nSymbol, subContext); - un = expression()->approximate(subContext); + un = expression(&subContext)-> template approximateToScalar(subContext); } setBufferValue(un, 0); setBufferIndexValue(n, 0); @@ -305,27 +319,27 @@ T Sequence::templatedEvaluateAtAbscissa(T x, Poincare::Context * context) const return NAN; } if (n == 0) { - return firstInitialConditionExpression()->approximate(*context); + return firstInitialConditionExpression(context)->approximateToScalar(*context); } if (n == 1) { setBufferIndexValue(0, 0); - setBufferValue(firstInitialConditionExpression()->approximate(*context), 0); + setBufferValue(firstInitialConditionExpression(context)->approximateToScalar(*context), 0); setBufferIndexValue(1, 1); - setBufferValue(secondInitialConditionExpression()->approximate(*context), 1); + setBufferValue(secondInitialConditionExpression(context)->approximateToScalar(*context), 1); return bufferValue(1); } LocalContext subContext = LocalContext(context); Poincare::Symbol nSymbol(symbol()); int start = indexBuffer(0) >= 0 && indexBuffer(0) < n && indexBuffer(1) > 0 && indexBuffer(1) <= n && indexBuffer(0) + 1 == indexBuffer(1) ? indexBuffer(0) : 0; - T un = indexBuffer(0) >= 0 && indexBuffer(0) < n && indexBuffer(1) > 0 && indexBuffer(1) <= n && indexBuffer(0) + 1 == indexBuffer(1) ? bufferValue(0) : firstInitialConditionExpression()->approximate(*context); - T un1 = indexBuffer(0) >= 0 && indexBuffer(0) < n && indexBuffer(1) > 0 && indexBuffer(1) <= n && indexBuffer(0) + 1 == indexBuffer(1) ? bufferValue(1) : secondInitialConditionExpression()->approximate(*context); + T un = indexBuffer(0) >= 0 && indexBuffer(0) < n && indexBuffer(1) > 0 && indexBuffer(1) <= n && indexBuffer(0) + 1 == indexBuffer(1) ? bufferValue(0) : firstInitialConditionExpression(context)->approximateToScalar(*context); + T un1 = indexBuffer(0) >= 0 && indexBuffer(0) < n && indexBuffer(1) > 0 && indexBuffer(1) <= n && indexBuffer(0) + 1 == indexBuffer(1) ? bufferValue(1) : secondInitialConditionExpression(context)->approximateToScalar(*context); for (int i = start; i < n-1; i++) { subContext.setValueForSequenceRank(un, name(), 0); subContext.setValueForSequenceRank(un1, name(), 1); Poincare::Complex e = Poincare::Complex::Float(i); subContext.setExpressionForSymbolName(&e, &nSymbol, subContext); un = un1; - un1 = expression()->approximate(subContext); + un1 = expression(&subContext)->template approximateToScalar(subContext); } setBufferValue(un, 0); setBufferIndexValue(n-1, 0); diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index c14687fbf..8cdebacbb 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -24,8 +24,8 @@ public: void setType(Type type); const char * firstInitialConditionText(); const char * secondInitialConditionText(); - Poincare::Expression * firstInitialConditionExpression() const; - Poincare::Expression * secondInitialConditionExpression() const; + Poincare::Expression * firstInitialConditionExpression(Poincare::Context * context) const; + Poincare::Expression * secondInitialConditionExpression(Poincare::Context * context) const; Poincare::ExpressionLayout * firstInitialConditionLayout(); Poincare::ExpressionLayout * secondInitialConditionLayout(); void setContent(const char * c) override; @@ -39,10 +39,10 @@ public: bool isDefined() override; bool isEmpty() override; float evaluateAtAbscissa(float x, Poincare::Context * context) const override { - return templatedEvaluateAtAbscissa(x, context); + return templatedApproximateAtAbscissa(x, context); } double evaluateAtAbscissa(double x, Poincare::Context * context) const override { - return templatedEvaluateAtAbscissa(x, context); + return templatedApproximateAtAbscissa(x, context); } double sumOfTermsBetweenAbscissa(double start, double end, Poincare::Context * context); void tidy() override; @@ -52,7 +52,7 @@ private: constexpr static size_t k_dataLengthInBytes = (3*TextField::maxBufferSize()+3)*sizeof(char)+1; static_assert((k_dataLengthInBytes & 0x3) == 0, "The sequence data size is not a multiple of 4 bytes (cannot compute crc)"); // Assert that dataLengthInBytes is a multiple of 4 char symbol() const override; - template T templatedEvaluateAtAbscissa(T x, Poincare::Context * context) const; + template T templatedApproximateAtAbscissa(T x, Poincare::Context * context) const; Type m_type; char m_firstInitialConditionText[TextField::maxBufferSize()]; char m_secondInitialConditionText[TextField::maxBufferSize()]; diff --git a/apps/settings/app.cpp b/apps/settings/app.cpp index 137768557..b9013a437 100644 --- a/apps/settings/app.cpp +++ b/apps/settings/app.cpp @@ -26,7 +26,7 @@ App::Descriptor * App::Snapshot::descriptor() { } App::App(Container * container, Snapshot * snapshot) : - ::App(container, snapshot, &m_stackViewController, I18n::Message::Warning), + Shared::TextFieldDelegateApp(container, snapshot, &m_stackViewController), m_mainController(&m_stackViewController), m_stackViewController(&m_modalViewController, &m_mainController) { diff --git a/apps/settings/app.h b/apps/settings/app.h index ea9170848..a84c79b16 100644 --- a/apps/settings/app.h +++ b/apps/settings/app.h @@ -1,12 +1,12 @@ #ifndef SETTINGS_APP_H #define SETTINGS_APP_H -#include #include "main_controller.h" +#include "../shared/text_field_delegate_app.h" namespace Settings { -class App : public ::App { +class App : public Shared::TextFieldDelegateApp { public: class Descriptor : public ::App::Descriptor { public: diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 5c8afecaf..58505a7c2 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -17,6 +17,7 @@ Degres = "Grad " Radian = "Bogenmass " Auto = "Auto " Scientific = "Wissenschaftlich " +SignificantFigures = "Signifikante Stellen " Deg = "gra" Rad = "rad" Sci = "sci/" diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n index 3880a44cb..975e2893e 100644 --- a/apps/settings/base.en.i18n +++ b/apps/settings/base.en.i18n @@ -17,6 +17,7 @@ Degres = "Degrees " Radian = "Radians " Auto = "Auto " Scientific = "Scientific " +SignificantFigures = "Significant figures " Deg = "deg" Rad = "rad" Sci = "sci/" diff --git a/apps/settings/base.es.i18n b/apps/settings/base.es.i18n index a50f4e084..d759afc75 100644 --- a/apps/settings/base.es.i18n +++ b/apps/settings/base.es.i18n @@ -17,6 +17,7 @@ Degres = "Grados " Radian = "Radianes " Auto = "Auto " Scientific = "Cientifico " +SignificantFigures = "Cifras significativas " Deg = "gra" Rad = "rad" Sci = "sci/" diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n index 9cfbbda93..5a12de95a 100644 --- a/apps/settings/base.fr.i18n +++ b/apps/settings/base.fr.i18n @@ -17,6 +17,7 @@ Degres = "Degres " Radian = "Radians " Auto = "Auto " Scientific = "Scientifique " +SignificantFigures = "Chiffres significatifs " Deg = "deg" Rad = "rad" Sci = "sci/" diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index 11f86cc8f..cf03bb47a 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -17,6 +17,7 @@ Degres = "Graus " Radian = "Radianos " Auto = "Auto " Scientific = "Cientifico " +SignificantFigures = "Algarismo significativo " Deg = "gra" Rad = "rad" Sci = "sci/" diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp index 5e4c91032..1f4aca5fd 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -11,7 +11,7 @@ using namespace Poincare; namespace Settings { const SettingsMessageTree angleChildren[2] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Radian)}; -const SettingsMessageTree FloatDisplayModeChildren[2] = {SettingsMessageTree(I18n::Message::Auto), SettingsMessageTree(I18n::Message::Scientific)}; +const SettingsMessageTree FloatDisplayModeChildren[3] = {SettingsMessageTree(I18n::Message::Auto), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::SignificantFigures)}; const SettingsMessageTree complexFormatChildren[2] = {SettingsMessageTree(I18n::Message::Default), SettingsMessageTree(I18n::Message::Default)}; const SettingsMessageTree examChildren[1] = {SettingsMessageTree(I18n::Message::ActivateExamMode)}; const SettingsMessageTree aboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)}; @@ -21,7 +21,7 @@ const SettingsMessageTree menu[8] = #else const SettingsMessageTree menu[7] = #endif - {SettingsMessageTree(I18n::Message::AngleUnit, angleChildren, 2), SettingsMessageTree(I18n::Message::DisplayMode, FloatDisplayModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, complexFormatChildren, 2), + {SettingsMessageTree(I18n::Message::AngleUnit, angleChildren, 2), SettingsMessageTree(I18n::Message::DisplayMode, FloatDisplayModeChildren, 3), SettingsMessageTree(I18n::Message::ComplexFormat, complexFormatChildren, 2), SettingsMessageTree(I18n::Message::Brightness), SettingsMessageTree(I18n::Message::Language), SettingsMessageTree(I18n::Message::ExamMode, examChildren, 1), #if OS_WITH_SOFTWARE_UPDATE_PROMPT SettingsMessageTree(I18n::Message::UpdatePopUp), diff --git a/apps/settings/sub_controller.cpp b/apps/settings/sub_controller.cpp index e89c03945..8fc44b8b3 100644 --- a/apps/settings/sub_controller.cpp +++ b/apps/settings/sub_controller.cpp @@ -4,6 +4,7 @@ #include "../../poincare/src/layout/baseline_relative_layout.h" #include "../../poincare/src/layout/string_layout.h" #include +#include using namespace Poincare; @@ -11,8 +12,9 @@ namespace Settings { SubController::SubController(Responder * parentResponder) : ViewController(parentResponder), + m_editableCell(&m_selectableTableView, this, m_draftTextBuffer), m_selectableTableView(this, this, 0, 1, k_topBottomMargin, Metric::CommonRightMargin, - k_topBottomMargin, Metric::CommonLeftMargin, this), + k_topBottomMargin, Metric::CommonLeftMargin, this, this), m_messageTreeModel(nullptr) { for (int i = 0; i < k_totalNumberOfCell; i++) { @@ -28,6 +30,8 @@ SubController::SubController(Responder * parentResponder) : for (int i = 0; i < 2; i++) { m_complexFormatCells[i].setExpression(m_complexFormatLayout[i]); } + m_editableCell.setMessage(I18n::Message::SignificantFigures); + m_editableCell.setMessageFontSize(KDText::FontSize::Large); } SubController::~SubController() { @@ -50,13 +54,8 @@ View * SubController::view() { return &m_selectableTableView; } -void SubController::didEnterResponderChain(Responder * previousResponder) { - if (previousResponder->commonAncestorWith(this) == parentResponder()) { - /* We want to select the prefered SettingMessageTree only when the previous page - * was the main setting page. We do not to change the selection when - * dismissing a pop-up for instance. */ - selectCellAtLocation(0, valueIndexForPreference(m_messageTreeModel->label())); - } +void SubController::didBecomeFirstResponder() { + selectCellAtLocation(0, valueIndexForPreference(m_messageTreeModel->label())); if (m_messageTreeModel->label() == I18n::Message::ExamMode) { m_selectableTableView.reloadData(); } @@ -94,6 +93,7 @@ bool SubController::handleEvent(Ion::Events::Event event) { return false; } /* Generic behaviour of preference menu*/ + assert(m_messageTreeModel->label() != I18n::Message::DisplayMode || selectedRow() != numberOfRows()-1); // In that case, events OK and EXE are handled by the cell setPreferenceWithValueIndex(m_messageTreeModel->label(), selectedRow()); AppsContainer * myContainer = (AppsContainer * )app()->container(); myContainer->refreshPreferences(); @@ -115,30 +115,70 @@ int SubController::numberOfRows() { return 0; } -HighlightCell * SubController::reusableCell(int index) { - assert(index >= 0); - assert(index < k_totalNumberOfCell); - if (m_messageTreeModel->label() == I18n::Message::ComplexFormat) { +HighlightCell * SubController::reusableCell(int index, int type) { + if (type == 2) { + assert(index == 0); + return &m_editableCell; + } else if (type == 1) { + assert(index >= 0 && index < 2); return &m_complexFormatCells[index]; } + assert(index >= 0 && index < k_totalNumberOfCell); return &m_cells[index]; } -int SubController::reusableCellCount() { - if (m_messageTreeModel->label() == I18n::Message::ComplexFormat) { - return 2; +int SubController::reusableCellCount(int type) { + switch (type) { + case 0: + return k_totalNumberOfCell; + case 1: + return 2; + case 2: + return 1; + default: + assert(false); + return 0; } - return k_totalNumberOfCell; } -KDCoordinate SubController::cellHeight() { +int SubController::typeAtLocation(int i, int j) { + if (m_messageTreeModel->label() == I18n::Message::ComplexFormat) { + return 1; + } + if (m_messageTreeModel->label() == I18n::Message::DisplayMode && j == numberOfRows()-1) { + return 2; + } + return 0; +} + +KDCoordinate SubController::rowHeight(int j) { return Metric::ParameterCellHeight; } +KDCoordinate SubController::cumulatedHeightFromIndex(int j) { + return rowHeight(0) * j; +} + +int SubController::indexFromCumulatedHeight(KDCoordinate offsetY) { + KDCoordinate height = rowHeight(0); + if (height == 0) { + return 0; + } + return (offsetY - 1) / height; +} + void SubController::willDisplayCellForIndex(HighlightCell * cell, int index) { if (m_messageTreeModel->label() == I18n::Message::ComplexFormat) { return; } + /* Number of significants figure row */ + if (m_messageTreeModel->label() == I18n::Message::DisplayMode && index == numberOfRows()-1) { + MessageTableCellWithEditableText * myCell = (MessageTableCellWithEditableText *)cell; + char buffer[3]; + Integer(Preferences::sharedPreferences()->numberOfSignificantDigits()).writeTextInBuffer(buffer, 3); + myCell->setAccessoryText(buffer); + return; + } MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)cell; myCell->setMessage(m_messageTreeModel->children(index)->label()); myCell->setMessageFontSize(KDText::FontSize::Large); @@ -179,6 +219,56 @@ void SubController::viewDidDisappear() { m_selectableTableView.deselectTable(); } +bool SubController::textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) { + return (event == Ion::Events::Up && selectedRow() > 0) + || TextFieldDelegate::textFieldShouldFinishEditing(textField, event); +} + +bool SubController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { + Context * globalContext = textFieldDelegateApp()->localContext(); + float floatBody = Expression::approximateToScalar(text, *globalContext); + if (std::isnan(floatBody) || std::isinf(floatBody)) { + floatBody = PrintFloat::k_numberOfPrintedSignificantDigits; + } + if (floatBody < 1) { + floatBody = 1; + } + if (floatBody > PrintFloat::k_numberOfStoredSignificantDigits) { + floatBody = PrintFloat::k_numberOfStoredSignificantDigits; + } + Preferences::sharedPreferences()->setNumberOfSignificantDigits((char)std::round(floatBody)); + m_selectableTableView.reloadCellAtLocation(0, selectedRow()); + if (event == Ion::Events::Up || event == Ion::Events::OK) { + m_selectableTableView.handleEvent(event); + } + return true; +} + +bool SubController::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) { + if (event == Ion::Events::Backspace && !textField->isEditing()) { + textField->setEditing(true); + return true; + } + return TextFieldDelegate::textFieldDidReceiveEvent(textField, event); +} + +void SubController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) { + if (m_messageTreeModel->label() != I18n::Message::DisplayMode) { + return; + } + if (previousSelectedCellX == t->selectedColumn() && previousSelectedCellY == t->selectedRow()) { + return; + } + if (previousSelectedCellY == numberOfRows()-1) { + MessageTableCellWithEditableText * myCell = (MessageTableCellWithEditableText *)t->cellAtLocation(previousSelectedCellX, previousSelectedCellY); + myCell->setEditing(false); + } + if (t->selectedRow() == numberOfRows() -1) { + MessageTableCellWithEditableText * myNewCell = (MessageTableCellWithEditableText *)t->selectedCell(); + app()->setFirstResponder(myNewCell); + } +} + StackViewController * SubController::stackController() const { return (StackViewController *)parentResponder(); } @@ -208,5 +298,8 @@ int SubController::valueIndexForPreference(I18n::Message message) { return 0; } +Shared::TextFieldDelegateApp * SubController::textFieldDelegateApp() { + return (Shared::TextFieldDelegateApp *)app(); +} } diff --git a/apps/settings/sub_controller.h b/apps/settings/sub_controller.h index 5e4c81d67..42a78c329 100644 --- a/apps/settings/sub_controller.h +++ b/apps/settings/sub_controller.h @@ -4,10 +4,11 @@ #include #include "settings_message_tree.h" #include "../hardware_test/pop_up_controller.h" +#include "../shared/text_field_delegate.h" namespace Settings { -class SubController : public ViewController, public SimpleListViewDataSource, public SelectableTableViewDataSource { +class SubController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource, public SelectableTableViewDelegate, public Shared::TextFieldDelegate { public: SubController(Responder * parentResponder); ~SubController(); @@ -18,24 +19,34 @@ public: View * view() override; const char * title() override; bool handleEvent(Ion::Events::Event event) override; - void didEnterResponderChain(Responder * previousFirstResponder) override; + void didBecomeFirstResponder() override; int numberOfRows() override; - KDCoordinate cellHeight() override; - HighlightCell * reusableCell(int index) override; - int reusableCellCount() override; + KDCoordinate rowHeight(int j) override; + KDCoordinate cumulatedHeightFromIndex(int j) override; + int indexFromCumulatedHeight(KDCoordinate offsetY) override; + HighlightCell * reusableCell(int index, int type) override; + int reusableCellCount(int type) override; + int typeAtLocation(int i, int j) override; void willDisplayCellForIndex(HighlightCell * cell, int index) override; void setMessageTreeModel(const MessageTree * messageTreeModel); void viewWillAppear() override; void viewDidDisappear() override; + bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; + bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; + bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; + void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) override; private: StackViewController * stackController() const; void setPreferenceWithValueIndex(I18n::Message message, int valueIndex); int valueIndexForPreference(I18n::Message message); + Shared::TextFieldDelegateApp * textFieldDelegateApp() override; constexpr static int k_totalNumberOfCell = I18n::NumberOfLanguages; constexpr static KDCoordinate k_topBottomMargin = 13; MessageTableCellWithBuffer m_cells[k_totalNumberOfCell]; ExpressionTableCell m_complexFormatCells[2]; Poincare::ExpressionLayout * m_complexFormatLayout[2]; + MessageTableCellWithEditableText m_editableCell; + char m_draftTextBuffer[MessageTableCellWithEditableText::k_bufferLength]; SelectableTableView m_selectableTableView; MessageTree * m_messageTreeModel; HardwareTest::PopUpController m_hardwareTestPopUpController; diff --git a/apps/shared/editable_cell_table_view_controller.cpp b/apps/shared/editable_cell_table_view_controller.cpp index ea03e457f..55bd2ddfe 100644 --- a/apps/shared/editable_cell_table_view_controller.cpp +++ b/apps/shared/editable_cell_table_view_controller.cpp @@ -24,7 +24,7 @@ bool EditableCellTableViewController::textFieldShouldFinishEditing(TextField * t bool EditableCellTableViewController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { AppsContainer * appsContainer = ((TextFieldDelegateApp *)app())->container(); Context * globalContext = appsContainer->globalContext(); - double floatBody = Expression::approximate(text, *globalContext); + double floatBody = Expression::approximateToScalar(text, *globalContext); if (std::isnan(floatBody) || std::isinf(floatBody)) { app()->displayWarning(I18n::Message::UndefinedValue); return false; diff --git a/apps/shared/float_parameter_controller.cpp b/apps/shared/float_parameter_controller.cpp index 04f925f6c..f4cc97c54 100644 --- a/apps/shared/float_parameter_controller.cpp +++ b/apps/shared/float_parameter_controller.cpp @@ -119,7 +119,7 @@ bool FloatParameterController::textFieldShouldFinishEditing(TextField * textFiel bool FloatParameterController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { AppsContainer * appsContainer = ((TextFieldDelegateApp *)app())->container(); Context * globalContext = appsContainer->globalContext(); - double floatBody = Expression::approximate(text, *globalContext); + double floatBody = Expression::approximateToScalar(text, *globalContext); if (std::isnan(floatBody) || std::isinf(floatBody)) { app()->displayWarning(I18n::Message::UndefinedValue); return false; diff --git a/apps/shared/function.cpp b/apps/shared/function.cpp index 36bca4846..dd4e46444 100644 --- a/apps/shared/function.cpp +++ b/apps/shared/function.cpp @@ -69,16 +69,23 @@ const char * Function::name() const { return m_name; } -Poincare::Expression * Function::expression() const { +Poincare::Expression * Function::expression(Poincare::Context * context) const { if (m_expression == nullptr) { m_expression = Expression::parse(m_text); + if (m_expression) { + Expression::Simplify(&m_expression, *context); + } } return m_expression; } Poincare::ExpressionLayout * Function::layout() { - if (m_layout == nullptr && expression() != nullptr) { - m_layout = expression()->createLayout(Expression::FloatDisplayMode::Decimal); + if (m_layout == nullptr) { + Expression * nonSimplifiedExpression = Expression::parse(m_text); + if (nonSimplifiedExpression != nullptr) { + m_layout = nonSimplifiedExpression->createLayout(Expression::FloatDisplayMode::Decimal); + delete nonSimplifiedExpression; + } } return m_layout; } @@ -100,12 +107,12 @@ bool Function::isEmpty() { } template -T Function::templatedEvaluateAtAbscissa(T x, Poincare::Context * context) const { +T Function::templatedApproximateAtAbscissa(T x, Poincare::Context * context) const { Poincare::VariableContext variableContext = Poincare::VariableContext(symbol(), context); Poincare::Symbol xSymbol(symbol()); Poincare::Complex e = Poincare::Complex::Float(x); variableContext.setExpressionForSymbolName(&e, &xSymbol, variableContext); - return expression()->approximate(variableContext); + return expression(context)->approximateToScalar(variableContext); } void Function::tidy() { @@ -121,5 +128,5 @@ void Function::tidy() { } -template float Shared::Function::templatedEvaluateAtAbscissa(float, Poincare::Context*) const; -template double Shared::Function::templatedEvaluateAtAbscissa(double, Poincare::Context*) const; +template float Shared::Function::templatedApproximateAtAbscissa(float, Poincare::Context*) const; +template double Shared::Function::templatedApproximateAtAbscissa(double, Poincare::Context*) const; diff --git a/apps/shared/function.h b/apps/shared/function.h index 2e6303bfe..c01525e83 100644 --- a/apps/shared/function.h +++ b/apps/shared/function.h @@ -19,7 +19,7 @@ public: const char * text() const; const char * name() const; KDColor color() const { return m_color; } - Poincare::Expression * expression() const; + Poincare::Expression * expression(Poincare::Context * context) const; Poincare::ExpressionLayout * layout(); virtual bool isDefined(); bool isActive(); @@ -28,16 +28,16 @@ public: virtual void setContent(const char * c); void setColor(KDColor m_color); virtual float evaluateAtAbscissa(float x, Poincare::Context * context) const { - return templatedEvaluateAtAbscissa(x, context); + return templatedApproximateAtAbscissa(x, context); } virtual double evaluateAtAbscissa(double x, Poincare::Context * context) const { - return templatedEvaluateAtAbscissa(x, context); + return templatedApproximateAtAbscissa(x, context); } virtual void tidy(); private: constexpr static size_t k_dataLengthInBytes = (TextField::maxBufferSize()+2)*sizeof(char)+2; static_assert((k_dataLengthInBytes & 0x3) == 0, "The function data size is not a multiple of 4 bytes (cannot compute crc)"); // Assert that dataLengthInBytes is a multiple of 4 - template T templatedEvaluateAtAbscissa(T x, Poincare::Context * context) const; + template T templatedApproximateAtAbscissa(T x, Poincare::Context * context) const; virtual char symbol() const = 0; mutable Poincare::Expression * m_expression; char m_text[TextField::maxBufferSize()]; diff --git a/apps/shared/text_field_delegate_app.h b/apps/shared/text_field_delegate_app.h index 63e532cd5..c5039a1ef 100644 --- a/apps/shared/text_field_delegate_app.h +++ b/apps/shared/text_field_delegate_app.h @@ -16,7 +16,7 @@ public: AppsContainer * container(); virtual const char * XNT(); bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; - bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; + virtual bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; Toolbox * toolboxForTextField(TextField * textField) override; protected: TextFieldDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController); diff --git a/escher/include/escher/palette.h b/escher/include/escher/palette.h index 5b6230678..ad47ce19d 100644 --- a/escher/include/escher/palette.h +++ b/escher/include/escher/palette.h @@ -13,6 +13,7 @@ public: constexpr static KDColor GreyBright = KDColor::RGB24(0xececec); constexpr static KDColor GreyMiddle = KDColor::RGB24(0xd9d9d9); constexpr static KDColor GreyDark = KDColor::RGB24(0xa7a7a7); + constexpr static KDColor GreyVeryDark = KDColor::RGB24(0x8c8c8c); constexpr static KDColor Select = KDColor::RGB24(0xd4d7e0); constexpr static KDColor SelectDark = KDColor::RGB24(0xb0b8d8); constexpr static KDColor WallScreen = KDColor::RGB24(0xf7f9fa); diff --git a/escher/src/palette.cpp b/escher/src/palette.cpp index 0602d3ca7..59da5fbb7 100644 --- a/escher/src/palette.cpp +++ b/escher/src/palette.cpp @@ -8,6 +8,7 @@ constexpr KDColor Palette::GreyWhite; constexpr KDColor Palette::GreyBright; constexpr KDColor Palette::GreyMiddle; constexpr KDColor Palette::GreyDark; +constexpr KDColor Palette::GreyVeryDark; constexpr KDColor Palette::Select; constexpr KDColor Palette::SelectDark; constexpr KDColor Palette::WallScreen; diff --git a/ion/include/ion/keyboard.h b/ion/include/ion/keyboard.h index 47339cb06..9e09314e9 100644 --- a/ion/include/ion/keyboard.h +++ b/ion/include/ion/keyboard.h @@ -3,6 +3,7 @@ extern "C" { #include +#include } namespace Ion { @@ -37,10 +38,14 @@ public: constexpr State(uint64_t s = 0) : m_bitField(s) {} + /* "Shift behavior is undefined if the right operand is negative, or greater + * than or equal to the length in bits of the promoted left operand" according + * to C++ spec but k is always in [0:52]. */ explicit constexpr State(Key k) : m_bitField((uint64_t)1 << (uint8_t)k) {} inline bool keyDown(Key k) const { + assert((uint8_t)k < 64); return (m_bitField>>(uint8_t)k) & 1; } operator uint64_t() const { return m_bitField; } diff --git a/ion/src/device/regs/register.h b/ion/src/device/regs/register.h index da4acb44d..15637284e 100644 --- a/ion/src/device/regs/register.h +++ b/ion/src/device/regs/register.h @@ -2,6 +2,7 @@ #define REGS_REGISTER_H #include +#include template class Register { @@ -21,13 +22,19 @@ public: m_value = bit_range_set_value(high, low, m_value, value); } T getBitRange(uint8_t high, uint8_t low) volatile { + /* "Shift behavior is undefined if the right operand is negative, or greater + * than or equal to the length in bits of the promoted left operand" according + * to C++ spec. */ + assert(low < 8*sizeof(T)); return (m_value & bit_range_mask(high,low)) >> low; } protected: static constexpr T bit_range_mask(uint8_t high, uint8_t low) { + // Same comment as for getBitRange: we should assert (high-low+1) < 8*sizeof(T) return ((((T)1)<<(high-low+1))-1)< typedef unsigned int uint32_t; long long __aeabi_llsl(long long value, int shift) { uint32_t low = (uint32_t)value << shift; + /* "Shift behavior is undefined if the right operand is negative, or greater + * than or equal to the length in bits of the promoted left operand" according + * to C++ spec. However, arm compiler fill the vacated bits with 0 */ + assert(shift < 32 || low == 0); uint32_t high = ((uint32_t)(value >> 32) << shift); + // Same comment + assert(shift < 32 || high == 0); if (shift < 32) { high |= ((uint32_t)value >> (32 - shift)); } else { diff --git a/liba/src/aeabi-rt/llsr.c b/liba/src/aeabi-rt/llsr.c index 38c200cce..0dd3e2cee 100644 --- a/liba/src/aeabi-rt/llsr.c +++ b/liba/src/aeabi-rt/llsr.c @@ -1,14 +1,21 @@ /* See the "Run-time ABI for the ARM Architecture", Section 4.2 */ +#include typedef unsigned int uint32_t; long long __aeabi_llsr(long long value, int shift) { uint32_t low = ((uint32_t)value >> shift); + /* "Shift behavior is undefined if the right operand is negative, or greater + * than or equal to the length in bits of the promoted left operand" according + * to C++ spec. However, arm compiler fill the vacated bits with 0 */ + assert(shift < 32 || low == 0); if (shift < 32) { low |= ((uint32_t)(value >> 32) << (32 - shift)); } else { low |= ((uint32_t)(value >> 32) >> (shift - 32)); } uint32_t high = (uint32_t)(value >> 32) >> shift; + // Same comment + assert(shift < 32 || high == 0); return ((long long)high << 32) | low; } diff --git a/poincare/Makefile b/poincare/Makefile index c62d58696..ccb5d3ad2 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -25,7 +25,7 @@ objs += $(addprefix poincare/src/,\ division_quotient.o\ division_remainder.o\ dynamic_hierarchy.o\ - evaluation_engine.o\ + approximation_engine.o\ expression.o\ expression_lexer.o\ expression_parser.o\ @@ -34,7 +34,6 @@ objs += $(addprefix poincare/src/,\ frac_part.o\ global_context.o\ great_common_divisor.o\ - hierarchy.o\ hyperbolic_arc_cosine.o\ hyperbolic_arc_sine.o\ hyperbolic_arc_tangent.o\ @@ -101,33 +100,31 @@ objs += $(addprefix poincare/src/layout/,\ ) tests += $(addprefix poincare/test/,\ - arithmetic.cpp\ - convert_expression_to_text.cpp\ - helper.cpp\ - integer.cpp\ - simplify_easy.cpp\ -) - -testsi += $(addprefix poincare/test/,\ addition.cpp\ arithmetic.cpp\ complex.cpp\ + convert_expression_to_text.cpp\ division.cpp\ + factorial.cpp\ function.cpp\ helper.cpp\ integer.cpp\ + logarithm.cpp\ matrix.cpp\ + multiplication.cpp\ parser.cpp\ - product.cpp\ power.cpp\ + rational.cpp\ + simplify_mix.cpp\ subtraction.cpp\ - simplify_utils.cpp\ symbol.cpp\ trigo.cpp\ ) +# simplify_utils.cpp\ ifdef POINCARE_TESTS_PRINT_EXPRESSIONS tests += poincare/src/expression_debug.o +objs += poincare/src/expression_debug.o SFLAGS += -DPOINCARE_TESTS_PRINT_EXPRESSIONS=1 endif diff --git a/poincare/README.txt b/poincare/README.txt index bb9e908a3..a7aedc554 100644 --- a/poincare/README.txt +++ b/poincare/README.txt @@ -1,20 +1,95 @@ -Things we will want to simplify: +# Poincare - 2.y.3 -> 6.y - y.x.3 + x^2 +1 -> x^2 + 3*x*y + 1 -Zeroes and ones - x + 0 -> x - 1*x -> x - x^1 -> x - x^0 -> 1 -Simplify fractions - (x^2+5.x+6)/(x+2) -> x+3 -Polynomials - (x+1)^2-x^2 -> 2*x+1 -Divisions - (2*x)/(x^2-1) - 1/(x-1) -> 1/(x+1) -Functional identities - ln(2x) - ln(x) -> ln(2) - y*sin^2(x) + y*cos^2(x) -> y +Expressions have a structure of tree, storing: +- Pointers to the operand expressions (ie children) +- A pointer to the parent expression +Expressions are typed (ie Type::Addition, Type::Multiplication...) and some expressions also hold values (ie Type::Rational). +Multiplication and Addition are the only type that can hold an infinite number of operands. Other expressions have a fixed number of operands (ie AbsoluteValue). -Note : The simplification process can be interrupted! -> It probably browses a graph +## Simplification + +Expression simplification is done in-place and modify directly the expression. +Simplify is a two-phase method: +- It first reduces the expression +- Then, it beautify the expression +So far, we excluded matrices from the simplificaiton process to avoid increasing complexity due to non commutativity in multiplications. + +### Order + +We define an simplification order on expressions with the following features: +- The order is total on types and values: + Rational(-2/3) < Rational(0) < ... < Multiplication < Power < Addition < ... +- The order relationship is depth-first recursive: if two expressions are equal in type (and values), we compare their operands starting with the last. +To compare two expressions, we first sort their commutative children to ensure the unicity of expression representations. This guarantee that the order is total on expressions. + +Moreover, the simplification order have some other specificities for some types: +- for addition and multiplication, any rational operand is always the first operands after sorting (by commutativity). +- Comparing an addition expression with an expression of different type called e is equivalent to comparing the addition with an addition with a single operand e. +- Idem for multiplications. +- To compare a power expression with an expression of different type called e, we compare the power with e^1. +The order groups like terms together to avoid quadratic complexity when factorizing addition or multiplication. For example, it groups terms with same bases together (ie Pi, Pi^3) and with same non-rational factors together (ie Pi, 2*Pi). + +Last comment; as the order is total, we can easily check if two expressions are identical by using this order. + + +### Reduce + +The reducing phase is the most important part of simplification. +It happens recursively and bottom-up: we first reduce the operands of an expression before reducing the expression itself. That way, when reducing itself, an expression can assert that its operands are reduced (and thus have some properties explained in the following). +Every type of expression has its own rules of reducing. + +To decrease the pool of possible expression types in reduced expressions, we converte subtraction to addition, division to power etc ... at reduction: +a-b -> a+(-1)*b +a/b -> a*b^(-1) +-a -> (-1)*a +sqrt(x) -> x^(1/2) +root(x,y) -> x^(1/y) +ln(x) -> log(x,e) + +Here is a short tour of shallow reduction for the main types: + +1. Additions are reduced by applying mathematics rules, ie: +- Associativity: (a+b)+c -> a+b+c +- Commutativity: a+b -> b+c which enables to sort operands and group like-terms together +- Factorization: a+5a -> 6a +- a+0->a +- We also reduce addition to same denominator. + +2. Multiplications apply the following rules: +- Associativity +- Commutativity (which is true because we do no reduce matrices yet) +- a*0 -> 0 +- Factorization +- sin/cos -> tan +- Distribution: a*(b+c) -> ab+ac + +3. Powers apply the following rules: +- We get rid of square roots at denominator and of sum of 2 square roots at denominator +- x^0-> 1 if x != 0 +- x^1 -> x +- 0^x -> 0 if x>0, undefined otherwise +- 1^x +- (a^b)^c -> a^(b+c) if a > 0 or c is integer +- (a*b*c*...)^n = a^n*b^n*c^n*... if n integer +- (a*b*...)^r -> |a|^r*(sign(a)*b*...)^r if a rational +- a^(b+c) -> (a^b)*a^c with a and b rational +- r^s with r, s rationals can be simplified using the factorisation in primes of r (ie, 8^(1/2) -> 2*2^(1/2)) +- i^(p/q)-> exp^(i*Pi*p/(2q)) with p, q integers +- exp^(i*Pi*p/q) -> cos(Pi*p/q)+i*sin(Pi*p/q) with p, q integers +- x^log(y,x)->y if y > 0 +- 10^log(y) + +To avoid infinite loop, reduction is contextualized on the parent expression (ie, reducing addition to same denominator). This forces to reduce an expression only once it is included in a expression. + +### Beautify + +This phase turns expressions in a more readable way. Division, subtraction, Naperian logarithm reappear at this step. Parenthesis are also added to be able to print the tree in infix notation without any ambiguity. +This phase is also recursive and top-down: we first beautify the node expression and the beautify its operands. + +## Approximation + +Expressions can be approximate which return another (dynamically allocated) expression that can be either: +- a complex +- a matrix of complex + +To approximate an expression, we first approximate its operands (which are ensured to be either complex or matrix of complex) and then approximate the expression using the operand approximations depending on its type. diff --git a/poincare/include/poincare/absolute_value.h b/poincare/include/poincare/absolute_value.h index e4a6030d5..870facc18 100644 --- a/poincare/include/poincare/absolute_value.h +++ b/poincare/include/poincare/absolute_value.h @@ -2,7 +2,7 @@ #define POINCARE_ABSOLUTE_VALUE_H #include -#include +#include #include namespace Poincare { @@ -24,11 +24,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/addition.h b/poincare/include/poincare/addition.h index 9f2a6a9d5..7652bf7f5 100644 --- a/poincare/include/poincare/addition.h +++ b/poincare/include/poincare/addition.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include namespace Poincare { @@ -19,10 +19,10 @@ public: /* Evaluation */ template static Complex compute(const Complex c, const Complex d); template static Matrix * computeOnMatrices(const Matrix * m, const Matrix * n) { - return EvaluationEngine::elementWiseOnComplexMatrices(m, n, compute); + return ApproximationEngine::elementWiseOnComplexMatrices(m, n, compute); } template static Matrix * computeOnComplexAndMatrix(const Complex * c, const Matrix * m) { - return EvaluationEngine::elementWiseOnComplexAndComplexMatrix(c, m, compute); + return ApproximationEngine::elementWiseOnComplexAndComplexMatrix(c, m, compute); } private: /* Layout */ @@ -43,13 +43,13 @@ private: static bool TermsHaveIdenticalNonRationalFactors(const Expression * e1, const Expression * e2); /* Evaluation */ template static Matrix * computeOnMatrixAndComplex(const Matrix * m, const Complex * c) { - return EvaluationEngine::elementWiseOnComplexAndComplexMatrix(c, m, compute); + return ApproximationEngine::elementWiseOnComplexAndComplexMatrix(c, m, compute); } - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } }; diff --git a/poincare/include/poincare/evaluation_engine.h b/poincare/include/poincare/approximation_engine.h similarity index 93% rename from poincare/include/poincare/evaluation_engine.h rename to poincare/include/poincare/approximation_engine.h index 9d256c101..673aa5226 100644 --- a/poincare/include/poincare/evaluation_engine.h +++ b/poincare/include/poincare/approximation_engine.h @@ -1,5 +1,5 @@ -#ifndef POINCARE_EVALUATION_ENGINE_H -#define POINCARE_EVALUATION_ENGINE_H +#ifndef POINCARE_APPROXIMATION_ENGINE_H +#define POINCARE_APPROXIMATION_ENGINE_H #include #include @@ -7,7 +7,7 @@ namespace Poincare { -class EvaluationEngine { +class ApproximationEngine { public: template using ComplexCompute = Complex(*)(const Complex, Expression::AngleUnit angleUnit); template static Expression * map(const Expression * expression, Context& context, Expression::AngleUnit angleUnit, ComplexCompute compute); diff --git a/poincare/include/poincare/arc_cosine.h b/poincare/include/poincare/arc_cosine.h index 81e29eb21..7b27c7e8a 100644 --- a/poincare/include/poincare/arc_cosine.h +++ b/poincare/include/poincare/arc_cosine.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -27,11 +27,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/arc_sine.h b/poincare/include/poincare/arc_sine.h index dcceec881..d2d0737ca 100644 --- a/poincare/include/poincare/arc_sine.h +++ b/poincare/include/poincare/arc_sine.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: Expression * shallowReduce(Context & context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/arc_tangent.h b/poincare/include/poincare/arc_tangent.h index b9a34a536..d8fb48580 100644 --- a/poincare/include/poincare/arc_tangent.h +++ b/poincare/include/poincare/arc_tangent.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/arithmetic.h b/poincare/include/poincare/arithmetic.h index 0d0d14d3b..1d5c95adb 100644 --- a/poincare/include/poincare/arithmetic.h +++ b/poincare/include/poincare/arithmetic.h @@ -12,6 +12,10 @@ public: constexpr static int k_numberOfPrimeFactors = 1000; constexpr static int k_maxNumberOfPrimeFactors = 32; static const Integer k_primorial32; +private: + /* When decomposing an integer into primes factors, we look for its prime + * factors among integer from 2 to 10000. */ + constexpr static int k_biggestPrimeFactor = 10000; }; } diff --git a/poincare/include/poincare/binomial_coefficient.h b/poincare/include/poincare/binomial_coefficient.h index f0215e7c8..95e562c37 100644 --- a/poincare/include/poincare/binomial_coefficient.h +++ b/poincare/include/poincare/binomial_coefficient.h @@ -21,9 +21,9 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/ceiling.h b/poincare/include/poincare/ceiling.h index 3bd704e49..e0e1363e2 100644 --- a/poincare/include/poincare/ceiling.h +++ b/poincare/include/poincare/ceiling.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -23,11 +23,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/complex.h b/poincare/include/poincare/complex.h index a61500a03..021f679eb 100644 --- a/poincare/include/poincare/complex.h +++ b/poincare/include/poincare/complex.h @@ -3,6 +3,7 @@ #include #include +#include #include namespace Poincare { @@ -12,14 +13,29 @@ namespace PrintFloat { // The wors case is -1.234E-38 return numberOfSignificantDigits + 7; } - /* This function prints the int i in the buffer with a '.' at the position + /* This function prints the integer i in the buffer with a '.' at the position * specified by the decimalMarkerPosition. It starts printing at the end of the * buffer and print from right to left. The integer given should be of the right * length to be written in bufferLength chars. If the integer is to small, the * empty chars on the left side are completed with '0'. If the integer is too * big, the printing stops when no more empty chars are available without - * returning any warning. */ - void printBase10IntegerWithDecimalMarker(char * buffer, int bufferSize, int i, int decimalMarkerPosition); + * returning any warning. + * Warning: the buffer is not null terminated but is ensured to hold + * bufferLength chars. */ + void printBase10IntegerWithDecimalMarker(char * buffer, int bufferLength, Integer i, int decimalMarkerPosition); + + constexpr static int k_numberOfPrintedSignificantDigits = 7; + constexpr static int k_numberOfStoredSignificantDigits = 14; + + /* We here define the buffer size to write the lengthest float possible. + * At maximum, the number has 15 significant digits so, in the worst case it + * has the form -1.99999999999999e-308 (15+7+1 char) (the auto mode is always + * shorter. */ + constexpr static int k_maxFloatBufferLength = k_numberOfStoredSignificantDigits+7+1; + /* We here define the buffer size to write the lengthest complex possible. + * The worst case has the form + * -1.99999999999999e-308*e^(-1.99999999999999e-308*i) (14+14+7+1 char) */ + constexpr static int k_maxComplexBufferLength = k_maxFloatBufferLength-1+k_maxFloatBufferLength-1+7+1; } template @@ -47,6 +63,10 @@ public: Complex * clone() const override; int writeTextInBuffer(char * buffer, int bufferSize) const override; + /* Simplification: complex does not implement simplificationOrderSameType + * because Complex expressions do not appear before evaluation. The sorting + * step is part of simplificaiton process which thus handles no complex. */ + /* The parameter 'DisplayMode' refers to the way to display float 'scientific' * or 'auto'. The scientific mode returns float with style -1.2E2 whereas * the auto mode tries to return 'natural' float like (0.021) and switches @@ -61,23 +81,13 @@ public: static int convertFloatToText(T d, char * buffer, int bufferSize, int numberOfSignificantDigits, Expression::FloatDisplayMode mode = Expression::FloatDisplayMode::Default); private: Complex(T a, T b); - constexpr static int k_numberOfSignificantDigits = 7; ExpressionLayout * privateCreateLayout(Expression::FloatDisplayMode floatDisplayMode, Expression::ComplexFormat complexFormat) const override; - Expression * privateEvaluate(Expression::SinglePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(Expression::DoublePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Complex * templatedEvaluate(Context& context, Expression::AngleUnit angleUnit) const; - /* We here define the buffer size to write the lengthest float possible. - * At maximum, the number has 7 significant digits so, in the worst case it - * has the form -1.999999e-308 (7+7+1 char) (the auto mode is always - * shorter. */ - constexpr static int k_maxFloatBufferLength = 7+7+1; - /* We here define the buffer size to write the lengthest complex possible. - * The worst case has the form -1.999999E-308*e^(-1.999999E-308*i) (14+14+7+1 - * char) */ - constexpr static int k_maxComplexBufferLength = 14+14+7+1; + Expression * privateApproximate(Expression::SinglePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(Expression::DoublePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Complex * templatedApproximate(Context& context, Expression::AngleUnit angleUnit) const; /* convertComplexToText and convertFloatToTextPrivate return the string length * of the buffer (does not count the 0 last char)*/ - int convertComplexToText(char * buffer, int bufferSize, Expression::FloatDisplayMode floatDisplayMode, Expression::ComplexFormat complexFormat) const; + int convertComplexToText(char * buffer, int bufferSize, int numberOfSignificantDigits, Expression::FloatDisplayMode floatDisplayMode, Expression::ComplexFormat complexFormat, char multiplicationSign) const; static int convertFloatToTextPrivate(T f, char * buffer, int numberOfSignificantDigits, Expression::FloatDisplayMode mode); ExpressionLayout * createPolarLayout(Expression::FloatDisplayMode floatDisplayMode) const; ExpressionLayout * createCartesianLayout(Expression::FloatDisplayMode floatDisplayMode) const; diff --git a/poincare/include/poincare/complex_argument.h b/poincare/include/poincare/complex_argument.h index cee734982..6d7f03659 100644 --- a/poincare/include/poincare/complex_argument.h +++ b/poincare/include/poincare/complex_argument.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/confidence_interval.h b/poincare/include/poincare/confidence_interval.h index 9f953e0af..269a47afd 100644 --- a/poincare/include/poincare/confidence_interval.h +++ b/poincare/include/poincare/confidence_interval.h @@ -23,9 +23,9 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(Expression::SinglePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(Expression::DoublePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(Expression::SinglePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(Expression::DoublePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/conjugate.h b/poincare/include/poincare/conjugate.h index 9eb33eaa6..2e199020c 100644 --- a/poincare/include/poincare/conjugate.h +++ b/poincare/include/poincare/conjugate.h @@ -2,7 +2,7 @@ #define POINCARE_CONJUGATE_H #include -#include +#include #include namespace Poincare { @@ -16,17 +16,17 @@ private: /* Layout */ ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; int writeTextInBuffer(char * buffer, int bufferSize) const override { - return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, "conjugate"); + return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, "conj"); } /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/cosine.h b/poincare/include/poincare/cosine.h index 2c23dc3a9..0fd5e471d 100644 --- a/poincare/include/poincare/cosine.h +++ b/poincare/include/poincare/cosine.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include namespace Poincare { @@ -27,11 +27,11 @@ private: /* Simplication */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/decimal.h b/poincare/include/poincare/decimal.h index 72242b183..90ee18b1c 100644 --- a/poincare/include/poincare/decimal.h +++ b/poincare/include/poincare/decimal.h @@ -37,11 +37,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; Expression * shallowBeautify(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, Expression::AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, Expression::AngleUnit angleUnit) const; - constexpr static int k_maxLength = 10; + constexpr static int k_maxLength = 15; Integer m_mantissa; int m_exponent; }; diff --git a/poincare/include/poincare/derivative.h b/poincare/include/poincare/derivative.h index 351fed8a0..c88c18aa4 100644 --- a/poincare/include/poincare/derivative.h +++ b/poincare/include/poincare/derivative.h @@ -24,9 +24,9 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; template T growthRateAroundAbscissa(T x, T h, VariableContext variableContext, AngleUnit angleUnit) const; template T approximateDerivate2(T x, T h, VariableContext xContext, AngleUnit angleUnit) const; // TODO: Change coefficients? diff --git a/poincare/include/poincare/determinant.h b/poincare/include/poincare/determinant.h index 6bb607695..39ad84723 100644 --- a/poincare/include/poincare/determinant.h +++ b/poincare/include/poincare/determinant.h @@ -24,9 +24,9 @@ private: /* Simplification */ Expression * shallowReduce(Context & context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/division.h b/poincare/include/poincare/division.h index d30fe3bd3..8b114ef98 100644 --- a/poincare/include/poincare/division.h +++ b/poincare/include/poincare/division.h @@ -2,7 +2,7 @@ #define POINCARE_DIVISION_H #include -#include +#include #include namespace Poincare { @@ -20,23 +20,23 @@ private: ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; int writeTextInBuffer(char * buffer, int bufferSize) const override { return LayoutEngine::writeInfixExpressionTextInBuffer(this, buffer, bufferSize, "/", [](const Expression * e) { - return e->type() == Type::Multiplication || e->type() == Type::Addition || e->type() == Type::Subtraction || e->type() == Type::Opposite; + return e->type() == Type::Division || e->type() == Type::Multiplication || e->type() == Type::Addition || e->type() == Type::Subtraction || e->type() == Type::Opposite || (e->type() == Type::Rational && !static_cast(e)->denominator().isOne()); }); } /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Matrix * computeOnMatrixAndComplex(const Matrix * m, const Complex * c) { - return EvaluationEngine::elementWiseOnComplexAndComplexMatrix(c, m, compute); + return ApproximationEngine::elementWiseOnComplexAndComplexMatrix(c, m, compute); } template static Matrix * computeOnComplexAndMatrix(const Complex * c, const Matrix * n); template static Matrix * computeOnMatrices(const Matrix * m, const Matrix * n); - virtual Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); + virtual Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } - virtual Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); + virtual Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } }; diff --git a/poincare/include/poincare/division_quotient.h b/poincare/include/poincare/division_quotient.h index 4c2171187..b9e84b9dd 100644 --- a/poincare/include/poincare/division_quotient.h +++ b/poincare/include/poincare/division_quotient.h @@ -24,9 +24,9 @@ private: /* Simplification */ Expression * shallowReduce(Context & context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Complex * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Complex * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/division_remainder.h b/poincare/include/poincare/division_remainder.h index 3c4b1dc87..8316ca63a 100644 --- a/poincare/include/poincare/division_remainder.h +++ b/poincare/include/poincare/division_remainder.h @@ -24,9 +24,9 @@ private: /* Simplification */ Expression * shallowReduce(Context & context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Complex * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Complex * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; diff --git a/poincare/include/poincare/dynamic_hierarchy.h b/poincare/include/poincare/dynamic_hierarchy.h index 2c94e079c..437ca624b 100644 --- a/poincare/include/poincare/dynamic_hierarchy.h +++ b/poincare/include/poincare/dynamic_hierarchy.h @@ -1,12 +1,12 @@ #ifndef POINCARE_DYNAMIC_HIERARCHY_H #define POINCARE_DYNAMIC_HIERARCHY_H -#include +#include #include namespace Poincare { -class DynamicHierarchy : public Hierarchy { +class DynamicHierarchy : public Expression { public: DynamicHierarchy(); DynamicHierarchy(const Expression * const * operands, int numberOfOperands, bool cloneOperands = true); diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index df9a1f6a2..a2150512d 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -72,7 +72,7 @@ class Expression { friend class SimplificationRoot; friend class Sequence; friend class Trigonometry; - friend class EvaluationEngine; + friend class ApproximationEngine; friend class SimplificationEngine; public: @@ -167,15 +167,20 @@ public: static bool shouldStopProcessing(); /* Hierarchy */ - virtual const Expression * operand(int i) const = 0; + virtual const Expression * const * operands() const = 0; + const Expression * operand(int i) const; Expression * editableOperand(int i) { return const_cast(operand(i)); } virtual int numberOfOperands() const = 0; + + Expression * replaceWith(Expression * newOperand, bool deleteAfterReplace = true); + void replaceOperand(const Expression * oldOperand, Expression * newOperand, bool deleteOldOperand = true); + void detachOperand(const Expression * e); // Removes an operand WITHOUT deleting it + void detachOperands(); // Removes all operands WITHOUT deleting them + void swapOperands(int i, int j); + Expression * parent() const { return m_parent; } void setParent(Expression * parent) { m_parent = parent; } bool hasAncestor(const Expression * e) const; - virtual void replaceOperand(const Expression * oldOperand, Expression * newOperand, bool deleteOldOperand = true) = 0; - Expression * replaceWith(Expression * newOperand, bool deleteAfterReplace = true); - virtual void swapOperands(int i, int j) = 0; /* Properties */ enum class Sign { @@ -208,12 +213,15 @@ public: /* Evaluation Engine * The function evaluate creates a new expression and thus mallocs memory. * Do not forget to delete the new expression to avoid leaking. */ - template Expression * evaluate(Context& context, AngleUnit angleUnit = AngleUnit::Default) const; - template T approximate(Context& context, AngleUnit angleUnit = AngleUnit::Default) const; - template static T approximate(const char * text, Context& context, AngleUnit angleUnit = AngleUnit::Default); + template Expression * approximate(Context& context, AngleUnit angleUnit = AngleUnit::Default) const; + template T approximateToScalar(Context& context, AngleUnit angleUnit = AngleUnit::Default) const; + template static T approximateToScalar(const char * text, Context& context, AngleUnit angleUnit = AngleUnit::Default); protected: /* Constructor */ Expression() : m_parent(nullptr) {} + static const Expression * const * ExpressionArray(const Expression * e1, const Expression * e2); + /* Hierarchy */ + void detachOperandAtIndex(int i); /* Evaluation Engine */ typedef float SinglePrecision; typedef double DoublePrecision; @@ -259,8 +267,8 @@ private: return nullptr; } /* Evaluation Engine */ - virtual Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const = 0; - virtual Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const = 0; + virtual Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const = 0; + virtual Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const = 0; Expression * m_parent; }; diff --git a/poincare/include/poincare/factorial.h b/poincare/include/poincare/factorial.h index e0c04785a..da1109b2a 100644 --- a/poincare/include/poincare/factorial.h +++ b/poincare/include/poincare/factorial.h @@ -2,7 +2,7 @@ #define POINCARE_FACTORIAL_H #include -#include +#include namespace Poincare { @@ -14,17 +14,19 @@ public: private: constexpr static int k_maxOperandValue = 100; template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; int writeTextInBuffer(char * buffer, int bufferSize) const override; +#if 0 int simplificationOrderGreaterType(const Expression * e) const override; int simplificationOrderSameType(const Expression * e) const override; +#endif }; } diff --git a/poincare/include/poincare/floor.h b/poincare/include/poincare/floor.h index 8ad78242a..78bfa51f4 100644 --- a/poincare/include/poincare/floor.h +++ b/poincare/include/poincare/floor.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -23,11 +23,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/frac_part.h b/poincare/include/poincare/frac_part.h index 745034d24..21f478c15 100644 --- a/poincare/include/poincare/frac_part.h +++ b/poincare/include/poincare/frac_part.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/great_common_divisor.h b/poincare/include/poincare/great_common_divisor.h index 4005715f0..63a5d0d02 100644 --- a/poincare/include/poincare/great_common_divisor.h +++ b/poincare/include/poincare/great_common_divisor.h @@ -24,9 +24,9 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Complex * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Complex * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/hierarchy.h b/poincare/include/poincare/hierarchy.h deleted file mode 100644 index 43f6769b0..000000000 --- a/poincare/include/poincare/hierarchy.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef POINCARE_HIERARCHY_H -#define POINCARE_HIERARCHY_H - -#include - -namespace Poincare { - -class Hierarchy : public Expression { -public: - using Expression::Expression; - const Expression * operand(int i) const override; - void swapOperands(int i, int j) override; - void replaceOperand(const Expression * oldOperand, Expression * newOperand, bool deleteOldOperand = true) override; - void detachOperand(const Expression * e); // Removes an operand WITHOUT deleting it - void detachOperands(); // Removes all operands WITHOUT deleting them - virtual const Expression * const * operands() const = 0; -protected: - static const Expression * const * ExpressionArray(const Expression * e1, const Expression * e2); -private: - void detachOperandAtIndex(int i); -}; - -} - -#endif diff --git a/poincare/include/poincare/hyperbolic_arc_cosine.h b/poincare/include/poincare/hyperbolic_arc_cosine.h index 4122a0e20..ccab941bc 100644 --- a/poincare/include/poincare/hyperbolic_arc_cosine.h +++ b/poincare/include/poincare/hyperbolic_arc_cosine.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/hyperbolic_arc_sine.h b/poincare/include/poincare/hyperbolic_arc_sine.h index e0ddecba9..25defc87f 100644 --- a/poincare/include/poincare/hyperbolic_arc_sine.h +++ b/poincare/include/poincare/hyperbolic_arc_sine.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/hyperbolic_arc_tangent.h b/poincare/include/poincare/hyperbolic_arc_tangent.h index 755394c64..694973778 100644 --- a/poincare/include/poincare/hyperbolic_arc_tangent.h +++ b/poincare/include/poincare/hyperbolic_arc_tangent.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/hyperbolic_cosine.h b/poincare/include/poincare/hyperbolic_cosine.h index 31dc054fc..ac543dd48 100644 --- a/poincare/include/poincare/hyperbolic_cosine.h +++ b/poincare/include/poincare/hyperbolic_cosine.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/hyperbolic_sine.h b/poincare/include/poincare/hyperbolic_sine.h index 244bb7d5e..b9921d4ea 100644 --- a/poincare/include/poincare/hyperbolic_sine.h +++ b/poincare/include/poincare/hyperbolic_sine.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/hyperbolic_tangent.h b/poincare/include/poincare/hyperbolic_tangent.h index e18448eb8..1ca7f1842 100644 --- a/poincare/include/poincare/hyperbolic_tangent.h +++ b/poincare/include/poincare/hyperbolic_tangent.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/imaginary_part.h b/poincare/include/poincare/imaginary_part.h index f2f713d74..6ece73ab0 100644 --- a/poincare/include/poincare/imaginary_part.h +++ b/poincare/include/poincare/imaginary_part.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/integral.h b/poincare/include/poincare/integral.h index 593f1e14a..f7c7c864f 100644 --- a/poincare/include/poincare/integral.h +++ b/poincare/include/poincare/integral.h @@ -22,16 +22,16 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Complex * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Complex * templatedApproximate(Context& context, AngleUnit angleUnit) const; template struct DetailedResult { T integral; T absoluteError; }; - constexpr static int k_maxNumberOfIterations = 100; + constexpr static int k_maxNumberOfIterations = 10; #ifdef LAGRANGE_METHOD template T lagrangeGaussQuadrature(T a, T b, VariableContext xContext, AngleUnit angleUnit) const; #else diff --git a/poincare/include/poincare/least_common_multiple.h b/poincare/include/poincare/least_common_multiple.h index d151b9c0d..977cea272 100644 --- a/poincare/include/poincare/least_common_multiple.h +++ b/poincare/include/poincare/least_common_multiple.h @@ -24,9 +24,9 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Complex * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Complex * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/logarithm.h b/poincare/include/poincare/logarithm.h index 5b3b0dcef..70c31e83f 100644 --- a/poincare/include/poincare/logarithm.h +++ b/poincare/include/poincare/logarithm.h @@ -26,9 +26,9 @@ private: Expression * splitInteger(Integer i, bool isDenominator, Context & context, AngleUnit angleUnit); /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/matrix.h b/poincare/include/poincare/matrix.h index 1ed00cbc6..fd7ea221b 100644 --- a/poincare/include/poincare/matrix.h +++ b/poincare/include/poincare/matrix.h @@ -33,9 +33,9 @@ private: /* Layout */ ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; int m_numberOfRows; }; diff --git a/poincare/include/poincare/matrix_data.h b/poincare/include/poincare/matrix_data.h index f168aaf1b..53ef2fbe7 100644 --- a/poincare/include/poincare/matrix_data.h +++ b/poincare/include/poincare/matrix_data.h @@ -25,7 +25,6 @@ private: int m_numberOfRows; int m_numberOfColumns; const Expression ** m_operands; - static Complex * defaultExpression(); }; } diff --git a/poincare/include/poincare/matrix_dimension.h b/poincare/include/poincare/matrix_dimension.h index a3922e12b..2e1bc6ec0 100644 --- a/poincare/include/poincare/matrix_dimension.h +++ b/poincare/include/poincare/matrix_dimension.h @@ -20,13 +20,13 @@ private: int writeTextInBuffer(char * buffer, int bufferSize) const override { return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, name()); } - const char * name() const { return "dimension"; } + const char * name() const { return "dim"; } /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/matrix_inverse.h b/poincare/include/poincare/matrix_inverse.h index 7037ebf54..1fbdc7c01 100644 --- a/poincare/include/poincare/matrix_inverse.h +++ b/poincare/include/poincare/matrix_inverse.h @@ -24,9 +24,9 @@ private: /* Simplification */ Expression * shallowReduce(Context & context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/matrix_trace.h b/poincare/include/poincare/matrix_trace.h index e54ce0df5..128fe34d6 100644 --- a/poincare/include/poincare/matrix_trace.h +++ b/poincare/include/poincare/matrix_trace.h @@ -24,9 +24,9 @@ private: /* Simplification */ Expression * shallowReduce(Context & context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/matrix_transpose.h b/poincare/include/poincare/matrix_transpose.h index 13f27bb00..2be3c90cb 100644 --- a/poincare/include/poincare/matrix_transpose.h +++ b/poincare/include/poincare/matrix_transpose.h @@ -24,9 +24,9 @@ private: /* Simplification */ Expression * shallowReduce(Context & context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/multiplication.h b/poincare/include/poincare/multiplication.h index a4e6e1358..6bc68b1ed 100644 --- a/poincare/include/poincare/multiplication.h +++ b/poincare/include/poincare/multiplication.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -22,7 +22,7 @@ public: /* Evaluation */ template static Complex compute(const Complex c, const Complex d); template static Matrix * computeOnComplexAndMatrix(const Complex * c, const Matrix * m) { - return EvaluationEngine::elementWiseOnComplexAndComplexMatrix(c, m, compute); + return ApproximationEngine::elementWiseOnComplexAndComplexMatrix(c, m, compute); } template static Matrix * computeOnMatrices(const Matrix * m, const Matrix * n); private: @@ -34,6 +34,7 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; Expression * privateShallowReduce(Context& context, AngleUnit angleUnit, bool expand); + void mergeMultiplicationOperands(); void factorizeBase(Expression * e1, Expression * e2, Context & context, AngleUnit angleUnit); void factorizeExponent(Expression * e1, Expression * e2, Context & context, AngleUnit angleUnit); Expression * distributeOnOperandAtIndex(int index, Context & context, AngleUnit angleUnit); @@ -44,7 +45,6 @@ private: static bool TermsHaveIdenticalBase(const Expression * e1, const Expression * e2); static bool TermsHaveIdenticalExponent(const Expression * e1, const Expression * e2); static bool TermHasRationalBase(const Expression * e); - static bool TermHasIntegerExponent(const Expression * e); static bool TermHasRationalExponent(const Expression * e); static const Expression * CreateExponent(Expression * e); Expression * shallowBeautify(Context & context, AngleUnit angleUnit) override; @@ -53,13 +53,13 @@ private: /* Evaluation */ template static Matrix * computeOnMatrixAndComplex(const Matrix * m, const Complex * c) { - return EvaluationEngine::elementWiseOnComplexAndComplexMatrix(c, m, compute); + return ApproximationEngine::elementWiseOnComplexAndComplexMatrix(c, m, compute); } - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } }; diff --git a/poincare/include/poincare/naperian_logarithm.h b/poincare/include/poincare/naperian_logarithm.h index 5034cd456..9991b9a51 100644 --- a/poincare/include/poincare/naperian_logarithm.h +++ b/poincare/include/poincare/naperian_logarithm.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/nth_root.h b/poincare/include/poincare/nth_root.h index 3455772d0..facf310e4 100644 --- a/poincare/include/poincare/nth_root.h +++ b/poincare/include/poincare/nth_root.h @@ -22,9 +22,9 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex compute(const Complex c, const Complex d); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; diff --git a/poincare/include/poincare/opposite.h b/poincare/include/poincare/opposite.h index 954409bfc..1c4a0219b 100644 --- a/poincare/include/poincare/opposite.h +++ b/poincare/include/poincare/opposite.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -20,11 +20,11 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, compute); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, compute); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, compute); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, compute); } }; diff --git a/poincare/include/poincare/parenthesis.h b/poincare/include/poincare/parenthesis.h index 93c61a0be..a5a56d291 100644 --- a/poincare/include/poincare/parenthesis.h +++ b/poincare/include/poincare/parenthesis.h @@ -21,9 +21,9 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; diff --git a/poincare/include/poincare/permute_coefficient.h b/poincare/include/poincare/permute_coefficient.h index 0cf54c594..da3497fa2 100644 --- a/poincare/include/poincare/permute_coefficient.h +++ b/poincare/include/poincare/permute_coefficient.h @@ -25,9 +25,9 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Complex * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Complex * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/power.h b/poincare/include/poincare/power.h index ca2e54e12..bc4e4433c 100644 --- a/poincare/include/poincare/power.h +++ b/poincare/include/poincare/power.h @@ -2,7 +2,7 @@ #define POINCARE_POWER_H #include -#include +#include #include #include @@ -14,19 +14,22 @@ class Power : public StaticHierarchy<2> { friend class NthRoot; friend class SquareRoot; friend class Addition; + friend class Division; + friend class Round; public: Type type() const override; Expression * clone() const override; Sign sign() const override; template static Complex compute(const Complex c, const Complex d); private: + constexpr static int k_maxIntegerPower = 100; /* Property */ Expression * setSign(Sign s, Context & context, AngleUnit angleUnit) override; /* Layout */ ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; int writeTextInBuffer(char * buffer, int bufferSize) const override { return LayoutEngine::writeInfixExpressionTextInBuffer(this, buffer, bufferSize, name(), [](const Expression * e) { - return e->type() == Type::Division || e->type() == Type::Multiplication || e->type() == Type::Addition || e->type() == Type::Subtraction || e->type() == Type::Opposite; + return e->type() == Type::Power || e->type() == Type::Division || e->type() == Type::Multiplication || e->type() == Type::Addition || e->type() == Type::Subtraction || e->type() == Type::Opposite || (e->type() == Type::Rational && !static_cast(e)->denominator().isOne()); }); } static const char * name() { return "^"; } @@ -47,17 +50,18 @@ private: static bool TermIsARationalSquareRootOrRational(const Expression * e); static const Rational * RadicandInExpression(const Expression * e); static const Rational * RationalFactorInExpression(const Expression * e); + static bool RationalExponentShouldNotBeReduced(const Rational * r); /* Evaluation */ constexpr static int k_maxApproximatePowerMatrix = 1000; constexpr static int k_maxExactPowerMatrix = 100; template static Matrix * computeOnComplexAndMatrix(const Complex * c, const Matrix * n) { return nullptr; } template static Matrix * computeOnMatrixAndComplex(const Matrix * m, const Complex * d); template static Matrix * computeOnMatrices(const Matrix * m, const Matrix * n) { return nullptr; } - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } }; diff --git a/poincare/include/poincare/prediction_interval.h b/poincare/include/poincare/prediction_interval.h index bef5d3963..7c3875e10 100644 --- a/poincare/include/poincare/prediction_interval.h +++ b/poincare/include/poincare/prediction_interval.h @@ -23,9 +23,9 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(Expression::SinglePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(Expression::DoublePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(Expression::SinglePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(Expression::DoublePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/preferences.h b/poincare/include/poincare/preferences.h index 4b0281d9b..40925dbd6 100644 --- a/poincare/include/poincare/preferences.h +++ b/poincare/include/poincare/preferences.h @@ -15,10 +15,13 @@ public: void setDisplayMode(Expression::FloatDisplayMode FloatDisplayMode); Expression::ComplexFormat complexFormat() const; void setComplexFormat(Expression::ComplexFormat complexFormat); + char numberOfSignificantDigits() const; + void setNumberOfSignificantDigits(char numberOfSignificantDigits); private: Expression::AngleUnit m_angleUnit; Expression::FloatDisplayMode m_displayMode; Expression::ComplexFormat m_complexFormat; + char m_numberOfSignificantDigits; }; } diff --git a/poincare/include/poincare/product.h b/poincare/include/poincare/product.h index 031b85bf7..ba5fe91c5 100644 --- a/poincare/include/poincare/product.h +++ b/poincare/include/poincare/product.h @@ -15,12 +15,12 @@ private: int emptySequenceValue() const override; ExpressionLayout * createSequenceLayoutWithArgumentLayouts(ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout, ExpressionLayout * argumentLayout) const override; Expression * evaluateWithNextTerm(DoublePrecision p, Expression * a, Expression * b) const override { - return templatedEvaluateWithNextTerm(a, b); + return templatedApproximateWithNextTerm(a, b); } Expression * evaluateWithNextTerm(SinglePrecision p, Expression * a, Expression * b) const override { - return templatedEvaluateWithNextTerm(a, b); + return templatedApproximateWithNextTerm(a, b); } - template Expression * templatedEvaluateWithNextTerm(Expression * a, Expression * b) const; + template Expression * templatedApproximateWithNextTerm(Expression * a, Expression * b) const; }; } diff --git a/poincare/include/poincare/rational.h b/poincare/include/poincare/rational.h index 776298378..52435dc8f 100644 --- a/poincare/include/poincare/rational.h +++ b/poincare/include/poincare/rational.h @@ -44,9 +44,9 @@ public: private: ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; int writeTextInBuffer(char * buffer, int bufferSize) const override; - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Complex * templatedEvaluate(Context& context, Expression::AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Complex * templatedApproximate(Context& context, Expression::AngleUnit angleUnit) const; Expression * shallowBeautify(Context & context, AngleUnit angleUnit) override; Expression * setSign(Sign s); Expression * setSign(Sign s, Context & context, AngleUnit angleUnit) override { diff --git a/poincare/include/poincare/real_part.h b/poincare/include/poincare/real_part.h index bcc7b2424..adfe7f0ee 100644 --- a/poincare/include/poincare/real_part.h +++ b/poincare/include/poincare/real_part.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -25,11 +25,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/round.h b/poincare/include/poincare/round.h index b9353bb7a..885dc0a7a 100644 --- a/poincare/include/poincare/round.h +++ b/poincare/include/poincare/round.h @@ -24,9 +24,9 @@ private: /* Simplification */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Complex */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Complex * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Complex * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/include/poincare/sequence.h b/poincare/include/poincare/sequence.h index 503b5529c..38959bc42 100644 --- a/poincare/include/poincare/sequence.h +++ b/poincare/include/poincare/sequence.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -17,9 +17,9 @@ private: virtual ExpressionLayout * createSequenceLayoutWithArgumentLayouts(ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout, ExpressionLayout * argumentLayout) const = 0; virtual const char * name() const = 0; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; virtual int emptySequenceValue() const = 0; virtual Expression * evaluateWithNextTerm(SinglePrecision p, Expression * a, Expression * b) const = 0; virtual Expression * evaluateWithNextTerm(DoublePrecision p, Expression * a, Expression * b) const = 0; diff --git a/poincare/include/poincare/simplification_root.h b/poincare/include/poincare/simplification_root.h index 033c3e5b9..09e50ac08 100644 --- a/poincare/include/poincare/simplification_root.h +++ b/poincare/include/poincare/simplification_root.h @@ -23,11 +23,11 @@ public: return nullptr; } int writeTextInBuffer(char * buffer, int bufferSize) const override { return 0; } - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { assert(false); return nullptr; } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { assert(false); return nullptr; } diff --git a/poincare/include/poincare/sine.h b/poincare/include/poincare/sine.h index 300b224d6..93fbc4670 100644 --- a/poincare/include/poincare/sine.h +++ b/poincare/include/poincare/sine.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include namespace Poincare { @@ -27,11 +27,11 @@ private: /* Simplication */ Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/square_root.h b/poincare/include/poincare/square_root.h index e567363cb..be1ee0094 100644 --- a/poincare/include/poincare/square_root.h +++ b/poincare/include/poincare/square_root.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -20,11 +20,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/static_hierarchy.h b/poincare/include/poincare/static_hierarchy.h index 26c2e33a7..24edcd9d0 100644 --- a/poincare/include/poincare/static_hierarchy.h +++ b/poincare/include/poincare/static_hierarchy.h @@ -1,13 +1,13 @@ #ifndef POINCARE_STATIC_HIERARCHY_H #define POINCARE_STATIC_HIERARCHY_H -#include +#include #include namespace Poincare { template -class StaticHierarchy : public Hierarchy { +class StaticHierarchy : public Expression { public: StaticHierarchy(); StaticHierarchy(const Expression * const * operands, bool cloneOperands = true); diff --git a/poincare/include/poincare/store.h b/poincare/include/poincare/store.h index 4cbc28795..e58d4e961 100644 --- a/poincare/include/poincare/store.h +++ b/poincare/include/poincare/store.h @@ -18,9 +18,9 @@ private: ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; int writeTextInBuffer(char * buffer, int bufferSize) const override; /* Evalutation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; const Symbol * symbol() const { return static_cast(operand(1)); } const Expression * value() const { return operand(0); } diff --git a/poincare/include/poincare/subtraction.h b/poincare/include/poincare/subtraction.h index 2f249b9f1..3c604d651 100644 --- a/poincare/include/poincare/subtraction.h +++ b/poincare/include/poincare/subtraction.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -26,18 +26,18 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Matrix * computeOnMatrixAndComplex(const Matrix * m, const Complex * c) { - return EvaluationEngine::elementWiseOnComplexAndComplexMatrix(c, m, compute); + return ApproximationEngine::elementWiseOnComplexAndComplexMatrix(c, m, compute); } template static Matrix * computeOnComplexAndMatrix(const Complex * c, const Matrix * n); template static Matrix * computeOnMatrices(const Matrix * m, const Matrix * n) { - return EvaluationEngine::elementWiseOnComplexMatrices(m, n, compute); + return ApproximationEngine::elementWiseOnComplexMatrices(m, n, compute); } - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::mapReduce(this, context, angleUnit, compute, computeOnComplexAndMatrix, computeOnMatrixAndComplex, computeOnMatrices); } }; diff --git a/poincare/include/poincare/sum.h b/poincare/include/poincare/sum.h index b4ceff686..854e59d57 100644 --- a/poincare/include/poincare/sum.h +++ b/poincare/include/poincare/sum.h @@ -15,12 +15,12 @@ private: int emptySequenceValue() const override; ExpressionLayout * createSequenceLayoutWithArgumentLayouts(ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout, ExpressionLayout * argumentLayout) const override; Expression * evaluateWithNextTerm(DoublePrecision p, Expression * a, Expression * b) const override { - return templatedEvaluateWithNextTerm(a, b); + return templatedApproximateWithNextTerm(a, b); } Expression * evaluateWithNextTerm(SinglePrecision p, Expression * a, Expression * b) const override { - return templatedEvaluateWithNextTerm(a, b); + return templatedApproximateWithNextTerm(a, b); } - template Expression * templatedEvaluateWithNextTerm(Expression * a, Expression * b) const; + template Expression * templatedApproximateWithNextTerm(Expression * a, Expression * b) const; }; } diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index d071272bb..9e7f3fb3f 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -36,6 +36,7 @@ public: Expression * clone() const override; Sign sign() const override; bool isMatrixSymbol() const; + bool isScalarSymbol() const; private: const char * textForSpecialSymbols(char name) const; /* Comparison */ @@ -44,9 +45,9 @@ private: ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; int writeTextInBuffer(char * buffer, int bufferSize) const override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Expression * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Expression * templatedApproximate(Context& context, AngleUnit angleUnit) const; const char m_name; }; diff --git a/poincare/include/poincare/tangent.h b/poincare/include/poincare/tangent.h index 04f70029e..f201e4c69 100644 --- a/poincare/include/poincare/tangent.h +++ b/poincare/include/poincare/tangent.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Poincare { @@ -26,11 +26,11 @@ private: Expression * shallowReduce(Context& context, AngleUnit angleUnit) override; /* Evaluation */ template static Complex computeOnComplex(const Complex c, AngleUnit angleUnit = AngleUnit::Radian); - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit,computeOnComplex); + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit,computeOnComplex); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } }; diff --git a/poincare/include/poincare/undefined.h b/poincare/include/poincare/undefined.h index 11154047d..672294b72 100644 --- a/poincare/include/poincare/undefined.h +++ b/poincare/include/poincare/undefined.h @@ -15,9 +15,9 @@ private: /* Layout */ ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; /* Evaluation */ - Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedEvaluate(context, angleUnit); } - template Complex * templatedEvaluate(Context& context, AngleUnit angleUnit) const; + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Complex * templatedApproximate(Context& context, AngleUnit angleUnit) const; }; } diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index 0580f915a..775f38352 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -165,14 +165,16 @@ Expression * Addition::factorizeOnCommonDenominator(Context & context, AngleUnit // want to create numerator = a/b*b*d + c/d*b*d + e/b*b*d Addition * numerator = new Addition(); for (int i=0; i < numberOfOperands(); i++) { - numerator->addOperand(new Multiplication(operand(i), commonDenominator, true)); + Expression * m = new Multiplication(operand(i), commonDenominator, true); + numerator->addOperand(m); + m->shallowReduce(context, angleUnit); } // Step 3: Add the denominator Power * inverseDenominator = new Power(commonDenominator, new Rational(-1), false); Multiplication * result = new Multiplication(numerator, inverseDenominator, false); // Step 4: Simplify the numerator to a*d + c*b + e*d - numerator->deepReduce(context, angleUnit); + numerator->shallowReduce(context, angleUnit); // Step 5: Simplify the denominator (in case it's a rational number) commonDenominator->deepReduce(context, angleUnit); diff --git a/poincare/src/evaluation_engine.cpp b/poincare/src/approximation_engine.cpp similarity index 50% rename from poincare/src/evaluation_engine.cpp rename to poincare/src/approximation_engine.cpp index ddab709b7..da5902d51 100644 --- a/poincare/src/evaluation_engine.cpp +++ b/poincare/src/approximation_engine.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include extern "C" { @@ -7,9 +7,9 @@ extern "C" { namespace Poincare { -template Expression * EvaluationEngine::map(const Expression * expression, Context& context, Expression::AngleUnit angleUnit, ComplexCompute compute) { +template Expression * ApproximationEngine::map(const Expression * expression, Context& context, Expression::AngleUnit angleUnit, ComplexCompute compute) { assert(expression->numberOfOperands() == 1); - Expression * input = expression->operand(0)->evaluate(context, angleUnit); + Expression * input = expression->operand(0)->approximate(context, angleUnit); Expression * result = nullptr; if (input->type() == Expression::Type::Complex) { Complex * c = static_cast *>(input); @@ -29,11 +29,11 @@ template Expression * EvaluationEngine::map(const Expression * expre return result; } -template Expression * EvaluationEngine::mapReduce(const Expression * expression, Context& context, Expression::AngleUnit angleUnit, ComplexAndComplexReduction computeOnComplexes, ComplexAndMatrixReduction computeOnComplexAndMatrix, MatrixAndComplexReduction computeOnMatrixAndComplex, MatrixAndMatrixReduction computeOnMatrices) { - Expression * result = expression->operand(0)->evaluate(context, angleUnit); +template Expression * ApproximationEngine::mapReduce(const Expression * expression, Context& context, Expression::AngleUnit angleUnit, ComplexAndComplexReduction computeOnComplexes, ComplexAndMatrixReduction computeOnComplexAndMatrix, MatrixAndComplexReduction computeOnMatrixAndComplex, MatrixAndMatrixReduction computeOnMatrices) { + Expression * result = expression->operand(0)->approximate(context, angleUnit); for (int i = 1; i < expression->numberOfOperands(); i++) { Expression * intermediateResult = nullptr; - Expression * nextOperandEvaluation = expression->operand(i)->evaluate(context, angleUnit); + Expression * nextOperandEvaluation = expression->operand(i)->approximate(context, angleUnit); if (result->type() == Expression::Type::Complex && nextOperandEvaluation->type() == Expression::Type::Complex) { const Complex * c = static_cast *>(result); const Complex * d = static_cast *>(nextOperandEvaluation); @@ -65,7 +65,7 @@ template Expression * EvaluationEngine::mapReduce(const Expression * return result; } -template Matrix * EvaluationEngine::elementWiseOnComplexAndComplexMatrix(const Complex * c, const Matrix * m, ComplexAndComplexReduction computeOnComplexes) { +template Matrix * ApproximationEngine::elementWiseOnComplexAndComplexMatrix(const Complex * c, const Matrix * m, ComplexAndComplexReduction computeOnComplexes) { Expression ** operands = new Expression * [m->numberOfRows()*m->numberOfColumns()]; for (int i = 0; i < m->numberOfOperands(); i++) { const Complex * d = static_cast *>(m->operand(i)); @@ -76,7 +76,7 @@ template Matrix * EvaluationEngine::elementWiseOnComplexAndComplexMa return result; } -template Matrix * EvaluationEngine::elementWiseOnComplexMatrices(const Matrix * m, const Matrix * n, ComplexAndComplexReduction computeOnComplexes) { +template Matrix * ApproximationEngine::elementWiseOnComplexMatrices(const Matrix * m, const Matrix * n, ComplexAndComplexReduction computeOnComplexes) { if (m->numberOfRows() != n->numberOfRows() || m->numberOfColumns() != n->numberOfColumns()) { return nullptr; } @@ -91,14 +91,14 @@ template Matrix * EvaluationEngine::elementWiseOnComplexMatrices(con return result; } -template Poincare::Expression * Poincare::EvaluationEngine::map(const Poincare::Expression * expression, Poincare::Context& context, Poincare::Expression::AngleUnit angleUnit, Poincare::EvaluationEngine::ComplexCompute compute); -template Poincare::Expression * Poincare::EvaluationEngine::map(const Poincare::Expression * expression, Poincare::Context& context, Poincare::Expression::AngleUnit angleUnit, Poincare::EvaluationEngine::ComplexCompute compute); -template Poincare::Expression * Poincare::EvaluationEngine::mapReduce(const Poincare::Expression * expression, Poincare::Context& context, Poincare::Expression::AngleUnit angleUnit, Poincare::EvaluationEngine::ComplexAndComplexReduction computeOnComplexes, Poincare::EvaluationEngine::ComplexAndMatrixReduction computeOnComplexAndMatrix, Poincare::EvaluationEngine::MatrixAndComplexReduction computeOnMatrixAndComplex, Poincare::EvaluationEngine::MatrixAndMatrixReduction computeOnMatrices); -template Poincare::Expression * Poincare::EvaluationEngine::mapReduce(const Poincare::Expression * expression, Poincare::Context& context, Poincare::Expression::AngleUnit angleUnit, Poincare::EvaluationEngine::ComplexAndComplexReduction computeOnComplexes, Poincare::EvaluationEngine::ComplexAndMatrixReduction computeOnComplexAndMatrix, Poincare::EvaluationEngine::MatrixAndComplexReduction computeOnMatrixAndComplex, Poincare::EvaluationEngine::MatrixAndMatrixReduction computeOnMatrices); -template Poincare::Matrix * Poincare::EvaluationEngine::elementWiseOnComplexAndComplexMatrix(Poincare::Complex const*, const Poincare::Matrix *, Poincare::Complex (*)(Poincare::Complex, Poincare::Complex)); -template Poincare::Matrix* Poincare::EvaluationEngine::elementWiseOnComplexAndComplexMatrix(Poincare::Complex const*, const Poincare::Matrix*, Poincare::Complex (*)(Poincare::Complex, Poincare::Complex)); -template Poincare::Matrix* Poincare::EvaluationEngine::elementWiseOnComplexMatrices(const Poincare::Matrix*, const Poincare::Matrix*, Poincare::Complex (*)(Poincare::Complex, Poincare::Complex)); -template Poincare::Matrix* Poincare::EvaluationEngine::elementWiseOnComplexMatrices(const Poincare::Matrix*, const Poincare::Matrix*, Poincare::Complex (*)(Poincare::Complex, Poincare::Complex)); +template Poincare::Expression * Poincare::ApproximationEngine::map(const Poincare::Expression * expression, Poincare::Context& context, Poincare::Expression::AngleUnit angleUnit, Poincare::ApproximationEngine::ComplexCompute compute); +template Poincare::Expression * Poincare::ApproximationEngine::map(const Poincare::Expression * expression, Poincare::Context& context, Poincare::Expression::AngleUnit angleUnit, Poincare::ApproximationEngine::ComplexCompute compute); +template Poincare::Expression * Poincare::ApproximationEngine::mapReduce(const Poincare::Expression * expression, Poincare::Context& context, Poincare::Expression::AngleUnit angleUnit, Poincare::ApproximationEngine::ComplexAndComplexReduction computeOnComplexes, Poincare::ApproximationEngine::ComplexAndMatrixReduction computeOnComplexAndMatrix, Poincare::ApproximationEngine::MatrixAndComplexReduction computeOnMatrixAndComplex, Poincare::ApproximationEngine::MatrixAndMatrixReduction computeOnMatrices); +template Poincare::Expression * Poincare::ApproximationEngine::mapReduce(const Poincare::Expression * expression, Poincare::Context& context, Poincare::Expression::AngleUnit angleUnit, Poincare::ApproximationEngine::ComplexAndComplexReduction computeOnComplexes, Poincare::ApproximationEngine::ComplexAndMatrixReduction computeOnComplexAndMatrix, Poincare::ApproximationEngine::MatrixAndComplexReduction computeOnMatrixAndComplex, Poincare::ApproximationEngine::MatrixAndMatrixReduction computeOnMatrices); +template Poincare::Matrix * Poincare::ApproximationEngine::elementWiseOnComplexAndComplexMatrix(Poincare::Complex const*, const Poincare::Matrix *, Poincare::Complex (*)(Poincare::Complex, Poincare::Complex)); +template Poincare::Matrix* Poincare::ApproximationEngine::elementWiseOnComplexAndComplexMatrix(Poincare::Complex const*, const Poincare::Matrix*, Poincare::Complex (*)(Poincare::Complex, Poincare::Complex)); +template Poincare::Matrix* Poincare::ApproximationEngine::elementWiseOnComplexMatrices(const Poincare::Matrix*, const Poincare::Matrix*, Poincare::Complex (*)(Poincare::Complex, Poincare::Complex)); +template Poincare::Matrix* Poincare::ApproximationEngine::elementWiseOnComplexMatrices(const Poincare::Matrix*, const Poincare::Matrix*, Poincare::Complex (*)(Poincare::Complex, Poincare::Complex)); } diff --git a/poincare/src/arithmetic.cpp b/poincare/src/arithmetic.cpp index f5fe302d1..161db6938 100644 --- a/poincare/src/arithmetic.cpp +++ b/poincare/src/arithmetic.cpp @@ -73,7 +73,7 @@ void Arithmetic::PrimeFactorization(const Integer * n, Integer * outputFactors, k++; testedPrimeFactor = k < k_numberOfPrimeFactors ? Integer(primeFactors[k]) : Integer::Addition(testedPrimeFactor, Integer(1)); outputFactors[t] = testedPrimeFactor; - } while (stopCondition); + } while (stopCondition && testedPrimeFactor.isLowerThan(Integer(k_biggestPrimeFactor))); outputFactors[t] = std::move(m); outputCoefficients[t] = Integer::Addition(outputCoefficients[t], Integer(1)); } diff --git a/poincare/src/binomial_coefficient.cpp b/poincare/src/binomial_coefficient.cpp index ae2812a92..b1d947a48 100644 --- a/poincare/src/binomial_coefficient.cpp +++ b/poincare/src/binomial_coefficient.cpp @@ -83,9 +83,9 @@ ExpressionLayout * BinomialCoefficient::privateCreateLayout(FloatDisplayMode flo } template -Expression * BinomialCoefficient::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * nInput = operand(0)->evaluate(context, angleUnit); - Expression * kInput = operand(1)->evaluate(context, angleUnit); +Expression * BinomialCoefficient::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * nInput = operand(0)->approximate(context, angleUnit); + Expression * kInput = operand(1)->approximate(context, angleUnit); if (nInput->type() != Type::Complex || kInput->type() != Type::Complex) { return new Complex(Complex::Float(NAN)); } diff --git a/poincare/src/complex.cpp b/poincare/src/complex.cpp index cdfa5eba6..34859247f 100644 --- a/poincare/src/complex.cpp +++ b/poincare/src/complex.cpp @@ -13,31 +13,28 @@ extern "C" { namespace Poincare { -void PrintFloat::printBase10IntegerWithDecimalMarker(char * buffer, int bufferSize, int i, int decimalMarkerPosition) { +void PrintFloat::printBase10IntegerWithDecimalMarker(char * buffer, int bufferLength, Integer i, int decimalMarkerPosition) { /* The decimal marker position is always preceded by a char, thus, it is never * in first position. When called by convertFloatToText, the buffer length is * always > 0 as we asserted a minimal number of available chars. */ - assert(bufferSize > 0 && decimalMarkerPosition != 0); - int endChar = bufferSize - 1, startChar = 0; - int dividend = i, digit = 0, quotien = 0; - if (i < 0) { - buffer[startChar++] = '-'; - dividend = -i; - decimalMarkerPosition += 1; - } - /* This loop acts correctly as we asserted the endChar >= 0 and - * decimalMarkerPosition != 0 */ - do { - if (endChar == decimalMarkerPosition) { - assert(endChar >= 0 && endChar < bufferSize); - buffer[endChar--] = '.'; + assert(bufferLength > 0 && decimalMarkerPosition != 0); + char tempBuffer[PrintFloat::k_maxFloatBufferLength]; + int intLength = i.writeTextInBuffer(tempBuffer, PrintFloat::k_maxFloatBufferLength); + int firstDigitChar = tempBuffer[0] == '-' ? 1 : 0; + for (int k = bufferLength-1; k >= firstDigitChar; k--) { + if (k == decimalMarkerPosition) { + buffer[k] = '.'; + continue; } - quotien = dividend/10; - digit = dividend - quotien*10; - assert(endChar >= 0 && endChar < bufferSize); - buffer[endChar--] = '0'+digit; - dividend = quotien; - } while (endChar >= startChar); + if (intLength > firstDigitChar) { + buffer[k] = tempBuffer[--intLength]; + continue; + } + buffer[k] = '0'; + } + if (firstDigitChar == 1) { + buffer[0] = tempBuffer[0]; + } } template @@ -200,7 +197,7 @@ T Complex::toScalar() const { template int Complex::writeTextInBuffer(char * buffer, int bufferSize) const { - return convertComplexToText(buffer, bufferSize, Preferences::sharedPreferences()->displayMode(), Preferences::sharedPreferences()->complexFormat()); + return convertComplexToText(buffer, bufferSize, PrintFloat::k_numberOfStoredSignificantDigits, Preferences::sharedPreferences()->displayMode(), Preferences::sharedPreferences()->complexFormat(), Ion::Charset::MultiplicationSign); } template @@ -210,7 +207,7 @@ int Complex::convertFloatToText(T f, char * buffer, int bufferSize, if (mode == Expression::FloatDisplayMode::Default) { return convertFloatToText(f, buffer, bufferSize, numberOfSignificantDigits, Preferences::sharedPreferences()->displayMode()); } - char tempBuffer[k_maxFloatBufferLength]; + char tempBuffer[PrintFloat::k_maxFloatBufferLength]; int requiredLength = convertFloatToTextPrivate(f, tempBuffer, numberOfSignificantDigits, mode); /* if the required buffer size overflows the buffer size, we first force the * display mode to scientific and decrease the number of significant digits to @@ -248,22 +245,22 @@ ExpressionLayout * Complex::privateCreateLayout(Expression::FloatDisplayMode template template -Complex * Complex::templatedEvaluate(Context& context, Expression::AngleUnit angleUnit) const { +Complex * Complex::templatedApproximate(Context& context, Expression::AngleUnit angleUnit) const { return new Complex(Complex::Cartesian((U)m_a, (U)m_b)); } template -int Complex::convertComplexToText(char * buffer, int bufferSize, Expression::FloatDisplayMode displayMode, Expression::ComplexFormat complexFormat) const { +int Complex::convertComplexToText(char * buffer, int bufferSize, int numberOfSignificantDigits, Expression::FloatDisplayMode displayMode, Expression::ComplexFormat complexFormat, char multiplicationSpecialChar) const { assert(displayMode != Expression::FloatDisplayMode::Default); int numberOfChars = 0; if (std::isnan(m_a) || std::isnan(m_b)) { - return convertFloatToText(NAN, buffer, bufferSize, k_numberOfSignificantDigits, displayMode); + return convertFloatToText(NAN, buffer, bufferSize, numberOfSignificantDigits, displayMode); } if (complexFormat == Expression::ComplexFormat::Polar) { if (r() != 1 || th() == 0) { - numberOfChars = convertFloatToText(r(), buffer, bufferSize, k_numberOfSignificantDigits, displayMode); + numberOfChars = convertFloatToText(r(), buffer, bufferSize, numberOfSignificantDigits, displayMode); if (r() != 0 && th() != 0 && bufferSize > numberOfChars+1) { - buffer[numberOfChars++] = '*'; + buffer[numberOfChars++] = multiplicationSpecialChar; // Ensure that the string is null terminated even if buffer size is to small buffer[numberOfChars] = 0; } @@ -276,9 +273,9 @@ int Complex::convertComplexToText(char * buffer, int bufferSize, Expression:: // Ensure that the string is null terminated even if buffer size is to small buffer[numberOfChars] = 0; } - numberOfChars += convertFloatToText(th(), buffer+numberOfChars, bufferSize-numberOfChars, k_numberOfSignificantDigits, displayMode); + numberOfChars += convertFloatToText(th(), buffer+numberOfChars, bufferSize-numberOfChars, numberOfSignificantDigits, displayMode); if (bufferSize > numberOfChars+3) { - buffer[numberOfChars++] = '*'; + buffer[numberOfChars++] = multiplicationSpecialChar; buffer[numberOfChars++] = Ion::Charset::IComplex; buffer[numberOfChars++] = ')'; buffer[numberOfChars] = 0; @@ -288,7 +285,7 @@ int Complex::convertComplexToText(char * buffer, int bufferSize, Expression:: } if (m_a != 0 || m_b == 0) { - numberOfChars = convertFloatToText(m_a, buffer, bufferSize, k_numberOfSignificantDigits, displayMode); + numberOfChars = convertFloatToText(m_a, buffer, bufferSize, numberOfSignificantDigits, displayMode); if (m_b > 0 && !std::isnan(m_b) && bufferSize > numberOfChars+1) { buffer[numberOfChars++] = '+'; // Ensure that the string is null terminated even if buffer size is to small @@ -296,8 +293,8 @@ int Complex::convertComplexToText(char * buffer, int bufferSize, Expression:: } } if (m_b != 1 && m_b != -1 && m_b != 0) { - numberOfChars += convertFloatToText(m_b, buffer+numberOfChars, bufferSize-numberOfChars, k_numberOfSignificantDigits, displayMode); - buffer[numberOfChars++] = '*'; + numberOfChars += convertFloatToText(m_b, buffer+numberOfChars, bufferSize-numberOfChars, numberOfSignificantDigits, displayMode); + buffer[numberOfChars++] = multiplicationSpecialChar; } if (m_b == -1 && bufferSize > numberOfChars+1) { buffer[numberOfChars++] = '-'; @@ -313,7 +310,7 @@ template int Complex::convertFloatToTextPrivate(T f, char * buffer, int numberOfSignificantDigits, Expression::FloatDisplayMode mode) { assert(mode != Expression::FloatDisplayMode::Default); assert(numberOfSignificantDigits > 0); - if (std::isinf(f)) { + /*if (std::isinf(f)) { int currentChar = 0; if (f < 0) { buffer[currentChar++] = '-'; @@ -323,9 +320,9 @@ int Complex::convertFloatToTextPrivate(T f, char * buffer, int numberOfSignif buffer[currentChar++] = 'f'; buffer[currentChar] = 0; return currentChar; - } + }*/ - if (std::isnan(f)) { + if (std::isinf(f) || std::isnan(f)) { int currentChar = 0; buffer[currentChar++] = 'u'; buffer[currentChar++] = 'n'; @@ -354,14 +351,17 @@ int Complex::convertFloatToTextPrivate(T f, char * buffer, int numberOfSignif int availableCharsForMantissaWithSign = f >= 0 ? availableCharsForMantissaWithoutSign : availableCharsForMantissaWithoutSign + 1; // Compute mantissa - /* The number of digits in an integer is capped because the maximal integer is - * 2^31 - 1. As our mantissa is an integer, we assert that we stay beyond this - * threshold during computation. */ - assert(availableCharsForMantissaWithoutSign - 1 < std::log10(std::pow(2.0f, 31.0f))); + /* The number of digits in an mantissa is capped because the maximal int64_t + * is 2^63 - 1. As our mantissa is an integer built from an int64_t, we assert + * that we stay beyond this threshold during computation. */ + assert(availableCharsForMantissaWithoutSign - 1 < std::log10(std::pow(2.0f, 63.0f))); int numberOfDigitBeforeDecimal = exponentInBase10 >= 0 || displayMode == Expression::FloatDisplayMode::Scientific ? exponentInBase10 + 1 : 1; - T mantissa = std::round(f * std::pow(10, (T)availableCharsForMantissaWithoutSign - 1 - numberOfDigitBeforeDecimal)); + + T unroundedMantissa = f * std::pow(10, (T)availableCharsForMantissaWithoutSign - 1 - numberOfDigitBeforeDecimal); + T mantissa = std::round(unroundedMantissa); + /* if availableCharsForMantissaWithoutSign - 1 - numberOfDigitBeforeDecimal * is too big (or too small), mantissa is now inf. We handle this case by * using logarithm function. */ @@ -371,24 +371,18 @@ int Complex::convertFloatToTextPrivate(T f, char * buffer, int numberOfSignif } /* We update the exponent in base 10 (if 0.99999999 was rounded to 1 for * instance) */ - T truncatedMantissa = (int)(f * std::pow(10, (T)(availableCharsForMantissaWithoutSign - 1 - numberOfDigitBeforeDecimal))); - if (std::isinf(truncatedMantissa) || std::isnan(truncatedMantissa)) { - truncatedMantissa = (int)(std::pow(10, std::log10(std::fabs(f))+(T)(availableCharsForMantissaWithoutSign - 1 - numberOfDigitBeforeDecimal))); - truncatedMantissa = std::copysign(truncatedMantissa, f); - } - if (mantissa != truncatedMantissa) { - T newLogBase10 = mantissa != 0 ? std::log10(std::fabs(mantissa/std::pow((T)10, (T)(availableCharsForMantissaWithoutSign - 1 - numberOfDigitBeforeDecimal)))) : 0; - if (std::isnan(newLogBase10) || std::isinf(newLogBase10)) { - newLogBase10 = std::log10(std::fabs((T)mantissa)) - (T)(availableCharsForMantissaWithoutSign - 1 - numberOfDigitBeforeDecimal); - } - exponentInBase10 = std::floor(newLogBase10); + T newLogBase10 = mantissa != 0 ? std::log10(std::fabs(mantissa/std::pow((T)10, (T)(availableCharsForMantissaWithoutSign - 1 - numberOfDigitBeforeDecimal)))) : 0; + if (std::isnan(newLogBase10) || std::isinf(newLogBase10)) { + newLogBase10 = std::log10(std::fabs((T)mantissa)) - (T)(availableCharsForMantissaWithoutSign - 1 - numberOfDigitBeforeDecimal); } + exponentInBase10 = std::floor(newLogBase10); int decimalMarkerPosition = exponentInBase10 < 0 || displayMode == Expression::FloatDisplayMode::Scientific ? 1 : exponentInBase10+1; + decimalMarkerPosition = f < 0 ? decimalMarkerPosition+1 : decimalMarkerPosition; // Correct the number of digits in mantissa after rounding int mantissaExponentInBase10 = exponentInBase10 > 0 || displayMode == Expression::FloatDisplayMode::Scientific ? availableCharsForMantissaWithoutSign - 1 : availableCharsForMantissaWithoutSign + exponentInBase10; - if ((int)(std::fabs(mantissa) * std::pow((T)10, - mantissaExponentInBase10)) > 0) { + if (std::floor(std::fabs((T)mantissa) * std::pow((T)10, - mantissaExponentInBase10)) > 0) { mantissa = mantissa/10; } @@ -399,18 +393,18 @@ int Complex::convertFloatToTextPrivate(T f, char * buffer, int numberOfSignif } // Supress the 0 on the right side of the mantissa - int dividend = std::fabs((T)mantissa); - int quotien = dividend/10; - int digit = dividend - quotien*10; + Integer dividend = Integer((int64_t)std::fabs(mantissa)); + Integer quotient = Integer::Division(dividend, Integer(10)).quotient; + Integer digit = Integer::Subtraction(dividend, Integer::Multiplication(quotient, Integer(10))); int minimumNumberOfCharsInMantissa = 1; - while (digit == 0 && availableCharsForMantissaWithoutSign > minimumNumberOfCharsInMantissa && + while (digit.isZero() && availableCharsForMantissaWithoutSign > minimumNumberOfCharsInMantissa && (availableCharsForMantissaWithoutSign > exponentInBase10+2 || displayMode == Expression::FloatDisplayMode::Scientific)) { mantissa = mantissa/10; availableCharsForMantissaWithoutSign--; availableCharsForMantissaWithSign--; - dividend = quotien; - quotien = dividend/10; - digit = dividend - quotien*10; + dividend = quotient; + quotient = Integer::Division(dividend, Integer(10)).quotient; + digit = Integer::Subtraction(dividend, Integer::Multiplication(quotient, Integer(10))); } // Suppress the decimal marker if no fractional part @@ -420,36 +414,36 @@ int Complex::convertFloatToTextPrivate(T f, char * buffer, int numberOfSignif } // Print mantissa - assert(availableCharsForMantissaWithSign < k_maxFloatBufferLength); - PrintFloat::printBase10IntegerWithDecimalMarker(buffer, availableCharsForMantissaWithSign, mantissa, decimalMarkerPosition); + assert(availableCharsForMantissaWithSign < PrintFloat::k_maxFloatBufferLength); + PrintFloat::printBase10IntegerWithDecimalMarker(buffer, availableCharsForMantissaWithSign, Integer((int64_t)mantissa), decimalMarkerPosition); if (displayMode == Expression::FloatDisplayMode::Decimal || exponentInBase10 == 0) { buffer[availableCharsForMantissaWithSign] = 0; return availableCharsForMantissaWithSign; } // Print exponent - assert(availableCharsForMantissaWithSign < k_maxFloatBufferLength); + assert(availableCharsForMantissaWithSign < PrintFloat::k_maxFloatBufferLength); buffer[availableCharsForMantissaWithSign] = Ion::Charset::Exponent; - assert(numberOfCharExponent+availableCharsForMantissaWithSign+1 < k_maxFloatBufferLength); - PrintFloat::printBase10IntegerWithDecimalMarker(buffer+availableCharsForMantissaWithSign+1, numberOfCharExponent, exponentInBase10, -1); + assert(numberOfCharExponent+availableCharsForMantissaWithSign+1 < PrintFloat::k_maxFloatBufferLength); + PrintFloat::printBase10IntegerWithDecimalMarker(buffer+availableCharsForMantissaWithSign+1, numberOfCharExponent, Integer(exponentInBase10), -1); buffer[availableCharsForMantissaWithSign+1+numberOfCharExponent] = 0; return (availableCharsForMantissaWithSign+1+numberOfCharExponent); } template ExpressionLayout * Complex::createPolarLayout(Expression::FloatDisplayMode floatDisplayMode) const { - char bufferBase[k_maxFloatBufferLength+2]; + char bufferBase[PrintFloat::k_maxFloatBufferLength+2]; int numberOfCharInBase = 0; - char bufferSuperscript[k_maxFloatBufferLength+2]; + char bufferSuperscript[PrintFloat::k_maxFloatBufferLength+2]; int numberOfCharInSuperscript = 0; - if (std::isnan(r()) || std::isnan(th())) { - numberOfCharInBase = convertFloatToText(NAN, bufferBase, k_maxComplexBufferLength, k_numberOfSignificantDigits, floatDisplayMode); + if (std::isnan(r()) || (std::isnan(th()) && r() != 0)) { + numberOfCharInBase = convertFloatToText(NAN, bufferBase, PrintFloat::k_maxComplexBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode); return new StringLayout(bufferBase, numberOfCharInBase); } if (r() != 1 || th() == 0) { - numberOfCharInBase = convertFloatToText(r(), bufferBase, k_maxFloatBufferLength, k_numberOfSignificantDigits, floatDisplayMode); + numberOfCharInBase = convertFloatToText(r(), bufferBase, PrintFloat::k_maxFloatBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode); if (r() != 0 && th() != 0) { - bufferBase[numberOfCharInBase++] = '*'; + bufferBase[numberOfCharInBase++] = Ion::Charset::MiddleDot; } } if (r() != 0 && th() != 0) { @@ -458,8 +452,8 @@ ExpressionLayout * Complex::createPolarLayout(Expression::FloatDisplayMode fl } if (r() != 0 && th() != 0) { - numberOfCharInSuperscript = convertFloatToText(th(), bufferSuperscript, k_maxFloatBufferLength, k_numberOfSignificantDigits, floatDisplayMode); - bufferSuperscript[numberOfCharInSuperscript++] = '*'; + numberOfCharInSuperscript = convertFloatToText(th(), bufferSuperscript, PrintFloat::k_maxFloatBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode); + bufferSuperscript[numberOfCharInSuperscript++] = Ion::Charset::MiddleDot; bufferSuperscript[numberOfCharInSuperscript++] = Ion::Charset::IComplex; bufferSuperscript[numberOfCharInSuperscript] = 0; } @@ -471,17 +465,17 @@ ExpressionLayout * Complex::createPolarLayout(Expression::FloatDisplayMode fl template ExpressionLayout * Complex::createCartesianLayout(Expression::FloatDisplayMode floatDisplayMode) const { - char buffer[k_maxComplexBufferLength]; - int numberOfChars = convertComplexToText(buffer, k_maxComplexBufferLength, floatDisplayMode, Expression::ComplexFormat::Cartesian); + char buffer[PrintFloat::k_maxComplexBufferLength]; + int numberOfChars = convertComplexToText(buffer, PrintFloat::k_maxComplexBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode, Expression::ComplexFormat::Cartesian, Ion::Charset::MiddleDot); return new StringLayout(buffer, numberOfChars); } template class Complex; template class Complex; -template Complex* Complex::templatedEvaluate(Context&, Expression::AngleUnit) const; -template Complex* Complex::templatedEvaluate(Context&, Expression::AngleUnit) const; -template Complex* Complex::templatedEvaluate(Context&, Expression::AngleUnit) const; -template Complex* Complex::templatedEvaluate(Context&, Expression::AngleUnit) const; +template Complex* Complex::templatedApproximate(Context&, Expression::AngleUnit) const; +template Complex* Complex::templatedApproximate(Context&, Expression::AngleUnit) const; +template Complex* Complex::templatedApproximate(Context&, Expression::AngleUnit) const; +template Complex* Complex::templatedApproximate(Context&, Expression::AngleUnit) const; } diff --git a/poincare/src/confidence_interval.cpp b/poincare/src/confidence_interval.cpp index 3ffc36764..3aa587249 100644 --- a/poincare/src/confidence_interval.cpp +++ b/poincare/src/confidence_interval.cpp @@ -59,9 +59,9 @@ Expression * ConfidenceInterval::shallowReduce(Context& context, AngleUnit angle } template -Expression * ConfidenceInterval::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * fInput = operand(0)->evaluate(context, angleUnit); - Expression * nInput = operand(1)->evaluate(context, angleUnit); +Expression * ConfidenceInterval::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * fInput = operand(0)->approximate(context, angleUnit); + Expression * nInput = operand(1)->approximate(context, angleUnit); if (fInput->type() != Type::Complex || nInput->type() != Type::Complex) { return new Complex(Complex::Float(NAN)); } diff --git a/poincare/src/decimal.cpp b/poincare/src/decimal.cpp index e7ac92254..be25e8e2f 100644 --- a/poincare/src/decimal.cpp +++ b/poincare/src/decimal.cpp @@ -107,7 +107,7 @@ Expression * Decimal::clone() const { return new Decimal(m_mantissa, m_exponent); } -template Expression * Decimal::templatedEvaluate(Context& context, Expression::AngleUnit angleUnit) const { +template Expression * Decimal::templatedApproximate(Context& context, Expression::AngleUnit angleUnit) const { T m = m_mantissa.approximate(); int numberOfDigits = numberOfDigitsInMantissaWithoutSign(); return new Complex(Complex::Float(m*std::pow((T)10.0, (T)(m_exponent-numberOfDigits+1)))); @@ -169,8 +169,8 @@ int Decimal::writeTextInBuffer(char * buffer, int bufferSize) const { /* If mantissa is negative, m_mantissa.writeTextInBuffer is going to add an * unwanted '-' in place of the temp char. We store it to replace it back * after calling m_mantissa.writeTextInBuffer. */ - char tempChar; - int tempCharPosition; + char tempChar = 0; + int tempCharPosition = 0; if (m_mantissa.isNegative()) { currentChar--; tempChar = buffer[currentChar]; diff --git a/poincare/src/derivative.cpp b/poincare/src/derivative.cpp index cfea6e23e..cb5b8d75c 100644 --- a/poincare/src/derivative.cpp +++ b/poincare/src/derivative.cpp @@ -35,17 +35,17 @@ Expression * Derivative::shallowReduce(Context& context, AngleUnit angleUnit) { } template -Expression * Derivative::templatedEvaluate(Context& context, AngleUnit angleUnit) const { +Expression * Derivative::templatedApproximate(Context& context, AngleUnit angleUnit) const { static T min = sizeof(T) == sizeof(double) ? DBL_MIN : FLT_MIN; static T max = sizeof(T) == sizeof(double) ? DBL_MAX : FLT_MAX; VariableContext xContext = VariableContext('x', &context); Symbol xSymbol('x'); - Expression * xInput = operand(1)->evaluate(context, angleUnit); + Expression * xInput = operand(1)->approximate(context, angleUnit); T x = xInput->type() == Type::Complex ? static_cast *>(xInput)->toScalar() : NAN; delete xInput; Complex e = Complex::Float(x); xContext.setExpressionForSymbolName(&e, &xSymbol, xContext); - Expression * fInput = operand(0)->evaluate(xContext, angleUnit); + Expression * fInput = operand(0)->approximate(xContext, angleUnit); T functionValue = fInput->type() == Type::Complex ? static_cast *>(fInput)->toScalar() : NAN; delete fInput; @@ -123,12 +123,12 @@ T Derivative::growthRateAroundAbscissa(T x, T h, VariableContext xContext, An Symbol xSymbol('x'); Complex e = Complex::Float(x + h); xContext.setExpressionForSymbolName(&e, &xSymbol, xContext); - Expression * fInput = operand(0)->evaluate(xContext, angleUnit); + Expression * fInput = operand(0)->approximate(xContext, angleUnit); T expressionPlus = fInput->type() == Type::Complex ? static_cast *>(fInput)->toScalar() : NAN; delete fInput; e = Complex::Float(x-h); xContext.setExpressionForSymbolName(&e, &xSymbol, xContext); - fInput = operand(0)->evaluate(xContext, angleUnit); + fInput = operand(0)->approximate(xContext, angleUnit); T expressionMinus = fInput->type() == Type::Complex ? static_cast *>(fInput)->toScalar() : NAN; delete fInput; return (expressionPlus - expressionMinus)/(2*h); @@ -139,17 +139,17 @@ T Derivative::approximateDerivate2(T x, T h, VariableContext xContext, AngleU Symbol xSymbol('x'); Complex e = Complex::Float(x + h); xContext.setExpressionForSymbolName(&e, &xSymbol, xContext); - Expression * fInput = operand(0)->evaluate(xContext, angleUnit); + Expression * fInput = operand(0)->approximate(xContext, angleUnit); T expressionPlus = fInput->type() == Type::Complex ? static_cast *>(fInput)->toScalar() : NAN; delete fInput; e = Complex::Float(x); xContext.setExpressionForSymbolName(&e, &xSymbol, xContext); - fInput = operand(0)->evaluate(xContext, angleUnit); + fInput = operand(0)->approximate(xContext, angleUnit); T expression = fInput->type() == Type::Complex ? static_cast *>(fInput)->toScalar() : NAN; delete fInput; e = Complex::Float(x-h); xContext.setExpressionForSymbolName(&e, &xSymbol, xContext); - fInput = operand(0)->evaluate(xContext, angleUnit); + fInput = operand(0)->approximate(xContext, angleUnit); T expressionMinus = fInput->type() == Type::Complex ? static_cast *>(fInput)->toScalar() : NAN; delete fInput; return expressionPlus - 2.0*expression + expressionMinus; diff --git a/poincare/src/determinant.cpp b/poincare/src/determinant.cpp index cf19a054a..5f42249da 100644 --- a/poincare/src/determinant.cpp +++ b/poincare/src/determinant.cpp @@ -34,8 +34,8 @@ Expression * Determinant::shallowReduce(Context& context, AngleUnit angleUnit) { // TODO: handle this exactly in shallowReduce for small dimensions. template -Expression * Determinant::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * input = operand(0)->evaluate(context, angleUnit); +Expression * Determinant::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * input = operand(0)->approximate(context, angleUnit); Expression * result = nullptr; if (input->type() == Type::Complex) { result = input->clone(); diff --git a/poincare/src/division.cpp b/poincare/src/division.cpp index 8d03c7509..2badf3742 100644 --- a/poincare/src/division.cpp +++ b/poincare/src/division.cpp @@ -31,7 +31,7 @@ Expression * Division::shallowReduce(Context& context, AngleUnit angleUnit) { Power * p = new Power(operand(1), new Rational(-1), false); Multiplication * m = new Multiplication(operand(0), p, false); detachOperands(); - p->deepReduce(context, angleUnit); + p->shallowReduce(context, angleUnit); replaceWith(m, true); return m->shallowReduce(context, angleUnit); } diff --git a/poincare/src/division_quotient.cpp b/poincare/src/division_quotient.cpp index 938299b14..23032d0d4 100644 --- a/poincare/src/division_quotient.cpp +++ b/poincare/src/division_quotient.cpp @@ -58,9 +58,9 @@ Expression * DivisionQuotient::shallowReduce(Context& context, AngleUnit angleUn } template -Complex * DivisionQuotient::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * f1Input = operand(0)->evaluate(context, angleUnit); - Expression * f2Input = operand(1)->evaluate(context, angleUnit); +Complex * DivisionQuotient::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * f1Input = operand(0)->approximate(context, angleUnit); + Expression * f2Input = operand(1)->approximate(context, angleUnit); T f1 = f1Input->type() == Type::Complex ? static_cast *>(f1Input)->toScalar() : NAN; T f2 = f2Input->type() == Type::Complex ? static_cast *>(f2Input)->toScalar() : NAN; delete f1Input; diff --git a/poincare/src/division_remainder.cpp b/poincare/src/division_remainder.cpp index ab631b010..bf6157b8a 100644 --- a/poincare/src/division_remainder.cpp +++ b/poincare/src/division_remainder.cpp @@ -58,9 +58,9 @@ Expression * DivisionRemainder::shallowReduce(Context& context, AngleUnit angleU } template -Complex * DivisionRemainder::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * f1Input = operand(0)->evaluate(context, angleUnit); - Expression * f2Input = operand(1)->evaluate(context, angleUnit); +Complex * DivisionRemainder::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * f1Input = operand(0)->approximate(context, angleUnit); + Expression * f2Input = operand(1)->approximate(context, angleUnit); T f1 = f1Input->type() == Type::Complex ? static_cast *>(f1Input)->toScalar() : NAN; T f2 = f2Input->type() == Type::Complex ? static_cast *>(f2Input)->toScalar() : NAN; delete f1Input; diff --git a/poincare/src/dynamic_hierarchy.cpp b/poincare/src/dynamic_hierarchy.cpp index cb60ca350..3aa805d7c 100644 --- a/poincare/src/dynamic_hierarchy.cpp +++ b/poincare/src/dynamic_hierarchy.cpp @@ -7,14 +7,14 @@ extern "C" { namespace Poincare { DynamicHierarchy::DynamicHierarchy() : - Hierarchy(), + Expression(), m_operands(nullptr), m_numberOfOperands(0) { } DynamicHierarchy::DynamicHierarchy(const Expression * const * operands, int numberOfOperands, bool cloneOperands) : - Hierarchy(), + Expression(), m_numberOfOperands(numberOfOperands) { assert(operands != nullptr); @@ -102,7 +102,11 @@ void DynamicHierarchy::sortOperands(ExpressionOrder order) { for (int j = 0; j < numberOfOperands()-1; j++) { /* Warning: Matrix operations are not always commutative (ie, * multiplication) so we never swap 2 matrices. */ +#if MATRIX_EXACT_REDUCING if (order(operand(j), operand(j+1)) > 0 && (!operand(j)->recursivelyMatches(Expression::IsMatrix) || !operand(j+1)->recursivelyMatches(Expression::IsMatrix))) { +#else + if (order(operand(j), operand(j+1)) > 0) { +#endif swapOperands(j, j+1); isSorted = false; } diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 06e605079..4e8e4f4e0 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -40,6 +40,13 @@ Expression * Expression::parse(char const * string) { return expression; } +const Expression * const * Expression::ExpressionArray(const Expression * e1, const Expression * e2) { + static const Expression * result[2] = {nullptr, nullptr}; + result[0] = e1; + result[1] = e2; + return result; +} + /* Circuit breaker */ static Expression::CircuitBreaker sCircuitBreaker = nullptr; @@ -57,6 +64,76 @@ bool Expression::shouldStopProcessing() { /* Hierarchy */ +const Expression * Expression::operand(int i) const { + assert(i >= 0); + assert(i < numberOfOperands()); + assert(operands()[i]->parent() == nullptr || operands()[i]->parent() == this); + return operands()[i]; +} + +Expression * Expression::replaceWith(Expression * newOperand, bool deleteAfterReplace) { + assert(m_parent != nullptr); + m_parent->replaceOperand(this, newOperand, deleteAfterReplace); + return newOperand; +} + +void Expression::replaceOperand(const Expression * oldOperand, Expression * newOperand, bool deleteOldOperand) { + assert(newOperand != nullptr); + // Caution: handle the case where we replace an operand with a descendant of ours. + if (newOperand->hasAncestor(this)) { + newOperand->parent()->detachOperand(newOperand); + } + Expression ** op = const_cast(operands()); + for (int i=0; iparent() == this) { + const_cast(oldOperand)->setParent(nullptr); + } + if (deleteOldOperand) { + delete oldOperand; + } + if (newOperand != nullptr) { + const_cast(newOperand)->setParent(this); + } + op[i] = newOperand; + break; + } + } +} + +void Expression::detachOperand(const Expression * e) { + Expression ** op = const_cast(operands()); + for (int i=0; i(operands()); + // When detachOperands is called, it's very likely that said operands have been stolen + if (op[i] != nullptr && op[i]->parent() == this) { + const_cast(op[i])->setParent(nullptr); + } + op[i] = nullptr; +} + +void Expression::swapOperands(int i, int j) { + assert(i >= 0 && i < numberOfOperands()); + assert(j >= 0 && j < numberOfOperands()); + Expression ** op = const_cast(operands()); + Expression * temp = op[i]; + op[i] = op[j]; + op[j] = temp; +} + bool Expression::hasAncestor(const Expression * e) const { assert(m_parent != this); if (m_parent == e) { @@ -68,12 +145,6 @@ bool Expression::hasAncestor(const Expression * e) const { return m_parent->hasAncestor(e); } -Expression * Expression::replaceWith(Expression * newOperand, bool deleteAfterReplace) { - assert(m_parent != nullptr); - m_parent->replaceOperand(this, newOperand, deleteAfterReplace); - return newOperand; -} - /* Properties */ bool Expression::recursivelyMatches(ExpressionTest test) const { @@ -89,7 +160,7 @@ bool Expression::recursivelyMatches(ExpressionTest test) const { } bool Expression::IsMatrix(const Expression * e) { - return e->type() == Type::Matrix || e->type() == Type::ConfidenceInterval || e->type() == Type::MatrixDimension || e->type() == Type::PredictionInterval || e->type() == Type::MatrixInverse || e->type() == Type::MatrixTranspose; + return e->type() == Type::Matrix || e->type() == Type::ConfidenceInterval || e->type() == Type::MatrixDimension || e->type() == Type::PredictionInterval || e->type() == Type::MatrixInverse || e->type() == Type::MatrixTranspose || (e->type() == Type::Symbol && static_cast(e)->isMatrixSymbol()); } /* Comparison */ @@ -97,9 +168,15 @@ bool Expression::IsMatrix(const Expression * e) { int Expression::SimplificationOrder(const Expression * e1, const Expression * e2) { if (e1->type() > e2->type()) { return -(e2->simplificationOrderGreaterType(e1)); + if (shouldStopProcessing()) { + return 1; + } } else if (e1->type() == e2->type()) { return e1->simplificationOrderSameType(e2); } else { + if (shouldStopProcessing()) { + return -1; + } return e1->simplificationOrderGreaterType(e2); } } @@ -182,17 +259,17 @@ Expression * Expression::deepBeautify(Context & context, AngleUnit angleUnit) { /* Evaluation */ -template Expression * Expression::evaluate(Context& context, AngleUnit angleUnit) const { +template Expression * Expression::approximate(Context& context, AngleUnit angleUnit) const { switch (angleUnit) { case AngleUnit::Default: - return privateEvaluate(T(), context, Preferences::sharedPreferences()->angleUnit()); + return privateApproximate(T(), context, Preferences::sharedPreferences()->angleUnit()); default: - return privateEvaluate(T(), context, angleUnit); + return privateApproximate(T(), context, angleUnit); } } -template T Expression::approximate(Context& context, AngleUnit angleUnit) const { - Expression * evaluation = evaluate(context, angleUnit); +template T Expression::approximateToScalar(Context& context, AngleUnit angleUnit) const { + Expression * evaluation = approximate(context, angleUnit); assert(evaluation->type() == Type::Complex || evaluation->type() == Type::Matrix); T result = NAN; if (evaluation->type() == Type::Complex) { @@ -207,9 +284,10 @@ template T Expression::approximate(Context& context, AngleUnit angle return result; } -template T Expression::approximate(const char * text, Context& context, AngleUnit angleUnit) { +template T Expression::approximateToScalar(const char * text, Context& context, AngleUnit angleUnit) { Expression * exp = parse(text); - T result = exp->approximate(context, angleUnit); + Simplify(&exp, context, angleUnit); + T result = exp->approximateToScalar(context, angleUnit); delete exp; return result; } @@ -221,11 +299,11 @@ template T Expression::epsilon() { } -template Poincare::Expression * Poincare::Expression::evaluate(Context& context, AngleUnit angleUnit) const; -template Poincare::Expression * Poincare::Expression::evaluate(Context& context, AngleUnit angleUnit) const; -template double Poincare::Expression::approximate(char const*, Poincare::Context&, Poincare::Expression::AngleUnit); -template float Poincare::Expression::approximate(char const*, Poincare::Context&, Poincare::Expression::AngleUnit); -template double Poincare::Expression::approximate(Poincare::Context&, Poincare::Expression::AngleUnit) const; -template float Poincare::Expression::approximate(Poincare::Context&, Poincare::Expression::AngleUnit) const; +template Poincare::Expression * Poincare::Expression::approximate(Context& context, AngleUnit angleUnit) const; +template Poincare::Expression * Poincare::Expression::approximate(Context& context, AngleUnit angleUnit) const; +template double Poincare::Expression::approximateToScalar(char const*, Poincare::Context&, Poincare::Expression::AngleUnit); +template float Poincare::Expression::approximateToScalar(char const*, Poincare::Context&, Poincare::Expression::AngleUnit); +template double Poincare::Expression::approximateToScalar(Poincare::Context&, Poincare::Expression::AngleUnit) const; +template float Poincare::Expression::approximateToScalar(Poincare::Context&, Poincare::Expression::AngleUnit) const; template double Poincare::Expression::epsilon(); template float Poincare::Expression::epsilon(); diff --git a/poincare/src/expression_debug.cpp b/poincare/src/expression_debug.cpp index 527317f2f..910aa94cd 100644 --- a/poincare/src/expression_debug.cpp +++ b/poincare/src/expression_debug.cpp @@ -60,7 +60,7 @@ void print_expression(const Expression * e, int indentationLevel) { break; case Expression::Type::Decimal: std::cout << "Decimal("; - std::cout << e->approximate(context, Expression::AngleUnit::Radian); + std::cout << e->approximateToScalar(context, Expression::AngleUnit::Radian); std::cout << ")"; break; case Expression::Type::Derivative: @@ -235,7 +235,7 @@ void print_prime_factorization(Integer * outputFactors, Integer * outputCoeffici std::cout << outputFactors[index].approximate(); std::cout << "^"; std::cout << outputCoefficients[index].approximate(); - std::cout << "+"; + std::cout << "*"; } std::cout <<" "<< std::endl; } diff --git a/poincare/src/expression_parser.y b/poincare/src/expression_parser.y index 4c989fa9c..8218558e7 100644 --- a/poincare/src/expression_parser.y +++ b/poincare/src/expression_parser.y @@ -144,7 +144,7 @@ lstData: /* MATRICES_ARE_DEFINED */ mtxData: LEFT_BRACKET lstData RIGHT_BRACKET { $$ = new Poincare::MatrixData($2, false); $2->detachOperands(); delete $2; } - | mtxData LEFT_BRACKET lstData RIGHT_BRACKET { $$ = $1; $$->pushListData($3, false); $3->detachOperands(); delete $3; } + | mtxData LEFT_BRACKET lstData RIGHT_BRACKET { if ($3->numberOfOperands() != $1->numberOfColumns()) { delete $1; delete $3; YYERROR; } ; $$ = $1; $$->pushListData($3, false); $3->detachOperands(); delete $3; } number: DIGITS { $$ = new Poincare::Rational(Poincare::Integer($1.address, false)); } diff --git a/poincare/src/factorial.cpp b/poincare/src/factorial.cpp index b751e361b..097802b33 100644 --- a/poincare/src/factorial.cpp +++ b/poincare/src/factorial.cpp @@ -82,13 +82,6 @@ ExpressionLayout * Factorial::privateCreateLayout(FloatDisplayMode floatDisplayM return new HorizontalLayout(childrenLayouts, 2); } -int Factorial::simplificationOrderGreaterType(const Expression * e) const { - if (SimplificationOrder(operand(0),e) == 0) { - return 1; - } - return SimplificationOrder(operand(0), e); -} - int Factorial::writeTextInBuffer(char * buffer, int bufferSize) const { if (bufferSize == 0) { return -1; @@ -103,8 +96,17 @@ int Factorial::writeTextInBuffer(char * buffer, int bufferSize) const { return numberOfChar; } +#if 0 +int Factorial::simplificationOrderGreaterType(const Expression * e) const { + if (SimplificationOrder(operand(0),e) == 0) { + return 1; + } + return SimplificationOrder(operand(0), e); +} + int Factorial::simplificationOrderSameType(const Expression * e) const { return SimplificationOrder(operand(0), e->operand(0)); } +#endif } diff --git a/poincare/src/global_context.cpp b/poincare/src/global_context.cpp index 4400804e9..fcecae12c 100644 --- a/poincare/src/global_context.cpp +++ b/poincare/src/global_context.cpp @@ -45,8 +45,13 @@ Complex * GlobalContext::defaultExpression() { } int GlobalContext::symbolIndex(const Symbol * symbol) const { - int index = symbol->name() - 'A'; - return index; + if (symbol->isMatrixSymbol()) { + return symbol->name() - (char)Symbol::SpecialSymbols::M0; + } + if (symbol->isScalarSymbol()) { + return symbol->name() - 'A'; + } + return -1; } const Expression * GlobalContext::expressionForSymbol(const Symbol * symbol) { @@ -59,11 +64,10 @@ const Expression * GlobalContext::expressionForSymbol(const Symbol * symbol) { if (symbol->name() == Ion::Charset::IComplex) { return &m_i; } - if (symbol->isMatrixSymbol()) { - int indexMatrix = symbol->name() - (char)Symbol::SpecialSymbols::M0; - return m_matrixExpressions[indexMatrix]; - } int index = symbolIndex(symbol); + if (symbol->isMatrixSymbol()) { + return m_matrixExpressions[index]; + } if (index < 0 || index >= k_maxNumberOfScalarExpressions) { return nullptr; } @@ -74,15 +78,16 @@ const Expression * GlobalContext::expressionForSymbol(const Symbol * symbol) { } void GlobalContext::setExpressionForSymbolName(const Expression * expression, const Symbol * symbol, Context & context) { - if (symbol->isMatrixSymbol()) { + int index = symbolIndex(symbol); + if (symbol->isMatrixSymbol()) { int indexMatrix = symbol->name() - (char)Symbol::SpecialSymbols::M0; assert(indexMatrix >= 0 && indexMatrix < k_maxNumberOfMatrixExpressions); + Expression * evaluation = expression ? expression->approximate(context) : nullptr; // evaluate before deleting anything (to be able to evaluate M1+2->M1) if (m_matrixExpressions[indexMatrix] != nullptr) { delete m_matrixExpressions[indexMatrix]; m_matrixExpressions[indexMatrix] = nullptr; } - if (expression != nullptr) { - Expression * evaluation = expression->evaluate(context); + if (evaluation != nullptr) { if (evaluation->type() == Expression::Type::Complex) { m_matrixExpressions[indexMatrix] = new Matrix(&evaluation, 1, 1, false); } else { @@ -91,18 +96,17 @@ void GlobalContext::setExpressionForSymbolName(const Expression * expression, co } return; } - int index = symbolIndex(symbol); if (index < 0 || index >= k_maxNumberOfScalarExpressions) { return; } + Expression * evaluation = expression ? expression->approximate(context) : nullptr; // evaluate before deleting anything (to be able to evaluate A+2->A) if (m_expressions[index] != nullptr) { delete m_expressions[index]; m_expressions[index] = nullptr; } - if (expression == nullptr) { + if (evaluation == nullptr) { return; } - Expression * evaluation = expression->evaluate(context); if (evaluation->type() == Expression::Type::Complex) { m_expressions[index] = static_cast *>(evaluation); } else { diff --git a/poincare/src/great_common_divisor.cpp b/poincare/src/great_common_divisor.cpp index 53494e623..6cd10604c 100644 --- a/poincare/src/great_common_divisor.cpp +++ b/poincare/src/great_common_divisor.cpp @@ -57,9 +57,9 @@ Expression * GreatCommonDivisor::shallowReduce(Context& context, AngleUnit angle } template -Complex * GreatCommonDivisor::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * f1Input = operand(0)->evaluate(context, angleUnit); - Expression * f2Input = operand(1)->evaluate(context, angleUnit); +Complex * GreatCommonDivisor::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * f1Input = operand(0)->approximate(context, angleUnit); + Expression * f2Input = operand(1)->approximate(context, angleUnit); T f1 = f1Input->type() == Type::Complex ? static_cast *>(f1Input)->toScalar() : NAN; T f2 = f2Input->type() == Type::Complex ? static_cast *>(f2Input)->toScalar() : NAN; delete f1Input; diff --git a/poincare/src/hierarchy.cpp b/poincare/src/hierarchy.cpp deleted file mode 100644 index a0adebaa6..000000000 --- a/poincare/src/hierarchy.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include -extern "C" { -#include -} - -namespace Poincare { - -const Expression * Hierarchy::operand(int i) const { - assert(i >= 0); - assert(i < numberOfOperands()); - assert(operands()[i]->parent() == nullptr || operands()[i]->parent() == this); - return operands()[i]; -} - -void Hierarchy::swapOperands(int i, int j) { - assert(i >= 0 && i < numberOfOperands()); - assert(j >= 0 && j < numberOfOperands()); - Expression ** op = const_cast(operands()); - Expression * temp = op[i]; - op[i] = op[j]; - op[j] = temp; -} - -void Hierarchy::detachOperand(const Expression * e) { - Expression ** op = const_cast(operands()); - for (int i=0; ihasAncestor(this)) { - static_cast(newOperand->parent())->detachOperand(newOperand); - } - Expression ** op = const_cast(operands()); - for (int i=0; iparent() == this) { - const_cast(oldOperand)->setParent(nullptr); - } - if (deleteOldOperand) { - delete oldOperand; - } - if (newOperand != nullptr) { - const_cast(newOperand)->setParent(this); - } - op[i] = newOperand; - break; - } - } -} - -const Expression * const * Hierarchy::ExpressionArray(const Expression * e1, const Expression * e2) { - static const Expression * result[2] = {nullptr, nullptr}; - result[0] = e1; - result[1] = e2; - return result; -} - -void Hierarchy::detachOperandAtIndex(int i) { - Expression ** op = const_cast(operands()); - // When detachOperands is called, it's very likely that said operands have been stolen - if (op[i] != nullptr && op[i]->parent() == this) { - const_cast(op[i])->setParent(nullptr); - } - op[i] = nullptr; -} - -} diff --git a/poincare/src/integer.cpp b/poincare/src/integer.cpp index 8a49f1dab..1c17bf2c3 100644 --- a/poincare/src/integer.cpp +++ b/poincare/src/integer.cpp @@ -34,17 +34,22 @@ static inline int8_t sign(bool negative) { // Constructors +static_assert(sizeof(Integer::double_native_int_t) == 2*sizeof(Integer::native_int_t), "double_native_int_t type has not the right size compared to native_int_t"); +static_assert(sizeof(Integer::native_int_t) == sizeof(Integer::native_uint_t), "native_int_t type has not the right size compared to native_uint_t"); + Integer::Integer(double_native_int_t i) { double_native_uint_t j = i < 0 ? -i : i; - if (j <= 0xFFFFFFFF) { - m_digit = j; - m_numberOfDigits = 1; + native_uint_t * digits = (native_uint_t *)&j; + native_uint_t leastSignificantDigit = *digits; + native_uint_t mostSignificantDigit = *(digits+1); + m_numberOfDigits = (mostSignificantDigit == 0) ? 1 : 2; + if (m_numberOfDigits == 1) { + m_digit = leastSignificantDigit; } else { native_uint_t * digits = new native_uint_t [2]; - digits[0] = j & 0xFFFFFFFF; - digits[1] = (j >> 32) & 0xFFFFFFFF; + digits[0] = leastSignificantDigit; + digits[1] = mostSignificantDigit; m_digits = digits; - m_numberOfDigits = 2; } m_negative = i < 0; } @@ -468,6 +473,15 @@ IntegerDivision Integer::udiv(const Integer & numerator, const Integer & denomin template T Integer::approximate() const { + if (isZero()) { + /* This special case for 0 is needed, because the current algorithm assumes + * that the big integer is non zero, thus puts the exponent to 126 (integer + * area), the issue is that when the mantissa is 0, a "shadow bit" is + * assumed to be there, thus 126 0x000000 is equal to 0.5 and not zero. + */ + T result = m_negative ? -0.0 : 0.0; + return result; + } union { uint64_t uint_result; T float_result; @@ -507,29 +521,37 @@ T Integer::approximate() const { exponent += numberOfBitsInLastDigit; uint64_t mantissa = 0; + /* Shift the most significant int to the left of the mantissa. The most + * significant 1 will be ignore at the end when inserting the mantissa in + * the resulting uint64_t (as required by IEEE754). */ + assert(totalNumberOfBits-numberOfBitsInLastDigit > 0 && totalNumberOfBits-numberOfBitsInLastDigit < 64); // Shift operator behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand mantissa |= ((uint64_t)lastDigit << (totalNumberOfBits-numberOfBitsInLastDigit)); int digitIndex = 2; - int numberOfBits = log2(lastDigit); + int numberOfBits = numberOfBitsInLastDigit; + /* Complete the mantissa by inserting, from left to right, every digit of the + * Integer from the most significant one to the last from. We break when + * the mantissa is complete to avoid undefined right shifting (Shift operator + * behavior is undefined if the right operand is negative, or greater than or + * equal to the length in bits of the promoted left operand). */ while (m_numberOfDigits >= digitIndex) { lastDigit = digit(m_numberOfDigits-digitIndex); numberOfBits += 32; + if (numberOfBits-totalNumberOfBits >= 64) { + break; + } if (totalNumberOfBits > numberOfBits) { + assert(totalNumberOfBits-numberOfBits > 0 && totalNumberOfBits-numberOfBits < 64); mantissa |= ((uint64_t)lastDigit << (totalNumberOfBits-numberOfBits)); } else { mantissa |= ((uint64_t)lastDigit >> (numberOfBits-totalNumberOfBits)); } digitIndex++; } - - if (isZero()) { - /* This special case for 0 is needed, because the current algorithm assumes - * that the big integer is non zero, thus puts the exponent to 126 (integer - * area), the issue is that when the mantissa is 0, a "shadow bit" is - * assumed to be there, thus 126 0x000000 is equal to 0.5 and not zero. - */ - T result = m_negative ? -0.0 : 0.0; - return result; - } + // TODO: Here, we just cast the Integer in float(double). We should round it + // to the closest float(double). To do so, we should keep a additional bit + // at the end of the mantissa and add it to the mantissa; do not forget to + // shift the mantissa if the rounding increase the length in bits of the + // mantissa. u.uint_result = 0; u.uint_result |= ((uint64_t)sign << (totalNumberOfBits-1)); @@ -550,13 +572,12 @@ int Integer::writeTextInBuffer(char * buffer, int bufferSize) const { return -1; } buffer[bufferSize-1] = 0; - /* If the integer is too long, this method may overflow the stack. + /* If the integer is too long, this method may be too slow. * Experimentally, we can display at most integer whose number of digits is - * around 7. However, to avoid crashing when the stack is already half full, - * we decide not to display integers whose number of digits > 5. */ - /*if (m_numberOfDigits > 12) { + * around 25. */ + if (m_numberOfDigits > 25) { return strlcpy(buffer, "inf", 4); - }*/ + } Integer base = Integer(10); Integer abs = *this; @@ -583,8 +604,7 @@ int Integer::writeTextInBuffer(char * buffer, int bufferSize) const { buffer[size] = 0; // Flip the string - int startChar = isNegative() ? 1 : 0; - for (int i=startChar, j=size-1 ; i < j ; i++, j--) { + for (int i=m_negative, j=size-1 ; i < j ; i++, j--) { char c = buffer[i]; buffer[i] = buffer[j]; buffer[j] = c; diff --git a/poincare/src/integral.cpp b/poincare/src/integral.cpp index 9d02e67ef..8fb5ad914 100644 --- a/poincare/src/integral.cpp +++ b/poincare/src/integral.cpp @@ -37,12 +37,12 @@ Expression * Integral::shallowReduce(Context& context, AngleUnit angleUnit) { } template -Complex * Integral::templatedEvaluate(Context & context, AngleUnit angleUnit) const { +Complex * Integral::templatedApproximate(Context & context, AngleUnit angleUnit) const { VariableContext xContext = VariableContext('x', &context); - Expression * aInput = operand(1)->evaluate(context, angleUnit); + Expression * aInput = operand(1)->approximate(context, angleUnit); T a = aInput->type() == Type::Complex ? static_cast *>(aInput)->toScalar() : NAN; delete aInput; - Expression * bInput = operand(2)->evaluate(context, angleUnit); + Expression * bInput = operand(2)->approximate(context, angleUnit); T b = bInput->type() == Type::Complex ? static_cast *>(bInput)->toScalar() : NAN; delete bInput; if (std::isnan(a) || std::isnan(b)) { @@ -70,7 +70,7 @@ T Integral::functionValueAtAbscissa(T x, VariableContext xContext, AngleUnit Complex e = Complex::Float(x); Symbol xSymbol('x'); xContext.setExpressionForSymbolName(&e, &xSymbol, xContext); - Expression * f = operand(0)->evaluate(xContext, angleUnit); + Expression * f = operand(0)->approximate(xContext, angleUnit); T result = f->type() == Type::Complex ? static_cast *>(f)->toScalar() : NAN; delete f; return result; @@ -174,6 +174,9 @@ Integral::DetailedResult Integral::kronrodGaussQuadrature(T a, T b, VariableC template T Integral::adaptiveQuadrature(T a, T b, T eps, int numberOfIterations, VariableContext xContext, AngleUnit angleUnit) const { + if (shouldStopProcessing()) { + return NAN; + } DetailedResult quadKG = kronrodGaussQuadrature(a, b, xContext, angleUnit); T result = quadKG.integral; if (quadKG.absoluteError <= eps) { diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 44b77435e..e71a263db 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -9,8 +9,7 @@ ExpressionLayout(), m_numerator_layout(numerator_layout), m_denominator_layout(d m_numerator_layout->setParent(this); m_denominator_layout->setParent(this); m_baseline = m_numerator_layout->size().height() - + k_fractionLineMargin + k_fractionLineHeight - + KDText::charSize().height()/2; + + k_fractionLineMargin + k_fractionLineHeight; } FractionLayout::~FractionLayout() { diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index b40f7adc5..495e4e9c7 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -16,7 +16,7 @@ GridLayout::GridLayout(ExpressionLayout ** entryLayouts, int numberOfRows, int n m_entryLayouts[i] = entryLayouts[i]; m_entryLayouts[i]->setParent(this); } - m_baseline = height()/2 + KDText::charSize().height()/2; + m_baseline = (height()+1)/2; } GridLayout::~GridLayout() { diff --git a/poincare/src/layout/product_layout.cpp b/poincare/src/layout/product_layout.cpp index 4699da3c5..cb573cf4b 100644 --- a/poincare/src/layout/product_layout.cpp +++ b/poincare/src/layout/product_layout.cpp @@ -8,13 +8,13 @@ void ProductLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDSize upperBoundSize = m_upperBoundLayout->size(); KDSize lowerBoundSize = m_lowerBoundLayout->size(); ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2), - p.y() + max(upperBoundSize.height()+k_boundHeightMargin, m_argumentLayout->baseline()-k_symbolHeight), + p.y() + max(upperBoundSize.height()+k_boundHeightMargin, m_argumentLayout->baseline()-(k_symbolHeight+1)/2), k_lineThickness, k_symbolHeight), expressionColor); ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2), - p.y() + max(upperBoundSize.height()+k_boundHeightMargin, m_argumentLayout->baseline()-k_symbolHeight), + p.y() + max(upperBoundSize.height()+k_boundHeightMargin, m_argumentLayout->baseline()-(k_symbolHeight+1)/2), k_symbolWidth, k_lineThickness), expressionColor); ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2)+k_symbolWidth, - p.y() + max(upperBoundSize.height()+k_boundHeightMargin, m_argumentLayout->baseline()-k_symbolHeight), + p.y() + max(upperBoundSize.height()+k_boundHeightMargin, m_argumentLayout->baseline()-(k_symbolHeight+1)/2), k_lineThickness, k_symbolHeight), expressionColor); } diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 927d0ee08..52ed5dc95 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -13,7 +13,7 @@ SequenceLayout::SequenceLayout(ExpressionLayout * lowerBoundLayout, ExpressionLa m_lowerBoundLayout->setParent(this); m_upperBoundLayout->setParent(this); m_argumentLayout->setParent(this); - m_baseline = max(m_upperBoundLayout->size().height()+k_boundHeightMargin+k_symbolHeight, m_argumentLayout->baseline()); + m_baseline = max(m_upperBoundLayout->size().height()+k_boundHeightMargin+(k_symbolHeight+1)/2, m_argumentLayout->baseline()); } SequenceLayout::~SequenceLayout() { @@ -28,7 +28,7 @@ KDSize SequenceLayout::computeSize() { KDSize upperBoundSize = m_upperBoundLayout->size(); return KDSize( max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin+argumentSize.width(), - m_baseline + max(k_boundHeightMargin+lowerBoundSize.height(), argumentSize.height() - m_argumentLayout->baseline()) + m_baseline + max(k_symbolHeight/2+k_boundHeightMargin+lowerBoundSize.height(), argumentSize.height() - m_argumentLayout->baseline()) ); } @@ -52,10 +52,10 @@ KDPoint SequenceLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate y = 0; if (child == m_lowerBoundLayout) { x = max(max(0, (k_symbolWidth-lowerBoundSize.width())/2), (upperBoundSize.width()-lowerBoundSize.width())/2); - y = m_baseline + k_boundHeightMargin; + y = m_baseline + k_symbolHeight/2 + k_boundHeightMargin; } else if (child == m_upperBoundLayout) { x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (lowerBoundSize.width()-upperBoundSize.width())/2); - y = m_baseline - k_symbolHeight- k_boundHeightMargin-upperBoundSize.height(); + y = m_baseline - (k_symbolHeight+1)/2- k_boundHeightMargin-upperBoundSize.height(); } else if (child == m_argumentLayout) { x = max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin; y = m_baseline - m_argumentLayout->baseline(); diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index 4cb1de862..62bbbb68c 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -11,8 +11,8 @@ StringLayout::StringLayout(const char * string, size_t length, KDText::FontSize m_string = new char[length+1]; memcpy(m_string, string, length); m_string[length] = 0; - // Height of the font. - m_baseline = KDText::charSize(m_fontSize).height(); + // Half height of the font. + m_baseline = (KDText::charSize(m_fontSize).height()+1)/2; } StringLayout::~StringLayout() { diff --git a/poincare/src/layout/sum_layout.cpp b/poincare/src/layout/sum_layout.cpp index 17bb0a995..95c376bee 100644 --- a/poincare/src/layout/sum_layout.cpp +++ b/poincare/src/layout/sum_layout.cpp @@ -27,7 +27,7 @@ void SumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDCo KDSize lowerBoundSize = m_lowerBoundLayout->size(); KDColor workingBuffer[k_symbolWidth*k_symbolHeight]; KDRect symbolFrame(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2), - p.y() + max(upperBoundSize.height()+k_boundHeightMargin, m_argumentLayout->baseline()-k_symbolHeight), + p.y() + max(upperBoundSize.height()+k_boundHeightMargin, m_argumentLayout->baseline()-(k_symbolHeight+1)/2), k_symbolWidth, k_symbolHeight); ctx->blendRectWithMask(symbolFrame, expressionColor, (const uint8_t *)symbolPixel, (KDColor *)workingBuffer); } diff --git a/poincare/src/least_common_multiple.cpp b/poincare/src/least_common_multiple.cpp index f55d410dd..71f048e6d 100644 --- a/poincare/src/least_common_multiple.cpp +++ b/poincare/src/least_common_multiple.cpp @@ -57,9 +57,9 @@ Expression * LeastCommonMultiple::shallowReduce(Context& context, AngleUnit angl } template -Complex * LeastCommonMultiple::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * f1Input = operand(0)->evaluate(context, angleUnit); - Expression * f2Input = operand(1)->evaluate(context, angleUnit); +Complex * LeastCommonMultiple::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * f1Input = operand(0)->approximate(context, angleUnit); + Expression * f2Input = operand(1)->approximate(context, angleUnit); T f1 = f1Input->type() == Type::Complex ? static_cast *>(f1Input)->toScalar() : NAN; T f2 = f2Input->type() == Type::Complex ? static_cast *>(f2Input)->toScalar() : NAN; delete f1Input; diff --git a/poincare/src/logarithm.cpp b/poincare/src/logarithm.cpp index b8ece9432..43cea1765 100644 --- a/poincare/src/logarithm.cpp +++ b/poincare/src/logarithm.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -149,9 +149,10 @@ Expression * Logarithm::splitInteger(Integer i, bool isDenominator, Context & co } assert(!i.isOne()); if (Arithmetic::k_primorial32.isLowerThan(i)) { - // We do not want to break i in prime factor because it might be take too many factors... More than k_maxNumberOfPrimeFactors. + /* We do not want to break i in prime factor because it might be take too + * many factors... More than k_maxNumberOfPrimeFactors. */ Expression * e = clone(); - e->replaceOperand(operand(0), new Rational(i), true); + e->replaceOperand(e->operand(0), new Rational(i), true); if (!isDenominator) { return e; } @@ -190,12 +191,12 @@ Expression * Logarithm::shallowBeautify(Context & context, AngleUnit angleUnit) } template -Expression * Logarithm::templatedEvaluate(Context& context, AngleUnit angleUnit) const { +Expression * Logarithm::templatedApproximate(Context& context, AngleUnit angleUnit) const { if (numberOfOperands() == 1) { - return EvaluationEngine::map(this, context, angleUnit, computeOnComplex); + return ApproximationEngine::map(this, context, angleUnit, computeOnComplex); } - Expression * x = operand(0)->evaluate(context, angleUnit); - Expression * n = operand(1)->evaluate(context, angleUnit); + Expression * x = operand(0)->approximate(context, angleUnit); + Expression * n = operand(1)->approximate(context, angleUnit); Complex result = Complex::Float(NAN); if (x->type() == Type::Complex && n->type() == Type::Complex) { Complex * xc = static_cast *>(x); diff --git a/poincare/src/matrix.cpp b/poincare/src/matrix.cpp index 8e23e7753..d9a67e939 100644 --- a/poincare/src/matrix.cpp +++ b/poincare/src/matrix.cpp @@ -312,10 +312,10 @@ Matrix * Matrix::createApproximateIdentity(int dim) { } template -Expression * Matrix::templatedEvaluate(Context& context, AngleUnit angleUnit) const { +Expression * Matrix::templatedApproximate(Context& context, AngleUnit angleUnit) const { Expression ** operands = new Expression * [numberOfOperands()]; for (int i = 0; i < numberOfOperands(); i++) { - Expression * operandEvaluation = operand(i)->evaluate(context, angleUnit); + Expression * operandEvaluation = operand(i)->approximate(context, angleUnit); if (operandEvaluation->type() != Type::Complex) { operands[i] = new Complex(Complex::Float(NAN)); delete operandEvaluation; diff --git a/poincare/src/matrix_data.cpp b/poincare/src/matrix_data.cpp index 8c1e31a3c..4ef93f708 100644 --- a/poincare/src/matrix_data.cpp +++ b/poincare/src/matrix_data.cpp @@ -23,10 +23,6 @@ MatrixData::MatrixData(ListData * listData, bool clone) : } } -Complex * MatrixData::defaultExpression() { - return new Complex(Complex::Float(0.0)); -} - MatrixData::~MatrixData() { if (m_operands != nullptr) { for (int i=0; inumberOfOperands() == m_numberOfColumns); for (int i = 0; i < m_numberOfRows*m_numberOfColumns; i++) { newOperands[i] = m_operands[i]; } for (int i = 0; i < m_numberOfColumns; i++) { - int max = listData->numberOfOperands(); if (clone) { - newOperands[m_numberOfRows*m_numberOfColumns+i] = i < max ? listData->operand(i)->clone() : defaultExpression(); + newOperands[m_numberOfRows*m_numberOfColumns+i] = listData->operand(i)->clone(); } else { - newOperands[m_numberOfRows*m_numberOfColumns+i] = i < max ? listData->operand(i) : defaultExpression(); + newOperands[m_numberOfRows*m_numberOfColumns+i] = listData->operand(i); } } delete[] m_operands; diff --git a/poincare/src/matrix_dimension.cpp b/poincare/src/matrix_dimension.cpp index 8bbb5fb74..f582f93cc 100644 --- a/poincare/src/matrix_dimension.cpp +++ b/poincare/src/matrix_dimension.cpp @@ -40,8 +40,8 @@ Expression * MatrixDimension::shallowReduce(Context& context, AngleUnit angleUni } template -Expression * MatrixDimension::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * input = operand(0)->evaluate(context, angleUnit); +Expression * MatrixDimension::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * input = operand(0)->approximate(context, angleUnit); Expression * operands[2]; if (input->type() == Type::Matrix) { operands[0] = new Complex(Complex::Float((T)static_cast(input)->numberOfRows())); diff --git a/poincare/src/matrix_inverse.cpp b/poincare/src/matrix_inverse.cpp index 1d5271be5..988604eb0 100644 --- a/poincare/src/matrix_inverse.cpp +++ b/poincare/src/matrix_inverse.cpp @@ -46,8 +46,8 @@ Expression * MatrixInverse::shallowReduce(Context& context, AngleUnit angleUnit) // TODO: handle this exactly in shallowReduce for small dimensions. template -Expression * MatrixInverse::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * input = operand(0)->evaluate(context, angleUnit); +Expression * MatrixInverse::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * input = operand(0)->approximate(context, angleUnit); Expression * result = nullptr; if (input->type() == Type::Complex) { Complex * c = static_cast *>(input); diff --git a/poincare/src/matrix_trace.cpp b/poincare/src/matrix_trace.cpp index 4ae4ebfab..0525b1590 100644 --- a/poincare/src/matrix_trace.cpp +++ b/poincare/src/matrix_trace.cpp @@ -49,8 +49,8 @@ Expression * MatrixTrace::shallowReduce(Context& context, AngleUnit angleUnit) { } template -Expression * MatrixTrace::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * input = operand(0)->evaluate(context, angleUnit); +Expression * MatrixTrace::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * input = operand(0)->approximate(context, angleUnit); Expression * result = nullptr; if (input->type() == Type::Complex) { result = input->clone(); diff --git a/poincare/src/matrix_transpose.cpp b/poincare/src/matrix_transpose.cpp index 59bb4ec3f..c6deb029d 100644 --- a/poincare/src/matrix_transpose.cpp +++ b/poincare/src/matrix_transpose.cpp @@ -39,8 +39,8 @@ Expression * MatrixTranspose::shallowReduce(Context& context, AngleUnit angleUni } template -Expression * MatrixTranspose::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * input = operand(0)->evaluate(context, angleUnit); +Expression * MatrixTranspose::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * input = operand(0)->approximate(context, angleUnit); Expression * result = nullptr; if (input->type() == Type::Complex) { result = input->clone(); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 5b6207f0f..69e2afa02 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -126,16 +126,7 @@ Expression * Multiplication::privateShallowReduce(Context & context, AngleUnit a } /* Step 1: Multiplication is associative, so let's start by merging children * which also are multiplications themselves. */ - int i = 0; - int initialNumberOfOperands = numberOfOperands(); - while (i < initialNumberOfOperands) { - Expression * o = editableOperand(i); - if (o->type() == Type::Multiplication) { - mergeOperands(static_cast(o)); // TODO: ensure that matrix operands are not swapped to implement MATRIX_EXACT_REDUCING - continue; - } - i++; - } + mergeMultiplicationOperands(); /* Step 2: If any of the operand is zero, the multiplication result is zero */ for (int i = 0; i < numberOfOperands(); i++) { @@ -225,23 +216,18 @@ Expression * Multiplication::privateShallowReduce(Context & context, AngleUnit a /* Step 4: Gather like terms. For example, turn pi^2*pi^3 into pi^5. Thanks to * the simplification order, such terms are guaranteed to be next to each * other. */ - i = 0; + int i = 0; while (i < numberOfOperands()-1) { Expression * oi = editableOperand(i); Expression * oi1 = editableOperand(i+1); - if (oi->type() == Type::Rational && oi1->type() == Type::Rational) { - Rational a = Rational::Multiplication(*(static_cast(oi)), *(static_cast(oi1))); - replaceOperand(oi, new Rational(a), true); - removeOperand(oi1, true); - continue; - } else if (TermsHaveIdenticalBase(oi, oi1)) { + if (TermsHaveIdenticalBase(oi, oi1)) { bool shouldFactorizeBase = true; if (TermHasRationalBase(oi)) { /* Combining powers of a given rational isn't straightforward. Indeed, * there are two cases we want to deal with: * - 2*2^(1/2) or 2*2^pi, we want to keep as-is * - 2^(1/2)*2^(3/2) we want to combine. */ - shouldFactorizeBase = !TermHasIntegerExponent(oi) && !TermHasIntegerExponent(oi1); + shouldFactorizeBase = oi->type() == Type::Power && oi1->type() == Type::Power; } if (shouldFactorizeBase) { factorizeBase(oi, oi1, context, angleUnit); @@ -268,6 +254,7 @@ Expression * Multiplication::privateShallowReduce(Context & context, AngleUnit a Expression * o2 = editableOperand(j); if (Base(o2)->type() == Type::Cosine && TermHasRationalExponent(o2) && Base(o2)->operand(0)->isIdenticalTo(x)) { factorizeSineAndCosine(o1, o2, context, angleUnit); + break; } } } @@ -277,30 +264,40 @@ Expression * Multiplication::privateShallowReduce(Context & context, AngleUnit a * shallowReduce */ sortOperands(SimplificationOrder); - /* Step 6: Let's remove ones if there's any. It's important to do this after - * having factorized because factorization can lead to new ones. For example - * pi^(-1)*pi. We don't remove the last one if it's the only operand left - * though. - * Same comment for -1 that can appear when reducing i*i. */ - i = 0; + /* Step 6: We remove rational operands that appeared in the middle of sorted + * operands. It's important to do this after having factorized because + * factorization can lead to new ones. Indeed: + * pi^(-1)*pi-> 1 + * i*i -> -1 + * 2^(1/2)*2^(1/2) -> 2 + * sin(x)*cos(x) -> 1*tan(x) + * Last, we remove the only rational operand if it is one and not the only + * operand. */ + i = 1; while (i < numberOfOperands()) { Expression * o = editableOperand(i); - if (o->type() == Type::Rational && static_cast(o)->isOne() && numberOfOperands() > 1) { + if (o->type() == Type::Rational && static_cast(o)->isOne()) { removeOperand(o, true); continue; } - if (o->type() == Type::Rational && static_cast(o)->isMinusOne() && numberOfOperands() > 1 && i > 0) { - removeOperand(o, operand(0)->type() == Type::Rational); + if (o->type() == Type::Rational) { if (operand(0)->type() == Type::Rational) { - Rational * r = static_cast(editableOperand(0)); - r->setSign(r->sign() == Sign::Positive ? Sign::Negative : Sign::Positive); + Rational * o0 = static_cast(editableOperand(0)); + Rational m = Rational::Multiplication(*o0, *(static_cast(o))); + replaceOperand(o0, new Rational(m), true); + removeOperand(o, true); } else { + removeOperand(o, false); addOperandAtIndex(o, 0); } continue; } i++; } + if (operand(0)->type() == Type::Rational && static_cast(editableOperand(0))->isOne() && numberOfOperands() > 1) { + removeOperand(editableOperand(0), true); + } + /* Step 7: Expand multiplication over addition operands if any. For example, * turn (a+b)*c into a*c + b*c. We do not want to do this step right now if @@ -322,6 +319,20 @@ Expression * Multiplication::privateShallowReduce(Context & context, AngleUnit a return result; } +void Multiplication::mergeMultiplicationOperands() { + // Multiplication is associative: a*(b*c)->a*b*c + int i = 0; + int initialNumberOfOperands = numberOfOperands(); + while (i < initialNumberOfOperands) { + Expression * o = editableOperand(i); + if (o->type() == Type::Multiplication) { + mergeOperands(static_cast(o)); // TODO: ensure that matrix operands are not swapped to implement MATRIX_EXACT_REDUCING + continue; + } + i++; + } +} + void Multiplication::factorizeSineAndCosine(Expression * o1, Expression * o2, Context & context, AngleUnit angleUnit) { assert(o1->parent() == this && o2->parent() == this); /* This function turn sin(x)^p * cos(x)^q into either: @@ -413,8 +424,7 @@ void Multiplication::factorizeExponent(Expression * e1, Expression * e2, Context const Expression * base1 = e1->operand(0)->clone(); const Expression * base2 = e2->operand(0); - // TODO: remove cast, everything is a hierarchy - static_cast(e2)->detachOperand(base2); + e2->detachOperand(base2); Expression * m = new Multiplication(base1, base2, false); removeOperand(e2, true); e1->replaceOperand(e1->operand(0), m, true); @@ -427,11 +437,12 @@ Expression * Multiplication::distributeOnOperandAtIndex(int i, Context & context // This function turns a*(b+c) into a*b + a*c // We avoid deleting and creating a new addition Addition * a = static_cast(editableOperand(i)); + removeOperand(a, false); for (int j = 0; j < a->numberOfOperands(); j++) { + Multiplication * m = static_cast(clone()); Expression * termJ = a->editableOperand(j); - replaceOperand(operand(i), termJ->clone(), false); - Expression * m = clone(); - a->replaceOperand(termJ, m, true); + a->replaceOperand(termJ, m, false); + m->addOperand(termJ); m->shallowReduce(context, angleUnit); // pi^(-1)*(pi + x) -> pi^(-1)*pi + pi^(-1)*x -> 1 + pi^(-1)*x } replaceWith(a, true); @@ -456,17 +467,6 @@ bool Multiplication::TermHasRationalBase(const Expression * e) { return Base(e)->type() == Type::Rational; } -bool Multiplication::TermHasIntegerExponent(const Expression * e) { - if (e->type() != Type::Power) { - return true; - } - if (e->operand(1)->type() == Type::Rational) { - const Rational * r = static_cast(e->operand(1)); - return r->denominator().isOne(); - } - return false; -} - bool Multiplication::TermHasRationalExponent(const Expression * e) { if (e->type() != Type::Power) { return true; @@ -628,13 +628,23 @@ void Multiplication::addMissingFactors(Expression * factor, Context & context, A Expression * sub = new Subtraction(CreateExponent(editableOperand(i)), CreateExponent(factor), false); Reduce((Expression **)&sub, context, angleUnit); if (sub->sign() == Sign::Negative) { // index[0] < index[1] - factor->replaceOperand(factor->editableOperand(1), new Opposite(sub, true), true); + if (factor->type() == Type::Power) { + factor->replaceOperand(factor->editableOperand(1), new Opposite(sub, true), true); + } else { + factor = new Power(factor, new Opposite(sub, true), false); + } + factor->editableOperand(1)->shallowReduce(context, angleUnit); factorizeBase(editableOperand(i), factor, context, angleUnit); editableOperand(i)->shallowReduce(context, angleUnit); } else if (sub->sign() == Sign::Unknown) { factorizeBase(editableOperand(i), factor, context, angleUnit); + editableOperand(i)->shallowReduce(context, angleUnit); } else {} delete sub; + /* Reducing the new operand i can lead to creating a new multiplication + * (ie 2^(1+2*3^(1/2)) -> 2*2^(2*3^(1/2)). We thus have to get rid of + * nested multiplication: */ + mergeMultiplicationOperands(); return; } } diff --git a/poincare/src/nth_root.cpp b/poincare/src/nth_root.cpp index 030dc13ff..e648818c0 100644 --- a/poincare/src/nth_root.cpp +++ b/poincare/src/nth_root.cpp @@ -54,9 +54,9 @@ Complex NthRoot::compute(const Complex c, const Complex d) { } template -Expression * NthRoot::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * base = operand(0)->evaluate(context, angleUnit); - Expression * index = operand(1)->evaluate(context, angleUnit); +Expression * NthRoot::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * base = operand(0)->approximate(context, angleUnit); + Expression * index = operand(1)->approximate(context, angleUnit); Complex result = Complex::Float(NAN); if (base->type() == Type::Complex && index->type() == Type::Complex) { Complex * basec = static_cast *>(base); diff --git a/poincare/src/parenthesis.cpp b/poincare/src/parenthesis.cpp index 9cc9c0829..e8a7985b6 100644 --- a/poincare/src/parenthesis.cpp +++ b/poincare/src/parenthesis.cpp @@ -32,8 +32,8 @@ Expression * Parenthesis::shallowReduce(Context& context, AngleUnit angleUnit) { } template -Expression * Parenthesis::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - return operand(0)->evaluate(context, angleUnit); +Expression * Parenthesis::templatedApproximate(Context& context, AngleUnit angleUnit) const { + return operand(0)->approximate(context, angleUnit); } } diff --git a/poincare/src/permute_coefficient.cpp b/poincare/src/permute_coefficient.cpp index f381173d4..4ecc692ef 100644 --- a/poincare/src/permute_coefficient.cpp +++ b/poincare/src/permute_coefficient.cpp @@ -68,9 +68,9 @@ Expression * PermuteCoefficient::shallowReduce(Context& context, AngleUnit angle } template -Complex * PermuteCoefficient::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * nInput = operand(0)->evaluate(context, angleUnit); - Expression * kInput = operand(1)->evaluate(context, angleUnit); +Complex * PermuteCoefficient::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * nInput = operand(0)->approximate(context, angleUnit); + Expression * kInput = operand(1)->approximate(context, angleUnit); if (nInput->type() != Type::Complex || kInput->type() != Type::Complex) { return new Complex(Complex::Float(NAN)); } diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index ecbae6c98..addb4f3f8 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -34,6 +34,9 @@ Expression * Power::clone() const { } Expression::Sign Power::sign() const { + if (shouldStopProcessing()) { + return Sign::Unknown; + } if (operand(0)->sign() == Sign::Positive && operand(1)->sign() != Sign::Unknown) { return Sign::Positive; } @@ -103,7 +106,9 @@ template Matrix * Power::computeOnMatrixAndComplex(const Matrix * m, delete result; return nullptr; } - result = Multiplication::computeOnMatrices(result, m); + Matrix * mult = Multiplication::computeOnMatrices(result, m); + delete result; + result = mult; } return result; } @@ -181,30 +186,39 @@ Expression * Power::shallowReduce(Context& context, AngleUnit angleUnit) { } #endif - /* Step 0: We look for square root and sum of square roots (two terms maximum - * so far) at the denominator and move them to the numerator. */ - Expression * r = removeSquareRootsFromDenominator(context, angleUnit); - if (r) { - return r; + /* Step 0: if both operands are true complexes, the result is undefined. + * We can assert that evaluations is a complex as matrix are not simplified */ + Complex * op0 = static_cast *>(operand(0)->approximate(context, angleUnit)); + Complex * op1 = static_cast *>(operand(1)->approximate(context, angleUnit)); + bool bothOperandsComplexes = op0->b() != 0 && op1->b() != 0; + delete op0; + delete op1; + if (bothOperandsComplexes) { + return replaceWith(new Undefined(), true); } + /* Step 1: We handle simple cases as x^0, x^1, 0^x and 1^x first for 2 reasons: + * - we can assert this step that there is no division by 0: + * for instance, 0^(-2)->undefined + * - we save computational time by early escaping for these cases. */ if (operand(1)->type() == Type::Rational) { const Rational * b = static_cast(operand(1)); // x^0 if (b->isZero()) { + // 0^0 = undef + if (operand(0)->type() == Type::Rational && static_cast(operand(0))->isZero()) { + return replaceWith(new Undefined(), true); + } + /* Warning: in all other case but 0^0, we replace x^0 by one. This is + * almost always true except when x = 0. However, not substituting x^0 by + * one would prevent from simplifying many expressions like x/x->1. */ return replaceWith(new Rational(1), true); } // x^1 if (b->isOne()) { return replaceWith(editableOperand(0), true); } - // i^(p/q) - if (operand(0)->type() == Type::Symbol && static_cast(operand(0))->name() == Ion::Charset::IComplex) { - Rational r = Rational::Multiplication(*b, Rational(1, 2)); - return replaceWith(CreateNthRootOfUnity(r))->shallowReduce(context, angleUnit); - } } - bool letPowerAtRoot = parentIsALogarithmOfSameBase(); if (operand(0)->type() == Type::Rational) { Rational * a = static_cast(editableOperand(0)); // 0^x @@ -220,15 +234,35 @@ Expression * Power::shallowReduce(Context& context, AngleUnit angleUnit) { if (a->isOne()) { return replaceWith(new Rational(1), true); } + } + + /* Step 2: We look for square root and sum of square roots (two terms maximum + * so far) at the denominator and move them to the numerator. */ + Expression * r = removeSquareRootsFromDenominator(context, angleUnit); + if (r) { + return r; + } + + if (operand(1)->type() == Type::Rational) { + const Rational * b = static_cast(operand(1)); + // i^(p/q) + if (operand(0)->type() == Type::Symbol && static_cast(operand(0))->name() == Ion::Charset::IComplex) { + Rational r = Rational::Multiplication(*b, Rational(1, 2)); + return replaceWith(CreateNthRootOfUnity(r))->shallowReduce(context, angleUnit); + } + } + bool letPowerAtRoot = parentIsALogarithmOfSameBase(); + if (operand(0)->type() == Type::Rational) { + Rational * a = static_cast(editableOperand(0)); // p^q with p, q rationals if (!letPowerAtRoot && operand(1)->type() == Type::Rational) { - double p = a->approximate(context, angleUnit); - double q = operand(1)->approximate(context, angleUnit); - double approx = std::pow(std::fabs(p), q); - if (std::isinf(approx) || std::isnan(approx) || std::fabs(approx)> 1E100) { + Rational * exp = static_cast(editableOperand(1)); + /* First, we check that the simplification does not involve too complex power + * of integers (ie 3^999) that would take too much time to compute. */ + if (RationalExponentShouldNotBeReduced(exp)) { return this; } - return simplifyRationalRationalPower(this, a, static_cast(editableOperand(1)), context, angleUnit); + return simplifyRationalRationalPower(this, a, exp, context, angleUnit); } } // e^(i*Pi*r) with r rational @@ -264,7 +298,7 @@ Expression * Power::shallowReduce(Context& context, AngleUnit angleUnit) { return replaceWith(editableOperand(1)->editableOperand(0), true); } } - // (a^b)^c -> a^(b+c) if a > 0 or c is integer + // (a^b)^c -> a^(b*c) if a > 0 or c is integer if (operand(0)->type() == Type::Power) { Power * p = static_cast(editableOperand(0)); // Check is a > 0 or c is Integer @@ -309,6 +343,11 @@ Expression * Power::shallowReduce(Context& context, AngleUnit angleUnit) { Addition * a = static_cast(editableOperand(1)); // Check is b is rational if (a->operand(0)->type() == Type::Rational) { + /* First, we check that the simplification does not involve too complex power + * of integers (ie 3^999) that would take too much time to compute. */ + if (RationalExponentShouldNotBeReduced(static_cast(a->operand(0)))) { + return this; + } Power * p1 = static_cast(clone()); replaceOperand(a, a->editableOperand(1), true); Power * p2 = static_cast(clone()); @@ -390,9 +429,12 @@ Expression * Power::CreateSimplifiedIntegerRationalPower(Integer i, Rational * r if (i.isOne()) { return new Rational(1); } - if (Arithmetic::k_primorial32.isLowerThan(i)) { + Integer absI = i; + absI.setNegative(false); + if (Arithmetic::k_primorial32.isLowerThan(absI)) { r->setSign(isDenominator ? Sign::Negative : Sign::Positive); - // We do not want to break i in prime factor because it might be take too many factors... More than k_maxNumberOfPrimeFactors. + /* We do not want to break i in prime factor because it might be take too + * many factors... More than k_maxNumberOfPrimeFactors. */ return new Power(new Rational(i), r->clone(), false); } Integer factors[Arithmetic::k_maxNumberOfPrimeFactors]; @@ -544,6 +586,7 @@ Expression * Power::removeSquareRootsFromDenominator(Context & context, AngleUni * p and q integers. * We'll turn those into sqrt(p*q)/q (or sqrt(p*q)/p) . */ Integer p = static_cast(operand(0))->numerator(); + assert(!p.isZero()); // We eliminated case of form 0^(-1/2) at first step of shallowReduce Integer q = static_cast(operand(0))->denominator(); // We do nothing for terms of the form sqrt(p) if (!q.isOne() || static_cast(operand(1))->isMinusHalf()) { @@ -551,7 +594,7 @@ Expression * Power::removeSquareRootsFromDenominator(Context & context, AngleUni if (static_cast(operand(1))->isHalf()) { result = new Multiplication(new Rational(Integer(1), q), sqrt, false); } else { - result = new Multiplication(new Rational(Integer(1), p), sqrt, false); + result = new Multiplication(new Rational(Integer(1), p), sqrt, false); // We use here the assertion that p != 0 } sqrt->shallowReduce(context, angleUnit); } @@ -649,6 +692,15 @@ bool Power::isNthRootOfUnity() const { return false; } +bool Power::RationalExponentShouldNotBeReduced(const Rational * r) { + Integer maxIntegerExponent = r->numerator(); + maxIntegerExponent.setNegative(false); + if (Integer::NaturalOrder(maxIntegerExponent, Integer(k_maxIntegerPower)) > 0) { + return true; + } + return false; +} + template Complex Power::compute(Complex, Complex); template Complex Power::compute(Complex, Complex); } diff --git a/poincare/src/prediction_interval.cpp b/poincare/src/prediction_interval.cpp index 42f33e734..548f2442a 100644 --- a/poincare/src/prediction_interval.cpp +++ b/poincare/src/prediction_interval.cpp @@ -68,9 +68,9 @@ Expression * PredictionInterval::shallowReduce(Context& context, AngleUnit angle } template -Expression * PredictionInterval::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * pInput = operand(0)->evaluate(context, angleUnit); - Expression * nInput = operand(1)->evaluate(context, angleUnit); +Expression * PredictionInterval::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * pInput = operand(0)->approximate(context, angleUnit); + Expression * nInput = operand(1)->approximate(context, angleUnit); if (pInput->type() != Type::Complex || nInput->type() != Type::Complex) { return new Complex(Complex::Float(NAN)); } diff --git a/poincare/src/preferences.cpp b/poincare/src/preferences.cpp index f23ad1cdf..c224419fd 100644 --- a/poincare/src/preferences.cpp +++ b/poincare/src/preferences.cpp @@ -1,4 +1,5 @@ #include +#include namespace Poincare { @@ -7,7 +8,8 @@ static Preferences s_preferences; Preferences::Preferences() : m_angleUnit(Expression::AngleUnit::Degree), m_displayMode(Expression::FloatDisplayMode::Decimal), - m_complexFormat(Expression::ComplexFormat::Cartesian) + m_complexFormat(Expression::ComplexFormat::Cartesian), + m_numberOfSignificantDigits(PrintFloat::k_numberOfPrintedSignificantDigits) { } @@ -20,9 +22,7 @@ Expression::AngleUnit Preferences::angleUnit() const { } void Preferences::setAngleUnit(Expression::AngleUnit angleUnit) { - if (angleUnit != m_angleUnit) { - m_angleUnit = angleUnit; - } + m_angleUnit = angleUnit; } Expression::FloatDisplayMode Preferences::displayMode() const { @@ -30,9 +30,7 @@ Expression::FloatDisplayMode Preferences::displayMode() const { } void Preferences::setDisplayMode(Expression::FloatDisplayMode FloatDisplayMode) { - if (FloatDisplayMode != m_displayMode) { - m_displayMode = FloatDisplayMode; - } + m_displayMode = FloatDisplayMode; } Expression::ComplexFormat Preferences::complexFormat() const { @@ -40,9 +38,15 @@ Expression::ComplexFormat Preferences::complexFormat() const { } void Preferences::setComplexFormat(Expression::ComplexFormat complexFormat) { - if (complexFormat != m_complexFormat) { - m_complexFormat = complexFormat; - } + m_complexFormat = complexFormat; +} + +char Preferences::numberOfSignificantDigits() const { + return m_numberOfSignificantDigits; +} + +void Preferences::setNumberOfSignificantDigits(char numberOfSignificantDigits) { + m_numberOfSignificantDigits = numberOfSignificantDigits; } } diff --git a/poincare/src/product.cpp b/poincare/src/product.cpp index dcc8f40d0..d202cd807 100644 --- a/poincare/src/product.cpp +++ b/poincare/src/product.cpp @@ -31,7 +31,7 @@ ExpressionLayout * Product::createSequenceLayoutWithArgumentLayouts(ExpressionLa } template -Expression * Product::templatedEvaluateWithNextTerm(Expression * a, Expression * b) const { +Expression * Product::templatedApproximateWithNextTerm(Expression * a, Expression * b) const { if (a->type() == Type::Complex && b->type() == Type::Complex) { Complex * c = static_cast *>(a); Complex * d = static_cast *>(b); diff --git a/poincare/src/rational.cpp b/poincare/src/rational.cpp index 78accb430..863a605f4 100644 --- a/poincare/src/rational.cpp +++ b/poincare/src/rational.cpp @@ -138,7 +138,7 @@ int Rational::simplificationOrderSameType(const Expression * e) const { return NaturalOrder(*this, *other); } -template Complex * Rational::templatedEvaluate(Context& context, Expression::AngleUnit angleUnit) const { +template Complex * Rational::templatedApproximate(Context& context, Expression::AngleUnit angleUnit) const { T n = m_numerator.approximate(); T d = m_denominator.approximate(); return new Complex(Complex::Float(n/d)); diff --git a/poincare/src/round.cpp b/poincare/src/round.cpp index ac379508d..cfdf2a3a9 100644 --- a/poincare/src/round.cpp +++ b/poincare/src/round.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include extern "C" { #include @@ -27,13 +29,32 @@ Expression * Round::shallowReduce(Context& context, AngleUnit angleUnit) { return replaceWith(new Undefined(), true); } #endif + if (operand(0)->type() == Type::Rational && operand(1)->type() == Type::Rational) { + Rational * r1 = static_cast(editableOperand(0)); + Rational * r2 = static_cast(editableOperand(1)); + if (!r2->denominator().isOne()) { + return replaceWith(new Undefined(), true); + } + if (Power::RationalExponentShouldNotBeReduced(r2)) { + return this; + } + Rational err = Rational::Power(Rational(10), r2->numerator()); + Rational mult = Rational::Multiplication(*r1, Rational(err)); + IntegerDivision d = Integer::Division(mult.numerator(), mult.denominator()); + Integer rounding = d.quotient; + if (Rational::NaturalOrder(Rational(d.remainder, mult.denominator()), Rational(1,2)) >= 0) { + rounding = Integer::Addition(rounding, Integer(1)); + } + Rational result = Rational::Multiplication(rounding, Rational::Power(Rational(1,10), r2->numerator())); + return replaceWith(new Rational(result), true); + } return this; // TODO: implement for rationals! } template -Complex * Round::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * f1Input = operand(0)->evaluate(context, angleUnit); - Expression * f2Input = operand(1)->evaluate(context, angleUnit); +Complex * Round::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * f1Input = operand(0)->approximate(context, angleUnit); + Expression * f2Input = operand(1)->approximate(context, angleUnit); T f1 = f1Input->type() == Type::Complex ? static_cast *>(f1Input)->toScalar() : NAN; T f2 = f2Input->type() == Type::Complex ? static_cast *>(f2Input)->toScalar() : NAN; delete f1Input; diff --git a/poincare/src/sequence.cpp b/poincare/src/sequence.cpp index 0b2b5bf1a..87386e816 100644 --- a/poincare/src/sequence.cpp +++ b/poincare/src/sequence.cpp @@ -23,9 +23,9 @@ ExpressionLayout * Sequence::privateCreateLayout(FloatDisplayMode floatDisplayMo } template -Expression * Sequence::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * aInput = operand(1)->evaluate(context, angleUnit); - Expression * bInput = operand(2)->evaluate(context, angleUnit); +Expression * Sequence::templatedApproximate(Context& context, AngleUnit angleUnit) const { + Expression * aInput = operand(1)->approximate(context, angleUnit); + Expression * bInput = operand(2)->approximate(context, angleUnit); T start = aInput->type() == Type::Complex ? static_cast *>(aInput)->toScalar() : NAN; T end = bInput->type() == Type::Complex ? static_cast *>(bInput)->toScalar() : NAN; delete aInput; @@ -43,7 +43,7 @@ Expression * Sequence::templatedEvaluate(Context& context, AngleUnit angleUnit) } Complex iExpression = Complex::Float(i); nContext.setExpressionForSymbolName(&iExpression, &nSymbol, nContext); - Expression * expression = operand(0)->evaluate(nContext, angleUnit); + Expression * expression = operand(0)->approximate(nContext, angleUnit); Expression * newResult = evaluateWithNextTerm(T(), result, expression); delete result; delete expression; diff --git a/poincare/src/simplification/expression_simplify.cpp b/poincare/src/simplification/expression_simplify.cpp index 7ce61943c..2d9d5f216 100644 --- a/poincare/src/simplification/expression_simplify.cpp +++ b/poincare/src/simplification/expression_simplify.cpp @@ -22,10 +22,10 @@ public: ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override { return nullptr; } - Evaluation * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { + Evaluation * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return nullptr; } - Evaluation * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { + Evaluation * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return nullptr; } }; diff --git a/poincare/src/static_hierarchy.cpp b/poincare/src/static_hierarchy.cpp index 62ec51d82..6716ecd12 100644 --- a/poincare/src/static_hierarchy.cpp +++ b/poincare/src/static_hierarchy.cpp @@ -7,14 +7,14 @@ namespace Poincare { template StaticHierarchy::StaticHierarchy() : - Hierarchy(), + Expression(), m_operands{} { } template StaticHierarchy::StaticHierarchy(const Expression * const * operands, bool cloneOperands) : - Hierarchy() + Expression() { build(operands, T, cloneOperands); } diff --git a/poincare/src/store.cpp b/poincare/src/store.cpp index ad930fac3..34296a405 100644 --- a/poincare/src/store.cpp +++ b/poincare/src/store.cpp @@ -37,12 +37,10 @@ ExpressionLayout * Store::privateCreateLayout(FloatDisplayMode floatDisplayMode, } template -Expression * Store::templatedEvaluate(Context& context, AngleUnit angleUnit) const { - Expression * valueEvaluation = value()->evaluate(context, angleUnit); - context.setExpressionForSymbolName(valueEvaluation, symbol(), context); - delete valueEvaluation; +Expression * Store::templatedApproximate(Context& context, AngleUnit angleUnit) const { + context.setExpressionForSymbolName(value(), symbol(), context); if (context.expressionForSymbol(symbol()) != nullptr) { - return context.expressionForSymbol(symbol())->evaluate(context, angleUnit); + return context.expressionForSymbol(symbol())->approximate(context, angleUnit); } return new Complex(Complex::Float(NAN)); } diff --git a/poincare/src/sum.cpp b/poincare/src/sum.cpp index 7e7e5c792..70a5168b7 100644 --- a/poincare/src/sum.cpp +++ b/poincare/src/sum.cpp @@ -31,7 +31,7 @@ ExpressionLayout * Sum::createSequenceLayoutWithArgumentLayouts(ExpressionLayout } template -Expression * Sum::templatedEvaluateWithNextTerm(Expression * a, Expression * b) const { +Expression * Sum::templatedApproximateWithNextTerm(Expression * a, Expression * b) const { if (a->type() == Type::Complex && b->type() == Type::Complex) { Complex * c = static_cast *>(a); Complex * d = static_cast *>(b); diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 440b9fdee..57db3583e 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -111,9 +111,9 @@ Expression::Sign Symbol::sign() const { } template -Expression * Symbol::templatedEvaluate(Context& context, AngleUnit angleUnit) const { +Expression * Symbol::templatedApproximate(Context& context, AngleUnit angleUnit) const { if (context.expressionForSymbol(this) != nullptr) { - return context.expressionForSymbol(this)->evaluate(context, angleUnit); + return context.expressionForSymbol(this)->approximate(context, angleUnit); } return new Complex(Complex::Float(NAN)); } @@ -181,12 +181,19 @@ bool Symbol::isMatrixSymbol() const { return false; } +bool Symbol::isScalarSymbol() const { + if (m_name >= 'A' && m_name <= 'Z') { + return true; + } + return false; +} + int Symbol::simplificationOrderSameType(const Expression * e) const { assert(e->type() == Expression::Type::Symbol); - if (m_name == ((Symbol *)e)->m_name) { + if ((uint8_t)m_name == ((uint8_t)static_cast(e)->name())) { return 0; } - if ((m_name > ((Symbol *)e)->m_name)) { + if ((uint8_t)m_name > ((uint8_t)static_cast(e)->name())) { return 1; } return -1; diff --git a/poincare/src/trigonometry.cpp b/poincare/src/trigonometry.cpp index 37b87d77c..633029590 100644 --- a/poincare/src/trigonometry.cpp +++ b/poincare/src/trigonometry.cpp @@ -22,7 +22,7 @@ Expression * Trigonometry::shallowReduceDirectFunction(Expression * e, Context& } Expression::Type correspondingType = e->type() == Expression::Type::Cosine ? Expression::Type::ArcCosine : (e->type() == Expression::Type::Sine ? Expression::Type::ArcSine : Expression::Type::ArcTangent); if (e->operand(0)->type() == correspondingType) { - float trigoOp = e->operand(0)->operand(0)->approximate(context, angleUnit); + float trigoOp = e->operand(0)->operand(0)->approximateToScalar(context, angleUnit); if (e->type() == Expression::Type::Tangent || (trigoOp >= -1.0f && trigoOp <= 1.0f)) { return e->replaceWith(e->editableOperand(0)->editableOperand(0), true); } @@ -83,7 +83,7 @@ bool Trigonometry::ExpressionIsEquivalentToTangent(const Expression * e) { Expression * Trigonometry::shallowReduceInverseFunction(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) { - float approxOp = e->operand(0)->approximate(context, angleUnit); + float approxOp = e->operand(0)->approximateToScalar(context, angleUnit); if (approxOp > 1.0f || approxOp < -1.0f) { return e->replaceWith(new Undefined(), true); } @@ -91,7 +91,7 @@ Expression * Trigonometry::shallowReduceInverseFunction(Expression * e, Context& 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 trigoOp = e->operand(0)->operand(0)->approximateToScalar(context, angleUnit); 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)) { @@ -100,7 +100,7 @@ Expression * Trigonometry::shallowReduceInverseFunction(Expression * e, Context& } // 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); + float trigoOp = e->operand(0)->operand(1)->operand(0)->approximateToScalar(context, angleUnit); if (trigoOp >= -pi/2.0f && trigoOp <= pi/2.0f) { return e->replaceWith(e->editableOperand(0)->editableOperand(1)->editableOperand(0), true); } @@ -180,6 +180,17 @@ Expression * Trigonometry::table(const Expression * e, Expression::Type type, Co int trigonometricFunctionIndex = type == Expression::Type::Cosine || type == Expression::Type::ArcCosine ? 2 : (type == Expression::Type::Sine || type == Expression::Type::ArcSine ? 3 : 4); int inputIndex = type == Expression::Type::ArcCosine || type == Expression::Type::ArcSine || type == Expression::Type::ArcTangent ? trigonometricFunctionIndex : angleUnitIndex; int outputIndex = type == Expression::Type::ArcCosine || type == Expression::Type::ArcSine || type == Expression::Type::ArcTangent ? angleUnitIndex : trigonometricFunctionIndex; + + /* Avoid looping if we can exclude quickly that the e is in the table */ + if (inputIndex == 0 && e->type() != Expression::Type::Rational) { + return nullptr; + } + if (inputIndex == 1 && e->type() != Expression::Type::Rational && e->type() != Expression::Type::Multiplication && e->type() != Expression::Type::Symbol) { + return nullptr; + } + if (inputIndex >1 && e->type() != Expression::Type::Rational && e->type() != Expression::Type::Multiplication && e->type() != Expression::Type::Power && e->type() != Expression::Type::Addition) { + return nullptr; + } for (int i = 0; i < k_numberOfEntries; i++) { Expression * input = Expression::parse(cheatTable[i][inputIndex]); if (input == nullptr) { diff --git a/poincare/src/undefined.cpp b/poincare/src/undefined.cpp index c8da8aac4..1fc6f27ad 100644 --- a/poincare/src/undefined.cpp +++ b/poincare/src/undefined.cpp @@ -14,7 +14,7 @@ Expression * Undefined::clone() const { return new Undefined(); } -template Complex * Undefined::templatedEvaluate(Context& context, AngleUnit angleUnit) const { +template Complex * Undefined::templatedApproximate(Context& context, AngleUnit angleUnit) const { return new Complex(Complex::Float(NAN)); } diff --git a/poincare/test/addition.cpp b/poincare/test/addition.cpp index 58f7f8786..85216991c 100644 --- a/poincare/test/addition.cpp +++ b/poincare/test/addition.cpp @@ -31,3 +31,28 @@ QUIZ_CASE(poincare_addition_evaluate) { assert_parsed_expression_evaluates_to("[[1,2+I][3,4][5,6]]+[[1,2+I][3,4][5,6]]", f, 3, 2); #endif } + +QUIZ_CASE(poincare_addition_simplify) { + assert_parsed_expression_simplify_to("2+1", "3"); + assert_parsed_expression_simplify_to("2+A", "2+A"); + assert_parsed_expression_simplify_to("1+2+3+4+5+6+7", "28"); + assert_parsed_expression_simplify_to("1+2+3+4+5+A+6+7", "28+A"); + assert_parsed_expression_simplify_to("(0+0)", "0"); + assert_parsed_expression_simplify_to("2+13cos(2)-23cos(2)", "2-10*cos(2)"); + assert_parsed_expression_simplify_to("1+1+ln(2)+(5+3*2)/9-4/7+1/98", "(2347+882*ln(2))/882"); + assert_parsed_expression_simplify_to("1+2+0+cos(2)", "3+cos(2)"); + assert_parsed_expression_simplify_to("-5P+3P", "-2*P"); + assert_parsed_expression_simplify_to("1-3+A-5+2A-4A", "(-7)-A"); + assert_parsed_expression_simplify_to("1+2", "3"); + assert_parsed_expression_simplify_to("A-A", "0"); + assert_parsed_expression_simplify_to("A-A+2cos(2)+B-B-cos(2)", "cos(2)"); + assert_parsed_expression_simplify_to("1+A+2+B+3", "6+A+B"); + assert_parsed_expression_simplify_to("-A", "-A"); + assert_parsed_expression_simplify_to("1/(x+1)+1/(P+2)", "(3+x+P)/(2+2*x+P+x*P)"); + assert_parsed_expression_simplify_to("1/x^2+1/(x^2*P)", "(1+P)/(x^2*P)"); + assert_parsed_expression_simplify_to("1/x^2+1/(x^3*P)", "(1+x*P)/(x^3*P)"); + assert_parsed_expression_simplify_to("4x/x^2+3P/(x^3*P)", "(3+4*x^2)/x^3"); + assert_parsed_expression_simplify_to("A+B-A-B", "0"); + assert_parsed_expression_simplify_to("A+B+(-1)*A+(-1)*B", "0"); + assert_parsed_expression_simplify_to("3^(1/2)+2^(-2*3^(1/2)*X^P)/2", "(1+2*2^(2*R(3)*X^P)*R(3))/(2*2^(2*R(3)*X^P))"); +} diff --git a/poincare/test/arithmetic.cpp b/poincare/test/arithmetic.cpp index accd9529e..841bd6a10 100644 --- a/poincare/test/arithmetic.cpp +++ b/poincare/test/arithmetic.cpp @@ -83,6 +83,6 @@ QUIZ_CASE(poincare_arithmetic) { int coefficients2[3] = {2,4,2}; assert_prime_factorization_equals_to(Integer(122500), factors2, coefficients2, 3); int factors3[8] = {3,7,11, 13, 19, 3607, 3803, 52579}; - int coefficients3[8] = {4,2,2,2,2,2,2,2}; - assert_prime_factorization_equals_to(Integer("15241578780673678515622620750190521"), factors3, coefficients3, 8); + int coefficients3[8] = {4,2,2,2,2,2,2,1}; + assert_prime_factorization_equals_to(Integer("289879586539753105148873518899"), factors3, coefficients3, 8); } diff --git a/poincare/test/complex.cpp b/poincare/test/complex.cpp index d08b3ab16..c78628c7b 100644 --- a/poincare/test/complex.cpp +++ b/poincare/test/complex.cpp @@ -5,107 +5,25 @@ #include #include #include +#include "helper.h" using namespace Poincare; -constexpr Expression::FloatDisplayMode Decimal = Expression::FloatDisplayMode::Decimal; -constexpr Expression::FloatDisplayMode Scientific = Expression::FloatDisplayMode::Scientific; -constexpr Expression::ComplexFormat Cartesian = Expression::ComplexFormat::Cartesian; -constexpr Expression::ComplexFormat Polar = Expression::ComplexFormat::Polar; - -template -void assert_cartesian_complex_converts_to(T a, T b, const char * result, Expression::FloatDisplayMode mode = Scientific, Expression::ComplexFormat format = Cartesian, int significantDigits = 7, int bufferSize = 13+13+7+1) { - quiz_print(result); - - int tagSize = 8; - unsigned char tag = 'X'; - char * taggedBuffer = new char[bufferSize+2*tagSize]; - memset(taggedBuffer, tag, bufferSize+2*tagSize); - char * buffer = taggedBuffer + tagSize; - - if (b == 0) { - Complex::convertFloatToText(a, buffer, bufferSize, significantDigits, mode); - } else { - Preferences::sharedPreferences()->setComplexFormat(format); - Preferences::sharedPreferences()->setDisplayMode(mode); - Complex::Cartesian(a, b).writeTextInBuffer(buffer, bufferSize); - } - - for (int i=0; i(Complex::Float(123.456f)); - Evaluation * m = a->evaluate(globalContext); - assert(std::fabs(m->complexOperand(0)->a() - 123.456) < 0.00001); - assert(m->complexOperand(0)->b() == 0.0); - assert(m->numberOfOperands() == 1); + Expression * m = a->approximate(globalContext); + assert(m->type() == Expression::Type::Complex); + Complex * mc = static_cast *>(m); + assert(std::fabs(mc->a() - 123.456) < 0.00001); + assert(mc->b() == 0.0); delete m; - Evaluation * n = a->evaluate(globalContext); - assert(n->complexOperand(0)->a() == 123.456f); - assert(n->complexOperand(0)->b() == 0.0f); - assert(n->numberOfOperands() == 1); + Expression * n = a->approximate(globalContext); + assert(n->type() == Expression::Type::Complex); + Complex * nc = static_cast *>(n); + assert(nc->a() == 123.456f); + assert(nc->b() == 0.0f); delete n; delete a; @@ -139,3 +57,15 @@ QUIZ_CASE(poincare_complex_constructor) { assert(d->r() == 1.0e155*M_SQRT2 && d->th() == -M_PI_4); delete d; } + +QUIZ_CASE(poincare_complex_simplify) { + assert_parsed_expression_simplify_to("I", "I"); + assert_parsed_expression_simplify_to("R(-33)", "R(33)*I"); + assert_parsed_expression_simplify_to("I^(3/5)", "(R(2)*R(5-R(5))+I+R(5)*I)/4"); + assert_parsed_expression_simplify_to("IIII", "1"); + assert_parsed_expression_simplify_to("R(-I)", "R(-I)"); + assert_parsed_expression_simplify_to("Acos(9)IIln(2)", "-cos(9)*ln(2)*A"); + assert_parsed_expression_simplify_to("(R(2)+R(2)*I)/2(R(2)+R(2)*I)/2(R(2)+R(2)*I)/2", "(R(2)+R(2)*I)/(2*(2*R(2)+2*R(2)*I)^2)"); + assert_parsed_expression_simplify_to("root(5^(-I)3^9,I)", "undef"); + assert_parsed_expression_simplify_to("I^I", "undef"); +} diff --git a/poincare/test/convert_expression_to_text.cpp b/poincare/test/convert_expression_to_text.cpp index 5f69ac26b..84ee111df 100644 --- a/poincare/test/convert_expression_to_text.cpp +++ b/poincare/test/convert_expression_to_text.cpp @@ -5,37 +5,103 @@ #include #include #include +#include "helper.h" using namespace Poincare; +constexpr Expression::FloatDisplayMode DecimalDisplay = Expression::FloatDisplayMode::Decimal; +constexpr Expression::FloatDisplayMode ScientificDisplay = Expression::FloatDisplayMode::Scientific; +constexpr Expression::ComplexFormat Cartesian = Expression::ComplexFormat::Cartesian; +constexpr Expression::ComplexFormat Polar = Expression::ComplexFormat::Polar; -void assert_expression_prints_to(Expression * e, const char * result, int bufferSize = 100) { +template +void assert_float_prints_to(T a, const char * result, Expression::FloatDisplayMode mode = ScientificDisplay, int significantDigits = 7, int bufferSize = 250) { quiz_print(result); - char * buffer = new char[bufferSize]; - e->writeTextInBuffer(buffer, bufferSize); + int tagSize = 8; + unsigned char tag = 'O'; + char * taggedBuffer = new char[bufferSize+2*tagSize]; + memset(taggedBuffer, tag, bufferSize+2*tagSize); + char * buffer = taggedBuffer + tagSize; - char * currentChar = buffer; - while (*currentChar != 0) { - if (*currentChar == Ion::Charset::Exponent) { - *currentChar = 'E'; - } - if (*currentChar == Ion::Charset::Exponential) { - *currentChar = 'e'; - } - if (*currentChar == Ion::Charset::IComplex) { - *currentChar = 'i'; - } - currentChar++; + Complex::convertFloatToText(a, buffer, bufferSize, significantDigits, mode); + + for (int i=0; isetComplexFormat(format); + Preferences::sharedPreferences()->setDisplayMode(mode); + e->writeTextInBuffer(buffer, bufferSize); + translate_in_ASCII_chars(buffer); + + for (int i=0; i c0 = Complex::Cartesian(1.0, 2.0); + assert_expression_prints_to(&c0, "1+2*I", DecimalDisplay, Cartesian); + Complex c1 = Complex::Cartesian(1.0, 2.0); + assert_expression_prints_to(&c1, "2.2360679774998*X^(1.1071487177941*I)", DecimalDisplay, Polar); + Complex c2 = Complex::Cartesian(-1.3, 2.444); + assert_expression_prints_to(&c2, "-1.3+2.444*I", DecimalDisplay, Cartesian); + Complex c3 = Complex::Cartesian(-1.3, 2.444); + assert_expression_prints_to(&c3, "2.7682369840749*X^(2.0596486811226*I)", DecimalDisplay, Polar); + Complex c4 = Complex::Cartesian(-1.3, -2.444); + assert_expression_prints_to(&c4, "-1.3-2.444*I", DecimalDisplay, Cartesian); + Complex c5 = Complex::Cartesian(64078208.0, 119229408.0); + assert_expression_prints_to(&c5, "64078208+119229408*I", DecimalDisplay, Cartesian); + Complex c6 = Complex::Cartesian(64078208.0, 119229408.0); + assert_expression_prints_to(&c6, "135357557.86997*X^(1.0776501182461*I)", DecimalDisplay, Polar); + Complex c7 = Complex::Cartesian(INFINITY, 119229408.0); + assert_expression_prints_to(&c7, "undef", DecimalDisplay, Polar); + Complex c8 = Complex::Cartesian(0.0f, 0.0f); + assert_expression_prints_to(&c8, "0", DecimalDisplay, Polar); + Complex c9 = Complex::Cartesian(NAN, 0.0f); + assert_expression_prints_to(&c9, "undef", DecimalDisplay, Polar); + Complex c10 = Complex::Cartesian(0.0f, NAN); + assert_expression_prints_to(&c10, "undef", DecimalDisplay, Polar); + Complex c11 = Complex::Cartesian(NAN, NAN); + assert_expression_prints_to(&c11, "undef", DecimalDisplay, Polar); + +} diff --git a/poincare/test/factorial.cpp b/poincare/test/factorial.cpp new file mode 100644 index 000000000..3151e20d9 --- /dev/null +++ b/poincare/test/factorial.cpp @@ -0,0 +1,15 @@ +#include +#include +#include +#include +#include "helper.h" + +using namespace Poincare; + +QUIZ_CASE(poincare_factorial_simplify) { + assert_parsed_expression_simplify_to("1/3!", "1/6"); + assert_parsed_expression_simplify_to("5!", "120"); + assert_parsed_expression_simplify_to("(1/3)!", "undef"); + assert_parsed_expression_simplify_to("P!", "undef"); + assert_parsed_expression_simplify_to("X!", "undef"); +} diff --git a/poincare/test/function.cpp b/poincare/test/function.cpp index c7f58f6e3..e63d5d56f 100644 --- a/poincare/test/function.cpp +++ b/poincare/test/function.cpp @@ -50,134 +50,250 @@ QUIZ_CASE(poincare_parse_function) { QUIZ_CASE(poincare_function_evaluate) { - Complex a0[1] = {Complex::Float(1.0)}; + Complex a0[1] = {Complex::Float(1.0)}; assert_parsed_expression_evaluates_to("abs(-1)", a0); + Complex ad0[1] = {Complex::Float(1.0)}; + assert_parsed_expression_evaluates_to("abs(-1)", ad0); Complex a1[1] = {Complex::Float(std::sqrt(3.0f*3.0f+2.0f*2.0f))}; assert_parsed_expression_evaluates_to("abs(3+2I)", a1); + Complex ad1[1] = {Complex::Float(std::sqrt(3.0*3.0+2.0*2.0))}; + assert_parsed_expression_evaluates_to("abs(3+2I)", ad1); - Complex a2[4] = {Complex::Float(1.0), Complex::Float(2.0), Complex::Float(3.0), Complex::Float(4.0)}; + Complex a2[4] = {Complex::Float(1.0), Complex::Float(2.0), Complex::Float(3.0), Complex::Float(4.0)}; assert_parsed_expression_evaluates_to("abs([[1,-2][3,-4]])", a2, 2, 2); + Complex ad2[4] = {Complex::Float(1.0), Complex::Float(2.0), Complex::Float(3.0), Complex::Float(4.0)}; + assert_parsed_expression_evaluates_to("abs([[1,-2][3,-4]])", ad2, 2, 2); Complex a3[4] = {Complex::Float(std::sqrt(3.0f*3.0f+2.0f*2.0f)), Complex::Float(std::sqrt(3.0f*3.0f+4.0f*4.0f)), Complex::Float(std::sqrt(5.0f*5.0f+2.0f*2.0f)), Complex::Float(std::sqrt(3.0f*3.0f+2.0f*2.0f))}; assert_parsed_expression_evaluates_to("abs([[3+2I,3+4I][5+2I,3+2I]])", a3, 2, 2); + Complex ad3[4] = {Complex::Float(std::sqrt(3.0f*3.0f+2.0f*2.0f)), Complex::Float(std::sqrt(3.0f*3.0f+4.0f*4.0f)), Complex::Float(std::sqrt(5.0f*5.0f+2.0f*2.0f)), Complex::Float(std::sqrt(3.0f*3.0f+2.0f*2.0f))}; + assert_parsed_expression_evaluates_to("abs([[3+2I,3+4I][5+2I,3+2I]])", ad3, 2, 2); - Complex b[1] = {Complex::Float(210.0)}; + Complex b[1] = {Complex::Float(210.0)}; assert_parsed_expression_evaluates_to("binomial(10, 4)", b); + Complex bd[1] = {Complex::Float(210.0)}; + assert_parsed_expression_evaluates_to("binomial(10, 4)", bd); Complex c[1] = {Complex::Float(1.0f)}; assert_parsed_expression_evaluates_to("ceil(0.2)", c); + Complex cd[1] = {Complex::Float(1.0f)}; + assert_parsed_expression_evaluates_to("ceil(0.2)", cd); - Complex d[1] = {Complex::Float(2.0)}; + Complex d[1] = {Complex::Float(2.0)}; assert_parsed_expression_evaluates_to("diff(2*x, 2)", d); + Complex dd[1] = {Complex::Float(2.0)}; + assert_parsed_expression_evaluates_to("diff(2*x, 2)", dd); #if MATRICES_ARE_DEFINED Complex e[1] = {Complex::Float(126.0f)}; assert_parsed_expression_evaluates_to("det([[1,23,3][4,5,6][7,8,9]])", e); + Complex ed[1] = {Complex::Float(126.0f)}; + assert_parsed_expression_evaluates_to("det([[1,23,3][4,5,6][7,8,9]])", ed); #endif - Complex f[1] = {Complex::Float(2.0)}; + Complex f[1] = {Complex::Float(2.0)}; assert_parsed_expression_evaluates_to("floor(2.3)", f); + Complex fd[1] = {Complex::Float(2.0)}; + assert_parsed_expression_evaluates_to("floor(2.3)", fd); Complex g[1] = {Complex::Float(0.3f)}; assert_parsed_expression_evaluates_to("frac(2.3)", g); + Complex gd[1] = {Complex::Float(0.3f)}; + assert_parsed_expression_evaluates_to("frac(2.3)", gd); - Complex h[1] = {Complex::Float(2.0)}; + Complex h[1] = {Complex::Float(2.0)}; assert_parsed_expression_evaluates_to("gcd(234,394)", h); + Complex hd[1] = {Complex::Float(2.0)}; + assert_parsed_expression_evaluates_to("gcd(234,394)", hd); Complex i[1] = {Complex::Float(3.0f)}; assert_parsed_expression_evaluates_to("im(2+3I)", i); + Complex id[1] = {Complex::Float(3.0f)}; + assert_parsed_expression_evaluates_to("im(2+3I)", id); - Complex j[1] = {Complex::Float(3.0/2.0)}; + Complex j[1] = {Complex::Float(3.0/2.0)}; assert_parsed_expression_evaluates_to("int(x, 1, 2)", j); + Complex jd[1] = {Complex::Float(3.0/2.0)}; + assert_parsed_expression_evaluates_to("int(x, 1, 2)", jd); Complex k[1] = {Complex::Float(46098.0f)}; assert_parsed_expression_evaluates_to("lcm(234,394)", k); + Complex kd[1] = {Complex::Float(46098.0f)}; + assert_parsed_expression_evaluates_to("lcm(234,394)", kd); - Complex l[1] = {Complex::Float(std::log(2.0))}; + Complex l[1] = {Complex::Float(std::log(2.0))}; assert_parsed_expression_evaluates_to("ln(2)", l); + Complex ld[1] = {Complex::Float(std::log(2.0))}; + assert_parsed_expression_evaluates_to("ln(2)", ld); Complex m[1] = {Complex::Float(std::log10(2.0f))}; assert_parsed_expression_evaluates_to("log(2)", m); + Complex md[1] = {Complex::Float(std::log10(2.0f))}; + assert_parsed_expression_evaluates_to("log(2)", md); - Complex n[1] = {Complex::Float(5040.0)}; + Complex n[1] = {Complex::Float(5040.0)}; assert_parsed_expression_evaluates_to("permute(10, 4)", n); + Complex nd[1] = {Complex::Float(5040.0)}; + assert_parsed_expression_evaluates_to("permute(10, 4)", nd); Complex o[1] = {Complex::Float(604800.0f)}; assert_parsed_expression_evaluates_to("product(n, 4, 10)", o); + Complex od[1] = {Complex::Float(604800.0f)}; + assert_parsed_expression_evaluates_to("product(n, 4, 10)", od); - Complex p[1] = {Complex::Float(2.0)}; + Complex p[1] = {Complex::Float(2.0)}; assert_parsed_expression_evaluates_to("re(2+I)", p); + Complex pd[1] = {Complex::Float(2.0)}; + assert_parsed_expression_evaluates_to("re(2+I)", pd); Complex q[1] = {Complex::Float(9.0f)}; assert_parsed_expression_evaluates_to("rem(29, 10)", q); + Complex qd[1] = {Complex::Float(9.0f)}; + assert_parsed_expression_evaluates_to("rem(29, 10)", qd); - Complex r[1] = {Complex::Float(std::pow(2.0, 1.0/3.0))}; + Complex r[1] = {Complex::Float(std::pow(2.0, 1.0/3.0))}; assert_parsed_expression_evaluates_to("root(2,3)", r); + Complex rd[1] = {Complex::Float(std::pow(2.0, 1.0/3.0))}; + assert_parsed_expression_evaluates_to("root(2,3)", rd); Complex s[1] = {Complex::Float(std::sqrt(2.0f))}; assert_parsed_expression_evaluates_to("R(2)", s); + Complex sd[1] = {Complex::Float(std::sqrt(2.0f))}; + assert_parsed_expression_evaluates_to("R(2)", sd); - Complex t[1] = {Complex::Float(49.0)}; + Complex t[1] = {Complex::Float(49.0)}; assert_parsed_expression_evaluates_to("sum(n, 4, 10)", t); + Complex td[1] = {Complex::Float(49.0)}; + assert_parsed_expression_evaluates_to("sum(n, 4, 10)", td); #if MATRICES_ARE_DEFINED Complex u[1] = {Complex::Float(15.0f)}; assert_parsed_expression_evaluates_to("trace([[1,2,3][4,5,6][7,8,9]])", u); + Complex ud[1] = {Complex::Float(15.0f)}; + assert_parsed_expression_evaluates_to("trace([[1,2,3][4,5,6][7,8,9]])", ud); #endif - Complex v[2] = {Complex::Float(0.1 - std::sqrt(1.0/100.0)), Complex::Float(0.1 + std::sqrt(1.0/100.0))}; + Complex v[2] = {Complex::Float(0.1 - std::sqrt(1.0/100.0)), Complex::Float(0.1 + std::sqrt(1.0/100.0))}; assert_parsed_expression_evaluates_to("confidence(0.1, 100)", v, 1, 2); + Complex vd[2] = {Complex::Float(0.1 - std::sqrt(1.0/100.0)), Complex::Float(0.1 + std::sqrt(1.0/100.0))}; + assert_parsed_expression_evaluates_to("confidence(0.1, 100)", vd, 1, 2); #if MATRICES_ARE_DEFINED Complex w[2] = {Complex::Float(2.0f), Complex::Float(3.0f)}; assert_parsed_expression_evaluates_to("dim([[1,2,3][4,5,-6]])", w, 1, 2); + Complex wd[2] = {Complex::Float(2.0f), Complex::Float(3.0f)}; + assert_parsed_expression_evaluates_to("dim([[1,2,3][4,5,-6]])", wd, 1, 2); #endif - Complex x[1] = {Complex::Cartesian(3.0, -2.0)}; + Complex x[1] = {Complex::Cartesian(3.0, -2.0)}; assert_parsed_expression_evaluates_to("conj(3+2*I)", x); + Complex xd[1] = {Complex::Cartesian(3.0, -2.0)}; + assert_parsed_expression_evaluates_to("conj(3+2*I)", xd); #if MATRICES_ARE_DEFINED Complex y[9] = {Complex::Float(-31.0f/24.0f), Complex::Float(-1.0f/12.0f), Complex::Float(3.0f/8.0f), Complex::Float(13.0f/12.0f), Complex::Float(1.0f/6.0f), Complex::Float(-1.0f/4.0f), Complex::Float(1.0f/24.0f),Complex::Float(-1.0f/12.0f), Complex::Float(1.0f/24.0f)}; assert_parsed_expression_evaluates_to("inverse([[1,2,3][4,5,-6][7,8,9]])", y, 3, 3); + Complex yd[9] = {Complex::Float(-31.0f/24.0f), Complex::Float(-1.0f/12.0f), Complex::Float(3.0f/8.0f), Complex::Float(13.0f/12.0f), Complex::Float(1.0f/6.0f), Complex::Float(-1.0f/4.0f), Complex::Float(1.0f/24.0f),Complex::Float(-1.0f/12.0f), Complex::Float(1.0f/24.0f)}; + assert_parsed_expression_evaluates_to("inverse([[1,2,3][4,5,-6][7,8,9]])", yd, 3, 3); #endif - Complex z[2] = {Complex::Float(0.1-std::sqrt(1.0/100.0)), Complex::Float(0.1+std::sqrt(1.0/100.0))}; + Complex z[2] = {Complex::Float(0.1-std::sqrt(1.0/100.0)), Complex::Float(0.1+std::sqrt(1.0/100.0))}; assert_parsed_expression_evaluates_to("prediction(0.1, 100)", z, 1, 2); + Complex zd[2] = {Complex::Float(0.1-std::sqrt(1.0/100.0)), Complex::Float(0.1+std::sqrt(1.0/100.0))}; + assert_parsed_expression_evaluates_to("prediction(0.1, 100)", zd, 1, 2); Complex aa[2] = {Complex::Float(0.1f-1.96f*std::sqrt((0.1f*(1.0f-0.1f))/100.0f)), Complex::Float(0.1f+1.96f*std::sqrt((0.1f*(1.0f-0.1f))/100.0f))}; assert_parsed_expression_evaluates_to("prediction95(0.1, 100)", aa, 1, 2); + Complex aad[2] = {Complex::Float(0.1f-1.96f*std::sqrt((0.1f*(1.0f-0.1f))/100.0f)), Complex::Float(0.1f+1.96f*std::sqrt((0.1f*(1.0f-0.1f))/100.0f))}; + assert_parsed_expression_evaluates_to("prediction95(0.1, 100)", aad, 1, 2); - Complex ab[1] = {Complex::Cartesian(-100.0, -540.0)}; + Complex ab[1] = {Complex::Cartesian(-100.0, -540.0)}; assert_parsed_expression_evaluates_to("product(2+n*I, 1, 5)", ab); + Complex abd[1] = {Complex::Cartesian(-100.0, -540.0)}; + assert_parsed_expression_evaluates_to("product(2+n*I, 1, 5)", abd); Complex ac[1] = {Complex::Cartesian(1.4593656008f, 0.1571201229f)}; assert_parsed_expression_evaluates_to("root(3+I, 3)", ac); + Complex acd[1] = {Complex::Cartesian(1.4593656008f, 0.1571201229f)}; + assert_parsed_expression_evaluates_to("root(3+I, 3)", acd); - Complex ad[1] = {Complex::Cartesian(1.38200696233, -0.152442779)}; - assert_parsed_expression_evaluates_to("root(3, 3+I)", ad); + Complex add[1] = {Complex::Cartesian(1.38200696233, -0.152442779)}; + assert_parsed_expression_evaluates_to("root(3, 3+I)", add); + Complex addd[1] = {Complex::Cartesian(1.38200696233, -0.152442779)}; + assert_parsed_expression_evaluates_to("root(3, 3+I)", addd); Complex ae[1] = {Complex::Cartesian(1.75532f, 0.28485f)}; assert_parsed_expression_evaluates_to("R(3+I)", ae); + Complex aed[1] = {Complex::Cartesian(1.75532f, 0.28485f)}; + assert_parsed_expression_evaluates_to("R(3+I)", aed); - Complex af[1] = {Complex::Cartesian(10.0, 15.0)}; + Complex af[1] = {Complex::Cartesian(10.0, 15.0)}; assert_parsed_expression_evaluates_to("sum(2+n*I,1,5)", af); + Complex afd[1] = {Complex::Cartesian(10.0, 15.0)}; + assert_parsed_expression_evaluates_to("sum(2+n*I,1,5)", afd); #if MATRICES_ARE_DEFINED - Complex ag[9] = {Complex::Float(1.0), Complex::Float(4.0), Complex::Float(7.0), Complex::Float(2.0), Complex::Float(5.0), Complex::Float(8.0), Complex::Float(3.0), Complex::Float(-6.0), Complex::Float(9.0)}; + Complex ag[9] = {Complex::Float(1.0), Complex::Float(4.0), Complex::Float(7.0), Complex::Float(2.0), Complex::Float(5.0), Complex::Float(8.0), Complex::Float(3.0), Complex::Float(-6.0), Complex::Float(9.0)}; assert_parsed_expression_evaluates_to("transpose([[1,2,3][4,5,-6][7,8,9]])", ag, 3, 3); assert_parsed_expression_evaluates_to("transpose([[1,7,5][4,2,8]])", ag, 3, 2); assert_parsed_expression_evaluates_to("transpose([[1,2][4,5][7,8]])", ag, 2, 3); + Complex agd[9] = {Complex::Float(1.0), Complex::Float(4.0), Complex::Float(7.0), Complex::Float(2.0), Complex::Float(5.0), Complex::Float(8.0), Complex::Float(3.0), Complex::Float(-6.0), Complex::Float(9.0)}; + assert_parsed_expression_evaluates_to("transpose([[1,2,3][4,5,-6][7,8,9]])", agd, 3, 3); + assert_parsed_expression_evaluates_to("transpose([[1,7,5][4,2,8]])", agd, 3, 2); + assert_parsed_expression_evaluates_to("transpose([[1,2][4,5][7,8]])", agd, 2, 3); #endif Complex ah[1] = {Complex::Float(2.325f)}; - assert_parsed_expression_evaluates_to("round(2.3245,3)", ah); + assert_parsed_expression_evaluates_to("round(2.3246,3)", ah); + Complex ahd[1] = {Complex::Float(2.325f)}; + assert_parsed_expression_evaluates_to("round(2.3245,3)", ahd); - Complex ai[1] = {Complex::Float(720.0f)}; + Complex ai[1] = {Complex::Float(720.0f)}; assert_parsed_expression_evaluates_to("6!", ai); + Complex aid[1] = {Complex::Float(720.0f)}; + assert_parsed_expression_evaluates_to("6!", aid); Complex aj[1] = {Complex::Cartesian(0.0f, 1.0f)}; assert_parsed_expression_evaluates_to("R(-1)", aj); + Complex ajd[1] = {Complex::Cartesian(0.0f, 1.0f)}; + assert_parsed_expression_evaluates_to("R(-1)", ajd); - Complex ak[1] = {Complex::Cartesian(0.5, 0.86602540378443864676)}; + Complex ak[1] = {Complex::Cartesian(0.5, 0.86602540378443864676)}; assert_parsed_expression_evaluates_to("root(-1,3)", ak); + Complex akd[1] = {Complex::Cartesian(0.5, 0.86602540378443864676)}; + assert_parsed_expression_evaluates_to("root(-1,3)", akd); +} + +QUIZ_CASE(poincare_function_simplify) { + assert_parsed_expression_simplify_to("abs(P)", "P"); + assert_parsed_expression_simplify_to("abs(-P)", "P"); + assert_parsed_expression_simplify_to("binomial(20,3)", "1140"); + assert_parsed_expression_simplify_to("binomial(20,10)", "184756"); + assert_parsed_expression_simplify_to("ceil(-1.3)", "-1"); + assert_parsed_expression_simplify_to("conj(1/2)", "1/2"); + assert_parsed_expression_simplify_to("quo(19,3)", "6"); + assert_parsed_expression_simplify_to("quo(19,0)", "undef"); + assert_parsed_expression_simplify_to("quo(-19,3)", "-7"); + assert_parsed_expression_simplify_to("rem(19,3)", "1"); + assert_parsed_expression_simplify_to("rem(-19,3)", "2"); + assert_parsed_expression_simplify_to("rem(19,0)", "undef"); + assert_parsed_expression_simplify_to("99!", "933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000"); + assert_parsed_expression_simplify_to("floor(-1.3)", "-2"); + assert_parsed_expression_simplify_to("frac(-1.3)", "7/10"); + assert_parsed_expression_simplify_to("gcd(123,278)", "1"); + assert_parsed_expression_simplify_to("gcd(11,121)", "11"); + assert_parsed_expression_simplify_to("lcm(123,278)", "34194"); + assert_parsed_expression_simplify_to("lcm(11,121)", "121"); + assert_parsed_expression_simplify_to("R(4)", "2"); + assert_parsed_expression_simplify_to("root(4,3)", "root(4,3)"); + assert_parsed_expression_simplify_to("root(4,P)", "4^(1/P)"); + assert_parsed_expression_simplify_to("root(27,3)", "3"); + assert_parsed_expression_simplify_to("round(4.235,2)", "106/25"); + assert_parsed_expression_simplify_to("round(4.23,0)", "4"); + assert_parsed_expression_simplify_to("round(4.9,0)", "5"); + assert_parsed_expression_simplify_to("round(12.9,-1)", "10"); + assert_parsed_expression_simplify_to("round(12.9,-2)", "0"); + assert_parsed_expression_simplify_to("permute(99,4)", "90345024"); + assert_parsed_expression_simplify_to("permute(20,-10)", "undef"); + assert_parsed_expression_simplify_to("re(1/2)", "1/2"); } diff --git a/poincare/test/helper.cpp b/poincare/test/helper.cpp index 279ec9931..103a68122 100644 --- a/poincare/test/helper.cpp +++ b/poincare/test/helper.cpp @@ -5,22 +5,45 @@ #include #include #include +#if POINCARE_TESTS_PRINT_EXPRESSIONS +#include "../src/expression_debug.h" +#include +using namespace std; +#endif using namespace Poincare; -Expression * parse_expression(const char * expression) { - quiz_print(expression); - char buffer[200]; - strlcpy(buffer, expression, sizeof(buffer)); - for (char *c = buffer; *c; c++) { +void translate_in_special_chars(char * expression) { + for (char *c = expression; *c; c++) { switch (*c) { case 'E': *c = Ion::Charset::Exponent; break; case 'X': *c = Ion::Charset::Exponential; break; case 'I': *c = Ion::Charset::IComplex; break; case 'R': *c = Ion::Charset::Root; break; case 'P': *c = Ion::Charset::SmallPi; break; + case '*': *c = Ion::Charset::MultiplicationSign; break; } } +} + +void translate_in_ASCII_chars(char * expression) { + for (char *c = expression; *c; c++) { + switch (*c) { + case Ion::Charset::Exponent: *c = 'E'; break; + case Ion::Charset::Exponential: *c = 'X'; break; + case Ion::Charset::IComplex: *c = 'I'; break; + case Ion::Charset::Root: *c = 'R'; break; + case Ion::Charset::SmallPi: *c = 'P'; break; + case Ion::Charset::MultiplicationSign: *c = '*'; break; + } + } +} + +Expression * parse_expression(const char * expression) { + quiz_print(expression); + char buffer[200]; + strlcpy(buffer, expression, sizeof(buffer)); + translate_in_special_chars(buffer); Expression * result = Expression::parse(buffer); assert(result); return result; @@ -36,22 +59,42 @@ template void assert_parsed_expression_evaluates_to(const char * expression, Complex * results, int numberOfRows, int numberOfColumns, Expression::AngleUnit angleUnit) { GlobalContext globalContext; Expression * a = parse_expression(expression); - Expression * m = a->evaluate(globalContext, angleUnit); + Expression * m = a->approximate(globalContext, angleUnit); assert(m); - assert(m->numberOfOperands() == numberOfRows*numberOfColumns); + assert(m->numberOfOperands() == 0 || m->numberOfOperands() == numberOfRows*numberOfColumns); if (m->type() == Expression::Type::Matrix) { assert(static_cast(m)->numberOfRows() == numberOfRows); assert(static_cast(m)->numberOfColumns() == numberOfColumns); - for (int i = 0; i < m->numberOfOperands(); i++) { - assert(std::fabs(static_cast *>(m->operand(i))->a() - results[i].a()) < 0.0001f); - assert(std::fabs(static_cast *>(m->operand(i))->b() - results[i].b()) < 0.0001f); + for (int i = 0; i < m->numberOfOperands(); i++) { + assert(std::fabs(static_cast *>(m->operand(i))->a() - results[i].a()) < 0.0001f); + assert(std::fabs(static_cast *>(m->operand(i))->b() - results[i].b()) < 0.0001f); + } + } else { + assert(std::fabs(static_cast *>(m)->a() - results[0].a()) < 0.0001f); + assert(std::fabs(static_cast *>(m)->b() - results[0].b()) < 0.0001f); } - } - assert(std::fabs(static_cast *>(m)->a() - results[0].a()) < 0.0001f); - assert(std::fabs(static_cast *>(m)->b() - results[0].b()) < 0.0001f); delete a; delete m; } +void assert_parsed_expression_simplify_to(const char * expression, const char * simplifiedExpression, Expression::AngleUnit angleUnit) { + GlobalContext globalContext; + Expression * e = parse_expression(expression); +#if POINCARE_TESTS_PRINT_EXPRESSIONS + cout << "---- Simplify: " << expression << "----" << endl; +#endif + Expression::Simplify(&e, globalContext, angleUnit); + char buffer[200]; + e->writeTextInBuffer(buffer, sizeof(buffer)); + translate_in_ASCII_chars(buffer); +#if POINCARE_TESTS_PRINT_EXPRESSIONS + print_expression(e, 0); + cout << "---- serialize to: " << buffer << " ----" << endl; + cout << "----- compared to: " << simplifiedExpression << " ----\n" << endl; +#endif + assert(strcmp(buffer, simplifiedExpression) == 0); + delete e; +} + template void assert_parsed_expression_evaluates_to(char const*, Poincare::Complex*, int, int, Poincare::Expression::AngleUnit); template void assert_parsed_expression_evaluates_to(char const*, Poincare::Complex*, int, int, Poincare::Expression::AngleUnit); diff --git a/poincare/test/helper.h b/poincare/test/helper.h index bb4e63350..d0b62e71f 100644 --- a/poincare/test/helper.h +++ b/poincare/test/helper.h @@ -3,11 +3,14 @@ constexpr Poincare::Expression::AngleUnit Degree = Poincare::Expression::AngleUnit::Degree; constexpr Poincare::Expression::AngleUnit Radian = Poincare::Expression::AngleUnit::Radian; +void translate_in_special_chars(char * expression); +void translate_in_ASCII_chars(char * expression); Poincare::Expression * parse_expression(const char * expression); void assert_parsed_expression_type(const char * expression, Poincare::Expression::Type type); template -void assert_parsed_expression_evaluates_to(const char * expression, Poincare::Complex * results, int numberOfRows, int numberOfColumns = 1, Poincare::Expression::AngleUnit angleUnit = Degree); +void assert_parsed_expression_evaluates_to(const char * expression, Poincare::Complex * results, int numberOfRows, int numberOfColumns, Poincare::Expression::AngleUnit angleUnit = Degree); template void assert_parsed_expression_evaluates_to(const char * expression, Poincare::Complex * results, Poincare::Expression::AngleUnit angleUnit = Degree) { - assert_parsed_expression_evaluates_to(expression, results, 1, 1, angleUnit); + assert_parsed_expression_evaluates_to(expression, results, 0, 0, angleUnit); } +void assert_parsed_expression_simplify_to(const char * expression, const char * simplifiedExpression, Poincare::Expression::AngleUnit angleUnit = Poincare::Expression::AngleUnit::Radian); diff --git a/poincare/test/integer.cpp b/poincare/test/integer.cpp index ee69159b4..6865d7c73 100644 --- a/poincare/test/integer.cpp +++ b/poincare/test/integer.cpp @@ -9,7 +9,7 @@ QUIZ_CASE(poincare_integer) { assert(Integer("123").isEqualTo(Integer(123))); assert(!Integer("-123").isEqualTo(Integer(123))); assert(Integer("-123").isEqualTo(Integer(-123))); - //assert(Integer("0123") == Integer(123)); + assert(Integer((int64_t)1234567891011121314).isEqualTo(Integer((int64_t)1234567891011121314))); //FIXME: assert(Integer("0x2BABE") == Integer(178878)); //FIXME: assert(Integer("0b1011") == Integer(11)); } diff --git a/poincare/test/logarithm.cpp b/poincare/test/logarithm.cpp new file mode 100644 index 000000000..3017142a3 --- /dev/null +++ b/poincare/test/logarithm.cpp @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include "helper.h" + +using namespace Poincare; + +QUIZ_CASE(poincare_logarithm_simplify) { + assert_parsed_expression_simplify_to("log(12925)", "2*log(5)+log(11)+log(47)"); + assert_parsed_expression_simplify_to("ln(12925)", "2*ln(5)+ln(11)+ln(47)"); + assert_parsed_expression_simplify_to("log(1742279/12925, 6)", "(-2*log(5,6))+log(7,6)+3*log(11,6)+log(17,6)-log(47,6)"); + assert_parsed_expression_simplify_to("ln(2/3)", "ln(2)-ln(3)"); + assert_parsed_expression_simplify_to("log(1742279/12925, -6)", "undef"); + assert_parsed_expression_simplify_to("ln(R(2))", "ln(2)/2"); + assert_parsed_expression_simplify_to("ln(X^3)", "3"); + assert_parsed_expression_simplify_to("log(10)", "1"); + assert_parsed_expression_simplify_to("log(R(3),R(3))", "1"); + assert_parsed_expression_simplify_to("log(1/R(2))", "-log(2)/2"); + assert_parsed_expression_simplify_to("log(-I)", "log(-I)"); + assert_parsed_expression_simplify_to("ln(X^(IP/7))", "(P*I)/7"); + assert_parsed_expression_simplify_to("log(10^24)", "24"); + assert_parsed_expression_simplify_to("log((23P)^4,23P)", "4"); + assert_parsed_expression_simplify_to("log(10^(2+P))", "2+P"); + assert_parsed_expression_simplify_to("ln(1881676377434183981909562699940347954480361860897069)", "ln(1881676377434183981909562699940347954480361860897069)"); + assert_parsed_expression_simplify_to("log(26061622162116)", "2*log(2)+log(3)+log(2171801846843)"); + assert_parsed_expression_simplify_to("log(26061622162116/5)", "2*log(2)+log(3)-log(5)+log(2171801846843)"); +} diff --git a/poincare/test/matrix.cpp b/poincare/test/matrix.cpp index 4e28f8ac6..25e354060 100644 --- a/poincare/test/matrix.cpp +++ b/poincare/test/matrix.cpp @@ -14,3 +14,99 @@ QUIZ_CASE(poincare_matrix_evaluate) { assert_parsed_expression_evaluates_to("[[1,2,3][4,5,6]]", b, 2, 3); #endif } + +QUIZ_CASE(poincare_matrix_simplify) { +#if MATRICES_ARE_DEFINED +#if MATRIX_EXACT_REDUCING + // Addition Matrix + assert_parsed_expression_simplify_to("1+[[1,2,3][4,5,6]]", "[[2,3,4][5,6,7]]"); + assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]+1", "[[2,3,4][5,6,7]]"); + assert_parsed_expression_simplify_to("[[1,2][3,4]]+[[1,2,3][4,5,6]]", "undef"); + assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]+[[1,2,3][4,5,6]]", "[[2,4,6][8,10,12]]"); + assert_parsed_expression_simplify_to("2+[[1,2,3][4,5,6]]+[[1,2,3][4,5,6]]", "[[4,6,8][10,12,14]]"); + assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]+cos(2)+[[1,2,3][4,5,6]]", "[[2+cos(2),4+cos(2),6+cos(2)][8+cos(2),10+cos(2),12+cos(2)]]"); + assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]+10+[[1,2,3][4,5,6]]+R(2)", "[[12+R(2),14+R(2),16+R(2)][18+R(2),20+R(2),22+R(2)]]"); + assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-1)+3", "inverse([[1,2][3,4]])+3"); + assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-3)+3", "inverse([[37,54][81,118]])+3"); + assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-3)+[[1,2][3,4]]", "inverse([[37,54][81,118]])+[[1,2][3,4]]"); + assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-3)+[[1,2][3,4]]+4+R(2)", "inverse([[37,54][81,118]])+[[5+R(2),6+R(2)][7+R(2),8+R(2)]]"); + + // Multiplication Matrix + assert_parsed_expression_simplify_to("2*[[1,2,3][4,5,6]]", "[[2,4,6][8,10,12]]"); + assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]*R(2)", "[[R(2),2R(2),3R(2)][4R(2),5R(2),6R(2)]]"); + assert_parsed_expression_simplify_to("[[1,2][3,4]]*[[1,2,3][4,5,6]]", "[[9, 12, 15][19, 26, 33]]"); + assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]*[[1,2][2,3][5,6]]", "[[20, 26][44, 59]]"); + assert_parsed_expression_simplify_to("[[1,2,3,4][4,5,6,5]]*[[1,2][2,3][5,6]]", "undef"); + assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-3)*[[1,2][3,4]]", "[[1,2][3,4]]^(-3)*[[1,2][3,4]]"); + assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-3)*[[1,2,3][3,4,5]]*[[1,2][3,2][4,5]]*4", "[[37,54][81,118]]^(-1)*[[76,84][140,156]]"); + assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-3)*[[1,2][3,4]]", "[[1,2][3,4]]^(-3)*[[1,2][3,4]]"); + + // Power Matrix + assert_parsed_expression_simplify_to("[[1,2,3][4,5,6][7,8,9]]^3", "[[468,576,684][1062,1305,1548][1656,2034,2412]]"); + assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]^(-1)", "undef"); + assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-1)", "[[1,2][3,4]]^(-1)"); // TODO: Implement matrix inverse for dim < 3 + + // Function on matrix + assert_parsed_expression_simplify_to("abs([[1,-2][3,4]])", "[[1,2][3,4]]"); + assert_parsed_expression_simplify_to("acos([[1/R(2),1/2][1,-1]])", "[[P/4,P/3][0,P]]"); + assert_parsed_expression_simplify_to("asin([[1/R(2),1/2][1,-1]])", "[[P/4,P/6][P/2,-P/2]]"); + assert_parsed_expression_simplify_to("atan([[R(3),1][1/R(3),-1]])", "[[P/3,P/4][P/6,-P/4]]"); + assert_parsed_expression_simplify_to("acos([[1/R(2),1/2][1,-1]])", "[[P/4,P/3][0,P]]"); + assert_parsed_expression_simplify_to("binomial([[1,-2][3,4]], 2)", "undef"); + assert_parsed_expression_simplify_to("ceil([[1/R(2),1/2][1,-1.3]])", "[[ceil(R(2)/2),1][1,-1]]"); + assert_parsed_expression_simplify_to("confidence(1/3, 25)", "[[2/15,8/15]]"); + assert_parsed_expression_simplify_to("confidence(45, 25)", "undef"); + assert_parsed_expression_simplify_to("confidence(1/3, -34)", "undef"); + assert_parsed_expression_simplify_to("conj([[1/R(2),1/2][1,-1]])", "[[conj(1/R(2)),1/2][1,-1]]"); + assert_parsed_expression_simplify_to("cos([[P/3,0][P/7,P/2]])", "[[1/2,1][cos(P/7),0]]"); + assert_parsed_expression_simplify_to("diff([[P/3,0][P/7,P/2]],3)", "undef"); + assert_parsed_expression_simplify_to("det([[1,2][3,4]])", "det([[1,2][3,4]])"); // TODO: implement determinant if dim < 3 + assert_parsed_expression_simplify_to("det([[2,2][3,4]])", "det([[2,2][3,4]])"); + assert_parsed_expression_simplify_to("det([[2,2][3,3]])", "det([[2,2][3,3]])"); + assert_parsed_expression_simplify_to("quo([[2,2][3,3]],2)", "undef"); + assert_parsed_expression_simplify_to("rem([[2,2][3,3]],2)", "undef"); + assert_parsed_expression_simplify_to("[[1,2][3,4]]!", "[[1,2][6,24]]"); + assert_parsed_expression_simplify_to("floor([[1/R(2),1/2][1,-1.3]])", "[[floor(R(2)/2),0][1,-2]]"); + assert_parsed_expression_simplify_to("frac([[1/R(2),1/2][1,-1.3]])", "[[frac(R(2)/2),1/2][0,0.7]]"); + assert_parsed_expression_simplify_to("gcd([[1/R(2),1/2][1,-1.3]], [[1]])", "undef"); + assert_parsed_expression_simplify_to("asinh([[1/R(2),1/2][1,-1]])", "[[asinh(1/R(2)),asinh(1/2)][asinh(1),asinh(-1)]]"); + assert_parsed_expression_simplify_to("atanh([[R(3),1][1/R(3),-1]])", "[[atanh(R(3)),atanh(1)][atanh(1/R(3)),atanh(-1)]]"); + assert_parsed_expression_simplify_to("acosh([[1/R(2),1/2][1,-1]])", "[[acosh(1/R(2)),acosh(1/2)][acosh(1),acosh(-1)]]"); + assert_parsed_expression_simplify_to("sinh([[1/R(2),1/2][1,-1]])", "[[sinh(1/R(2)),sinh(1/2)][sinh(1),sinh(-1)]]"); + assert_parsed_expression_simplify_to("tanh([[R(3),1][1/R(3),-1]])", "[[tanh(R(3)),tanh(1)][tanh(1/R(3)),tanh(-1)]]"); + assert_parsed_expression_simplify_to("cosh([[1/R(2),1/2][1,-1]])", "[[cosh(1/R(2)),cosh(1/2)][cosh(1),cosh(-1)]]"); + assert_parsed_expression_simplify_to("im([[1/R(2),1/2][1,-1]])", "[[im(1/R(2)),0][0,0]]"); + assert_parsed_expression_simplify_to("int([[P/3,0][P/7,P/2]],3,2)", "undef"); + assert_parsed_expression_simplify_to("lcm(2, [[1]])", "undef"); + assert_parsed_expression_simplify_to("log([[R(2),1/2][1,3]])", "[[(1/2)*log(2),-log(2)][0,log(3)]]"); + assert_parsed_expression_simplify_to("log([[1/R(2),1/2][1,-3]])", "undef"); + assert_parsed_expression_simplify_to("log([[1/R(2),1/2][1,-3]],3)", "undef"); + assert_parsed_expression_simplify_to("ln([[R(2),1/2][1,3]])", "[[(1/2)*ln(2),-ln(2)][0,ln(3)]]"); + assert_parsed_expression_simplify_to("log([[1/R(2),1/2][1,-3]])", "undef"); + assert_parsed_expression_simplify_to("dim([[1/R(2),1/2,3][2,1,-3]])", "[[2,3]]"); + assert_parsed_expression_simplify_to("inverse([[1/R(2),1/2,3][2,1,-3]])", "undef"); + assert_parsed_expression_simplify_to("inverse([[1,2][3,4]])", "inverse([[1,2][3,4]])"); // TODO: implement matrix inverse if dim < 3 + assert_parsed_expression_simplify_to("trace([[1/R(2),1/2,3][2,1,-3]])", "undef"); + assert_parsed_expression_simplify_to("trace([[R(2),2][4,3+log(3)]])", "R(2)+3+log(3)"); + assert_parsed_expression_simplify_to("trace(R(2)+log(3))", "R(2)+log(3)"); + assert_parsed_expression_simplify_to("transpose([[1/R(2),1/2,3][2,1,-3]])", "[[1/R(2),2][1/2, 1][3,-3]]"); + assert_parsed_expression_simplify_to("transpose(R(4))", "2"); + assert_parsed_expression_simplify_to("root([[R(4)]],2)", "undef"); + assert_parsed_expression_simplify_to("root(4,3)", "4^(1/3)"); + assert_parsed_expression_simplify_to("-[[1/R(2),1/2,3][2,1,-3]]", "[[-1/R(2),-1/2,-3][-2,-1,3]]"); + assert_parsed_expression_simplify_to("permute([[1,-2][3,4]], 2)", "undef"); + assert_parsed_expression_simplify_to("prediction95(1/3, 25)", "[[1/3-49R(2)/375,1/3+49R(2)/375]]"); + assert_parsed_expression_simplify_to("prediction95(45, 25)", "undef"); + assert_parsed_expression_simplify_to("prediction95(1/3, -34)", "undef"); + assert_parsed_expression_simplify_to("product([[1,2][3,4]], 1/3, -34)", "product([[1,2][3,4]], 1/3, -34)"); + assert_parsed_expression_simplify_to("sum([[1,2][3,4]], 1/3, -34)", "sum([[1,2][3,4]], 1/3, -34)"); + assert_parsed_expression_simplify_to("re([[1/R(2),1/2][1,-1]])", "[[re(1/R(2)),1/2][1,-1]]"); + assert_parsed_expression_simplify_to("round([[1/R(2),1/2][1,-1]],2)", "undef"); + assert_parsed_expression_simplify_to("sin([[P/3,0][P/7,P/2]])", "[[R(3)/2,0][sin(P/7),1]]"); + assert_parsed_expression_simplify_to("R([[4,2][P/7,1]])", "[[2,R(2)][R(P/7),1]]"); + assert_parsed_expression_simplify_to("tan([[P/3,0][P/7,P/6]])", "[[R(3),0][tan(P/7),R(3)/3]]"); +#else + assert_parsed_expression_simplify_to("R([[4,2][P/7,1]])", "R([[4,2][P/7,1]])"); +#endif +#endif +} diff --git a/poincare/test/multiplication.cpp b/poincare/test/multiplication.cpp new file mode 100644 index 000000000..4b706b855 --- /dev/null +++ b/poincare/test/multiplication.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include "helper.h" + +using namespace Poincare; + +QUIZ_CASE(poincare_multiplication_evaluate) { + Complex a[1] = {Complex::Float(2.0f)}; + assert_parsed_expression_evaluates_to("1*2", a); + + Complex b[1] = {Complex::Cartesian(11.0, 7.0)}; + assert_parsed_expression_evaluates_to("(3+I)*(4+I)", b); + +#if MATRICES_ARE_DEFINED + Complex c[6] = {Complex::Float(2.0f), Complex::Float(4.0f), Complex::Float(6.0f), Complex::Float(8.0f), Complex::Float(10.0f), Complex::Float(12.0f)}; + assert_parsed_expression_evaluates_to("[[1,2][3,4][5,6]]*2", c, 3, 2); + + Complex d[6] = {Complex::Cartesian(3.0, 1.0), Complex::Cartesian(5.0, 5.0), Complex::Cartesian(9.0, 3.0), Complex::Cartesian(12.0, 4.0), Complex::Cartesian(15.0, 5.0), Complex::Cartesian(18.0, 6.0)}; + assert_parsed_expression_evaluates_to("[[1,2+I][3,4][5,6]]*(3+I)", d, 3, 2); + + assert_parsed_expression_evaluates_to("2*[[1,2][3,4][5,6]]", c, 3, 2); + + assert_parsed_expression_evaluates_to("(3+I)*[[1,2+I][3,4][5,6]]", d, 3, 2); + + Complex e[12] = {Complex::Float(11.0f), Complex::Float(14.0f), Complex::Float(17.0f), Complex::Float(20.0f), Complex::Float(23.0f), Complex::Float(30.0f), Complex::Float(37.0f), Complex::Float(44.0f), Complex::Float(35.0f), Complex::Float(46.0f), Complex::Float(57.0f), Complex::Float(68.0f)}; + assert_parsed_expression_evaluates_to("[[1,2][3,4][5,6]]*[[1,2,3,4][5,6,7,8]]", e, 3, 4); + + Complex f[12] = {Complex::Cartesian(11.0, 5.0), Complex::Cartesian(13.0, 9.0), Complex::Cartesian(17.0, 7.0), Complex::Cartesian(20.0, 8.0), Complex::Cartesian(23.0, 0.0), Complex::Cartesian(30.0, 7.0), Complex::Cartesian(37.0, 0.0), Complex::Cartesian(44.0, 0.0), Complex::Cartesian(35.0, 0.0), Complex::Cartesian(46.0, 11.0), Complex::Cartesian(57.0, 0.0), Complex::Cartesian(68.0, 0.0)}; + assert_parsed_expression_evaluates_to("[[1,2+I][3,4][5,6]]*[[1,2+I,3,4][5,6+I,7,8]]", f, 3, 4); +#endif +} + +QUIZ_CASE(poincare_multiplication_simplify) { + assert_parsed_expression_simplify_to("0*x+B", "B"); + assert_parsed_expression_simplify_to("0*x*0*32*cos(3)", "0"); + assert_parsed_expression_simplify_to("3*A^4*B^x*B^2*(A^2+2)*2*1.2", "(72*A^4*B^(2+x)+36*A^6*B^(2+x))/5"); + assert_parsed_expression_simplify_to("A*(B+C)*(D+3)", "3*A*B+3*A*C+A*B*D+A*C*D"); + assert_parsed_expression_simplify_to("A/B", "A/B"); + assert_parsed_expression_simplify_to("(A*B)^2", "A^2*B^2"); + assert_parsed_expression_simplify_to("(1/2)*A/B", "A/(2*B)"); + assert_parsed_expression_simplify_to("1+2+3+4+5+6", "21"); + assert_parsed_expression_simplify_to("1-2+3-4+5-6", "-3"); + assert_parsed_expression_simplify_to("987654321123456789*998877665544332211", "986545842648570754445552922919330479"); + assert_parsed_expression_simplify_to("2/3", "2/3"); + assert_parsed_expression_simplify_to("9/17+5/4", "121/68"); + assert_parsed_expression_simplify_to("1/2*3/4", "3/8"); + assert_parsed_expression_simplify_to("0*2/3", "0"); + assert_parsed_expression_simplify_to("1+(1/(1+1/(1+1/(1+1))))", "8/5"); + assert_parsed_expression_simplify_to("1+2/(3+4/(5+6/(7+8)))", "155/101"); + assert_parsed_expression_simplify_to("3/4*16/12", "1"); + assert_parsed_expression_simplify_to("3/4*(8+8)/12", "1"); + assert_parsed_expression_simplify_to("916791/794976477", "305597/264992159"); + assert_parsed_expression_simplify_to("321654987123456789/112233445566778899", "3249040273974311/1133671167341201"); + assert_parsed_expression_simplify_to("0.1+0.2", "3/10"); + assert_parsed_expression_simplify_to("2^3", "8"); + assert_parsed_expression_simplify_to("(-1)*(-1)", "1"); + assert_parsed_expression_simplify_to("(-2)^2", "4"); + assert_parsed_expression_simplify_to("(-3)^3", "-27"); + assert_parsed_expression_simplify_to("(1/2)^-1", "2"); + assert_parsed_expression_simplify_to("R(2)*R(3)", "R(6)"); + assert_parsed_expression_simplify_to("2*2^P", "2*2^P"); + assert_parsed_expression_simplify_to("A^3*B*A^(-3)", "B"); + assert_parsed_expression_simplify_to("A^3*A^(-3)", "1"); + assert_parsed_expression_simplify_to("2^P*(1/2)^P", "1"); + assert_parsed_expression_simplify_to("A^3*A^(-3)", "1"); + assert_parsed_expression_simplify_to("(x+1)*(x+2)", "2+3*x+x^2"); + assert_parsed_expression_simplify_to("(x+1)*(x-1)", "(-1)+x^2"); + assert_parsed_expression_simplify_to("11P/(22P+11P)", "1/3"); + assert_parsed_expression_simplify_to("11/(22P+11P)", "1/(3*P)"); + assert_parsed_expression_simplify_to("-11/(22P+11P)", "-1/(3*P)"); + assert_parsed_expression_simplify_to("A^2*BA^(-2)*B^(-2)", "1/B"); + assert_parsed_expression_simplify_to("A^(-1)*B^(-1)", "1/(A*B)"); + assert_parsed_expression_simplify_to("x+x", "2*x"); + assert_parsed_expression_simplify_to("2*x+x", "3*x"); + assert_parsed_expression_simplify_to("x*2+x", "3*x"); + assert_parsed_expression_simplify_to("2*x+2*x", "4*x"); + assert_parsed_expression_simplify_to("x*2+2*n", "2*n+2*x"); + assert_parsed_expression_simplify_to("x+x+n+n", "2*n+2*x"); + assert_parsed_expression_simplify_to("x-x-n+n", "0"); + assert_parsed_expression_simplify_to("x+n-x-n", "0"); + assert_parsed_expression_simplify_to("x-x", "0"); +} diff --git a/poincare/test/power.cpp b/poincare/test/power.cpp index d8d875c8e..fd238d4ed 100644 --- a/poincare/test/power.cpp +++ b/poincare/test/power.cpp @@ -28,3 +28,52 @@ QUIZ_CASE(poincare_power_evaluate) { Complex f[1] = {Complex::Float(std::exp(-M_PI_2))}; assert_parsed_expression_evaluates_to("I^I", f); } + +QUIZ_CASE(poincare_power_simplify) { + assert_parsed_expression_simplify_to("3^4", "81"); + assert_parsed_expression_simplify_to("3^(-4)", "1/81"); + assert_parsed_expression_simplify_to("1256^(1/3)*x", "2*root(157,3)*x"); + assert_parsed_expression_simplify_to("1256^(-1/3)", "1/(2*root(157,3))"); + assert_parsed_expression_simplify_to("32^(-1/5)", "1/2"); + assert_parsed_expression_simplify_to("(2+3-4)^(x)", "1"); + assert_parsed_expression_simplify_to("1^x", "1"); + assert_parsed_expression_simplify_to("x^1", "x"); + assert_parsed_expression_simplify_to("0^3", "0"); + assert_parsed_expression_simplify_to("0^0", "undef"); + assert_parsed_expression_simplify_to("0^(-3)", "undef"); + assert_parsed_expression_simplify_to("4^0.5", "2"); + assert_parsed_expression_simplify_to("8^0.5", "2*R(2)"); + assert_parsed_expression_simplify_to("(12^4*3)^(0.5)", "144*R(3)"); + assert_parsed_expression_simplify_to("(2^A)^B", "2^(A*B)"); + assert_parsed_expression_simplify_to("(2*A)^B", "2^B*A^B"); + assert_parsed_expression_simplify_to("(12^4*x)^(0.5)", "144*R(x)"); + assert_parsed_expression_simplify_to("R(32)", "4*R(2)"); + assert_parsed_expression_simplify_to("R(3^2)", "3"); + assert_parsed_expression_simplify_to("2^(2+P)", "4*2^P"); + assert_parsed_expression_simplify_to("R(5513219850886344455940081)", "2348024669991"); + assert_parsed_expression_simplify_to("R(154355776)", "12424"); + assert_parsed_expression_simplify_to("R(P)^2", "P"); + assert_parsed_expression_simplify_to("R(P^2)", "P"); + assert_parsed_expression_simplify_to("R((-P)^2)", "P"); + assert_parsed_expression_simplify_to("R(x*144)", "12*R(x)"); + assert_parsed_expression_simplify_to("R(x*144*P^2)", "12*R(x)*P"); + assert_parsed_expression_simplify_to("R(x*144*P)", "12*R(x)*R(P)"); + assert_parsed_expression_simplify_to("x^(1/2)", "R(x)"); + assert_parsed_expression_simplify_to("x^(-1/2)", "1/R(x)"); + assert_parsed_expression_simplify_to("x^(1/7)", "root(x,7)"); + assert_parsed_expression_simplify_to("x^(-1/7)", "1/root(x,7)"); + assert_parsed_expression_simplify_to("1/(3R(2))", "R(2)/6"); + assert_parsed_expression_simplify_to("X^ln(3)", "3"); + assert_parsed_expression_simplify_to("X^ln(R(3))", "R(3)"); + assert_parsed_expression_simplify_to("P^log(R(3),P)", "R(3)"); + assert_parsed_expression_simplify_to("10^log(P)", "P"); + assert_parsed_expression_simplify_to("X^ln(65)", "65"); + assert_parsed_expression_simplify_to("X^ln(PX)", "P*X"); + assert_parsed_expression_simplify_to("X^log(PX)", "X^(log(P)+log(X))"); + assert_parsed_expression_simplify_to("R(X^2)", "X"); + assert_parsed_expression_simplify_to("999^(10000/3)", "999^(10000/3)"); + /* This does not reduce but should not as the integer is above + * k_maxNumberOfPrimeFactors and thus it prime decomposition might overflow + * 32 factors. */ + assert_parsed_expression_simplify_to("1881676377434183981909562699940347954480361860897069^(1/3)", "root(1881676377434183981909562699940347954480361860897069,3)"); +} diff --git a/poincare/test/product.cpp b/poincare/test/product.cpp deleted file mode 100644 index 21ac7c038..000000000 --- a/poincare/test/product.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include -#include -#include "helper.h" - -using namespace Poincare; - -QUIZ_CASE(poincare_product_evaluate) { - Complex a[1] = {Complex::Float(2.0f)}; - assert_parsed_expression_evaluates_to("1*2", a); - - Complex b[1] = {Complex::Cartesian(11.0, 7.0)}; - assert_parsed_expression_evaluates_to("(3+I)*(4+I)", b); - -#if MATRICES_ARE_DEFINED - Complex c[6] = {Complex::Float(2.0f), Complex::Float(4.0f), Complex::Float(6.0f), Complex::Float(8.0f), Complex::Float(10.0f), Complex::Float(12.0f)}; - assert_parsed_expression_evaluates_to("[[1,2][3,4][5,6]]*2", c, 3, 2); - - Complex d[6] = {Complex::Cartesian(3.0, 1.0), Complex::Cartesian(5.0, 5.0), Complex::Cartesian(9.0, 3.0), Complex::Cartesian(12.0, 4.0), Complex::Cartesian(15.0, 5.0), Complex::Cartesian(18.0, 6.0)}; - assert_parsed_expression_evaluates_to("[[1,2+I][3,4][5,6]]*(3+I)", d, 3, 2); - - assert_parsed_expression_evaluates_to("2*[[1,2][3,4][5,6]]", c, 3, 2); - - assert_parsed_expression_evaluates_to("(3+I)*[[1,2+I][3,4][5,6]]", d, 3, 2); - - Complex e[12] = {Complex::Float(11.0f), Complex::Float(14.0f), Complex::Float(17.0f), Complex::Float(20.0f), Complex::Float(23.0f), Complex::Float(30.0f), Complex::Float(37.0f), Complex::Float(44.0f), Complex::Float(35.0f), Complex::Float(46.0f), Complex::Float(57.0f), Complex::Float(68.0f)}; - assert_parsed_expression_evaluates_to("[[1,2][3,4][5,6]]*[[1,2,3,4][5,6,7,8]]", e, 3, 4); - - Complex f[12] = {Complex::Cartesian(11.0, 5.0), Complex::Cartesian(13.0, 9.0), Complex::Cartesian(17.0, 7.0), Complex::Cartesian(20.0, 8.0), Complex::Cartesian(23.0, 0.0), Complex::Cartesian(30.0, 7.0), Complex::Cartesian(37.0, 0.0), Complex::Cartesian(44.0, 0.0), Complex::Cartesian(35.0, 0.0), Complex::Cartesian(46.0, 11.0), Complex::Cartesian(57.0, 0.0), Complex::Cartesian(68.0, 0.0)}; - assert_parsed_expression_evaluates_to("[[1,2+I][3,4][5,6]]*[[1,2+I,3,4][5,6+I,7,8]]", f, 3, 4); -#endif -} diff --git a/poincare/test/rational.cpp b/poincare/test/rational.cpp new file mode 100644 index 000000000..6a0f9c4a6 --- /dev/null +++ b/poincare/test/rational.cpp @@ -0,0 +1,54 @@ +#include +#include +#include +#include "helper.h" + +using namespace Poincare; + +QUIZ_CASE(poincare_rational_sign) { + assert(Rational(-2).sign() == Expression::Sign::Negative); + assert(Rational(-2, 3).sign() == Expression::Sign::Negative); + assert(Rational(2, 3).sign() == Expression::Sign::Positive); +} + +QUIZ_CASE(poincare_rational_compare) { + assert(Rational::NaturalOrder(Rational(123, 234),Rational(456, 567)) < 0); + assert(Rational::NaturalOrder(Rational(-123, 234),Rational(456, 567)) < 0); + assert(Rational::NaturalOrder(Rational(123, 234),Rational(-456, 567)) > 0); + assert(Rational::NaturalOrder(Rational(123, 234),Rational("123456789123456789", "12345678912345678910")) > 0); +} + +QUIZ_CASE(poincare_rational_evaluate) { + Complex a[1] = {Complex::Float(0.333333333f)}; + assert_parsed_expression_evaluates_to("1/3", a); + Complex b[1] = {Complex::Float(0.099999)}; + assert_parsed_expression_evaluates_to("123456/1234567", b); +} + +QUIZ_CASE(poincare_rational_simplify) { + assert_parsed_expression_simplify_to("-1/3", "-1/3"); + assert_parsed_expression_simplify_to("22355/45325", "4471/9065"); + assert_parsed_expression_simplify_to("0000.000000", "0"); + assert_parsed_expression_simplify_to(".000000", "0"); + assert_parsed_expression_simplify_to("0000", "0"); + assert_parsed_expression_simplify_to("0.1234567", "1234567/10000000"); + assert_parsed_expression_simplify_to("123.4567", "1234567/10000"); + assert_parsed_expression_simplify_to("0.1234", "617/5000"); + assert_parsed_expression_simplify_to("0.1234000", "617/5000"); + assert_parsed_expression_simplify_to("001234000", "1234000"); + assert_parsed_expression_simplify_to("001.234000E3", "1234"); + assert_parsed_expression_simplify_to("001234000E-4", "617/5"); + assert_parsed_expression_simplify_to("3/4+5/4-12+1/567", "-5669/567"); + assert_parsed_expression_simplify_to("34/78+67^(-1)", "1178/2613"); + assert_parsed_expression_simplify_to("12348/34564", "3087/8641"); + assert_parsed_expression_simplify_to("1-0.3-0.7", "0"); + assert_parsed_expression_simplify_to("123456789123456789+112233445566778899", "235690234690235688"); + assert_parsed_expression_simplify_to("56^56", "79164324866862966607842406018063254671922245312646690223362402918484170424104310169552592050323456"); + assert_parsed_expression_simplify_to("999^999", "999^999"); + assert_parsed_expression_simplify_to("999^-999", "1/999^999"); + assert_parsed_expression_simplify_to("0^0", "undef"); + assert_parsed_expression_simplify_to("x^0", "1"); + assert_parsed_expression_simplify_to("P^0", "1"); + assert_parsed_expression_simplify_to("A^0", "1"); + assert_parsed_expression_simplify_to("(-3)^0", "1"); +} diff --git a/poincare/test/simplify_addition.cpp b/poincare/test/simplify_addition.cpp deleted file mode 100644 index 0c9b0eb4b..000000000 --- a/poincare/test/simplify_addition.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include "simplify_utils.h" - -using namespace Poincare; - -QUIZ_CASE(poincare_simplify_addition_integer) { - assert(simplifies_to("1", "1")); - assert(simplifies_to("1+2", "3")); - assert(simplifies_to("1+A", "1+A")); - assert(simplifies_to("1+2+3+4+5+6+7", "28")); - assert(simplifies_to("1+2+3+4+5+A+6+7", "28+A")); - assert(simplifies_to("A*(0+0)", "0")); -} diff --git a/poincare/test/simplify_easy.cpp b/poincare/test/simplify_easy.cpp deleted file mode 100644 index 3cd135ba1..000000000 --- a/poincare/test/simplify_easy.cpp +++ /dev/null @@ -1,506 +0,0 @@ -#include -#include -#include -#include -#include "helper.h" -#if POINCARE_TESTS_PRINT_EXPRESSIONS -#include "../src/expression_debug.h" -#include -using namespace std; -#endif - -using namespace Poincare; - -void assert_parsed_expression_simplify_to(const char * expression, const char * simplifiedExpression, Expression::AngleUnit angleUnit = Expression::AngleUnit::Radian) { - GlobalContext globalContext; - Expression * e = parse_expression(expression); -#if POINCARE_TESTS_PRINT_EXPRESSIONS - cout << "---- Simplify: " << expression << "----" << endl; -#endif - Expression::Simplify(&e, globalContext, angleUnit); -#if POINCARE_TESTS_PRINT_EXPRESSIONS - print_expression(e, 0); -#endif - Expression * f = parse_expression(simplifiedExpression); - Expression::Simplify(&f, globalContext, angleUnit); -#if POINCARE_TESTS_PRINT_EXPRESSIONS - cout << "---- compared to: " << simplifiedExpression << "----" << endl; - print_expression(f, 0); -#endif - assert(e->isIdenticalTo(f)); - delete e; - delete f; -} - -QUIZ_CASE(poincare_simplify_easy) { - //assert_parsed_expression_simplify_to("(((R(6)-R(2))/4)/((R(6)+R(2))/4))+1", "((1/2)*R(6))/((R(6)+R(2))/4)"); - // Addition Matrix -#if MATRIX_EXACT_REDUCING - assert_parsed_expression_simplify_to("1+[[1,2,3][4,5,6]]", "[[2,3,4][5,6,7]]"); - assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]+1", "[[2,3,4][5,6,7]]"); - assert_parsed_expression_simplify_to("[[1,2][3,4]]+[[1,2,3][4,5,6]]", "undef"); - assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]+[[1,2,3][4,5,6]]", "[[2,4,6][8,10,12]]"); - assert_parsed_expression_simplify_to("2+[[1,2,3][4,5,6]]+[[1,2,3][4,5,6]]", "[[4,6,8][10,12,14]]"); - assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]+cos(2)+[[1,2,3][4,5,6]]", "[[2+cos(2),4+cos(2),6+cos(2)][8+cos(2),10+cos(2),12+cos(2)]]"); - assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]+10+[[1,2,3][4,5,6]]+R(2)", "[[12+R(2),14+R(2),16+R(2)][18+R(2),20+R(2),22+R(2)]]"); - assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-1)+3", "inverse([[1,2][3,4]])+3"); - assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-3)+3", "inverse([[37,54][81,118]])+3"); - assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-3)+[[1,2][3,4]]", "inverse([[37,54][81,118]])+[[1,2][3,4]]"); - assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-3)+[[1,2][3,4]]+4+R(2)", "inverse([[37,54][81,118]])+[[5+R(2),6+R(2)][7+R(2),8+R(2)]]"); - - // Multiplication Matrix - assert_parsed_expression_simplify_to("2*[[1,2,3][4,5,6]]", "[[2,4,6][8,10,12]]"); - assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]*R(2)", "[[R(2),2R(2),3R(2)][4R(2),5R(2),6R(2)]]"); - assert_parsed_expression_simplify_to("[[1,2][3,4]]*[[1,2,3][4,5,6]]", "[[9, 12, 15][19, 26, 33]]"); - assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]*[[1,2][2,3][5,6]]", "[[20, 26][44, 59]]"); - assert_parsed_expression_simplify_to("[[1,2,3,4][4,5,6,5]]*[[1,2][2,3][5,6]]", "undef"); - assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-3)*[[1,2][3,4]]", "[[1,2][3,4]]^(-3)*[[1,2][3,4]]"); - assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-3)*[[1,2,3][3,4,5]]*[[1,2][3,2][4,5]]*4", "[[37,54][81,118]]^(-1)*[[76,84][140,156]]"); - assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-3)*[[1,2][3,4]]", "[[1,2][3,4]]^(-3)*[[1,2][3,4]]"); - - // Power Matrix - assert_parsed_expression_simplify_to("[[1,2,3][4,5,6][7,8,9]]^3", "[[468,576,684][1062,1305,1548][1656,2034,2412]]"); - assert_parsed_expression_simplify_to("[[1,2,3][4,5,6]]^(-1)", "undef"); - assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-1)", "[[1,2][3,4]]^(-1)"); // TODO: Implement matrix inverse for dim < 3 - - // Function on matrix - assert_parsed_expression_simplify_to("abs([[1,-2][3,4]])", "[[1,2][3,4]]"); - assert_parsed_expression_simplify_to("acos([[1/R(2),1/2][1,-1]])", "[[P/4,P/3][0,P]]"); - assert_parsed_expression_simplify_to("asin([[1/R(2),1/2][1,-1]])", "[[P/4,P/6][P/2,-P/2]]"); - assert_parsed_expression_simplify_to("atan([[R(3),1][1/R(3),-1]])", "[[P/3,P/4][P/6,-P/4]]"); - assert_parsed_expression_simplify_to("acos([[1/R(2),1/2][1,-1]])", "[[P/4,P/3][0,P]]"); - assert_parsed_expression_simplify_to("binomial([[1,-2][3,4]], 2)", "undef"); - assert_parsed_expression_simplify_to("ceil([[1/R(2),1/2][1,-1.3]])", "[[ceil(R(2)/2),1][1,-1]]"); - assert_parsed_expression_simplify_to("confidence(1/3, 25)", "[[2/15,8/15]]"); - assert_parsed_expression_simplify_to("confidence(45, 25)", "undef"); - assert_parsed_expression_simplify_to("confidence(1/3, -34)", "undef"); - assert_parsed_expression_simplify_to("conj([[1/R(2),1/2][1,-1]])", "[[conj(1/R(2)),1/2][1,-1]]"); - assert_parsed_expression_simplify_to("cos([[P/3,0][P/7,P/2]])", "[[1/2,1][cos(P/7),0]]"); - assert_parsed_expression_simplify_to("diff([[P/3,0][P/7,P/2]],3)", "undef"); - assert_parsed_expression_simplify_to("det([[1,2][3,4]])", "det([[1,2][3,4]])"); // TODO: implement determinant if dim < 3 - assert_parsed_expression_simplify_to("det([[2,2][3,4]])", "det([[2,2][3,4]])"); - assert_parsed_expression_simplify_to("det([[2,2][3,3]])", "det([[2,2][3,3]])"); - assert_parsed_expression_simplify_to("quo([[2,2][3,3]],2)", "undef"); - assert_parsed_expression_simplify_to("rem([[2,2][3,3]],2)", "undef"); - assert_parsed_expression_simplify_to("[[1,2][3,4]]!", "[[1,2][6,24]]"); - assert_parsed_expression_simplify_to("floor([[1/R(2),1/2][1,-1.3]])", "[[floor(R(2)/2),0][1,-2]]"); - assert_parsed_expression_simplify_to("frac([[1/R(2),1/2][1,-1.3]])", "[[frac(R(2)/2),1/2][0,0.7]]"); - assert_parsed_expression_simplify_to("gcd([[1/R(2),1/2][1,-1.3]], [[1]])", "undef"); - assert_parsed_expression_simplify_to("asinh([[1/R(2),1/2][1,-1]])", "[[asinh(1/R(2)),asinh(1/2)][asinh(1),asinh(-1)]]"); - assert_parsed_expression_simplify_to("atanh([[R(3),1][1/R(3),-1]])", "[[atanh(R(3)),atanh(1)][atanh(1/R(3)),atanh(-1)]]"); - assert_parsed_expression_simplify_to("acosh([[1/R(2),1/2][1,-1]])", "[[acosh(1/R(2)),acosh(1/2)][acosh(1),acosh(-1)]]"); - assert_parsed_expression_simplify_to("sinh([[1/R(2),1/2][1,-1]])", "[[sinh(1/R(2)),sinh(1/2)][sinh(1),sinh(-1)]]"); - assert_parsed_expression_simplify_to("tanh([[R(3),1][1/R(3),-1]])", "[[tanh(R(3)),tanh(1)][tanh(1/R(3)),tanh(-1)]]"); - assert_parsed_expression_simplify_to("cosh([[1/R(2),1/2][1,-1]])", "[[cosh(1/R(2)),cosh(1/2)][cosh(1),cosh(-1)]]"); - assert_parsed_expression_simplify_to("im([[1/R(2),1/2][1,-1]])", "[[im(1/R(2)),0][0,0]]"); - assert_parsed_expression_simplify_to("int([[P/3,0][P/7,P/2]],3,2)", "undef"); - assert_parsed_expression_simplify_to("lcm(2, [[1]])", "undef"); - assert_parsed_expression_simplify_to("log([[R(2),1/2][1,3]])", "[[(1/2)*log(2),-log(2)][0,log(3)]]"); - assert_parsed_expression_simplify_to("log([[1/R(2),1/2][1,-3]])", "undef"); - assert_parsed_expression_simplify_to("log([[1/R(2),1/2][1,-3]],3)", "undef"); - assert_parsed_expression_simplify_to("ln([[R(2),1/2][1,3]])", "[[(1/2)*ln(2),-ln(2)][0,ln(3)]]"); - assert_parsed_expression_simplify_to("log([[1/R(2),1/2][1,-3]])", "undef"); - assert_parsed_expression_simplify_to("dim([[1/R(2),1/2,3][2,1,-3]])", "[[2,3]]"); - assert_parsed_expression_simplify_to("inverse([[1/R(2),1/2,3][2,1,-3]])", "undef"); - assert_parsed_expression_simplify_to("inverse([[1,2][3,4]])", "inverse([[1,2][3,4]])"); // TODO: implement matrix inverse if dim < 3 - assert_parsed_expression_simplify_to("trace([[1/R(2),1/2,3][2,1,-3]])", "undef"); - assert_parsed_expression_simplify_to("trace([[R(2),2][4,3+log(3)]])", "R(2)+3+log(3)"); - assert_parsed_expression_simplify_to("trace(R(2)+log(3))", "R(2)+log(3)"); - assert_parsed_expression_simplify_to("transpose([[1/R(2),1/2,3][2,1,-3]])", "[[1/R(2),2][1/2, 1][3,-3]]"); - assert_parsed_expression_simplify_to("transpose(R(4))", "2"); - assert_parsed_expression_simplify_to("root([[R(4)]],2)", "undef"); - assert_parsed_expression_simplify_to("root(4,3)", "4^(1/3)"); - assert_parsed_expression_simplify_to("-[[1/R(2),1/2,3][2,1,-3]]", "[[-1/R(2),-1/2,-3][-2,-1,3]]"); - assert_parsed_expression_simplify_to("permute([[1,-2][3,4]], 2)", "undef"); - assert_parsed_expression_simplify_to("prediction95(1/3, 25)", "[[1/3-49R(2)/375,1/3+49R(2)/375]]"); - assert_parsed_expression_simplify_to("prediction95(45, 25)", "undef"); - assert_parsed_expression_simplify_to("prediction95(1/3, -34)", "undef"); - assert_parsed_expression_simplify_to("product([[1,2][3,4]], 1/3, -34)", "product([[1,2][3,4]], 1/3, -34)"); - assert_parsed_expression_simplify_to("sum([[1,2][3,4]], 1/3, -34)", "sum([[1,2][3,4]], 1/3, -34)"); - assert_parsed_expression_simplify_to("re([[1/R(2),1/2][1,-1]])", "[[re(1/R(2)),1/2][1,-1]]"); - assert_parsed_expression_simplify_to("round([[1/R(2),1/2][1,-1]],2)", "undef"); - assert_parsed_expression_simplify_to("sin([[P/3,0][P/7,P/2]])", "[[R(3)/2,0][sin(P/7),1]]"); - assert_parsed_expression_simplify_to("R([[4,2][P/7,1]])", "[[2,R(2)][R(P/7),1]]"); - assert_parsed_expression_simplify_to("tan([[P/3,0][P/7,P/6]])", "[[R(3),0][tan(P/7),R(3)/3]]"); -#else - assert_parsed_expression_simplify_to("R([[4,2][P/7,1]])", "R([[4,2][P/7,1]])"); -#endif - /* Complex */ - assert_parsed_expression_simplify_to("I", "I"); - assert_parsed_expression_simplify_to("R(-33)", "R(33)*I"); - assert_parsed_expression_simplify_to("I^(3/5)", "X^(IP3/10)"); - - //Functions - assert_parsed_expression_simplify_to("binomial(20,3)", "1140"); - assert_parsed_expression_simplify_to("binomial(20,10)", "184756"); - assert_parsed_expression_simplify_to("ceil(-1.3)", "-1"); - assert_parsed_expression_simplify_to("conj(1/2)", "1/2"); - assert_parsed_expression_simplify_to("quo(19,3)", "6"); - assert_parsed_expression_simplify_to("quo(19,0)", "undef"); - assert_parsed_expression_simplify_to("quo(-19,3)", "-7"); - assert_parsed_expression_simplify_to("rem(19,3)", "1"); - assert_parsed_expression_simplify_to("rem(-19,3)", "2"); - assert_parsed_expression_simplify_to("rem(19,0)", "undef"); - assert_parsed_expression_simplify_to("99!", "933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000"); - assert_parsed_expression_simplify_to("floor(-1.3)", "-2"); - assert_parsed_expression_simplify_to("frac(-1.3)", "0.7"); - assert_parsed_expression_simplify_to("gcd(123,278)", "1"); - assert_parsed_expression_simplify_to("gcd(11,121)", "11"); - assert_parsed_expression_simplify_to("lcm(123,278)", "34194"); - assert_parsed_expression_simplify_to("lcm(11,121)", "121"); - assert_parsed_expression_simplify_to("root(4,3)", "4^(1/3)"); - assert_parsed_expression_simplify_to("permute(99,4)", "90345024"); - assert_parsed_expression_simplify_to("permute(20,-10)", "undef"); - assert_parsed_expression_simplify_to("re(1/2)", "1/2"); - - assert_parsed_expression_simplify_to("1*tan(2)*tan(5)", "tan(2)*tan(5)"); - assert_parsed_expression_simplify_to("P+(3R(2)-2R(3))/25", "(3R(2)-2R(3)+25P)/25"); - assert_parsed_expression_simplify_to("-1/3", "-1/3"); - assert_parsed_expression_simplify_to("2+13cos(2)-23cos(2)", "2-10cos(2)"); - assert_parsed_expression_simplify_to("1/(R(2)+R(3))", "-(R(2)-R(3))"); - assert_parsed_expression_simplify_to("1/(5+R(3))", "(5-R(3))/22"); - assert_parsed_expression_simplify_to("1/(R(2)+4)", "(4-R(2))/14"); - assert_parsed_expression_simplify_to("1/(2R(2)-4)", "-R(2)/4-1/2"); - assert_parsed_expression_simplify_to("1/(-2R(2)+4)", "R(2)/4+1/2"); - assert_parsed_expression_simplify_to("5!", "120"); - assert_parsed_expression_simplify_to("1/3!", "1/6"); - assert_parsed_expression_simplify_to("(1/3)!", "undef"); - assert_parsed_expression_simplify_to("P!", "undef"); - assert_parsed_expression_simplify_to("X!", "undef"); - assert_parsed_expression_simplify_to("tan(62P/21)", "-tan(P/21)"); - assert_parsed_expression_simplify_to("cos(26P/21)/sin(25P/17)", "cos(5P/21)/sin(8P/17)"); - assert_parsed_expression_simplify_to("cos(62P/21)*P*3/sin(62P/21)", "-3P/tan(P/21)"); - assert_parsed_expression_simplify_to("cos(62P/21)/(P*3sin(62P/21))", "-1/(3Ptan(P/21))"); - assert_parsed_expression_simplify_to("sin(62P/21)*P*3/cos(62P/21)", "-3Ptan(P/21)"); - assert_parsed_expression_simplify_to("sin(62P/21)/(P*3cos(62P/21))", "-tan(P/21)/(3P)"); - assert_parsed_expression_simplify_to("-cos(P/62)ln(3)/(sin(P/62)P)", "-ln(3)/(tan(P/62)P)"); - assert_parsed_expression_simplify_to("-2cos(P/62)ln(3)/(sin(P/62)P)", "-2ln(3)/(tan(P/62)P)"); - assert_parsed_expression_simplify_to("0000.000000", "0"); - assert_parsed_expression_simplify_to(".000000", "0"); - assert_parsed_expression_simplify_to("0000", "0"); - assert_parsed_expression_simplify_to("0.1234567", "1234567/10000000"); - assert_parsed_expression_simplify_to("123.4567", "1234567/10000"); - assert_parsed_expression_simplify_to("0.1234", "1234/10000"); - assert_parsed_expression_simplify_to("0.1234000", "1234/10000"); - assert_parsed_expression_simplify_to("001234000", "1234000"); - assert_parsed_expression_simplify_to("001.234000E3", "1234"); - assert_parsed_expression_simplify_to("001234000E-4", "1234/10"); - assert_parsed_expression_simplify_to("1+1+ln(2)+(5+3*2)/9-4/7+1/98", "ln(2)+2347/882"); - assert_parsed_expression_simplify_to("1+1+ln(2)+(5+3*2)/9-4/7+1/98", "ln(2)+2347/882"); - assert_parsed_expression_simplify_to("1+1+ln(2)+(5+3*2)/9-4/7+1/98", "ln(2)+2347/882"); - assert_parsed_expression_simplify_to("3/4+5/4-12+1/567", "-5669/567"); - assert_parsed_expression_simplify_to("34/78+67^(-1)", "1178/2613"); - assert_parsed_expression_simplify_to("root(4,5)", "4^(1/5)"); - assert_parsed_expression_simplify_to("R(4)", "2"); - assert_parsed_expression_simplify_to("3^4", "81"); - assert_parsed_expression_simplify_to("3^(-4)", "1/81"); - assert_parsed_expression_simplify_to("12348/34564", "3087/8641"); - assert_parsed_expression_simplify_to("1256^(1/3)*x", "2*157^(1/3)*x"); - assert_parsed_expression_simplify_to("1256^(-1/3)", "2^(-1)*157^(-1/3)"); - assert_parsed_expression_simplify_to("32^(-1/5)", "1/2"); - assert_parsed_expression_simplify_to("ln(2+3)", "ln(5)"); - assert_parsed_expression_simplify_to("1-0.3-0.7", "0"); - assert_parsed_expression_simplify_to("(2+3-4)^(x)", "1"); - assert_parsed_expression_simplify_to("1^x", "1"); - assert_parsed_expression_simplify_to("x^1", "x"); - assert_parsed_expression_simplify_to("0^3", "0"); - assert_parsed_expression_simplify_to("0^0", "1"); - assert_parsed_expression_simplify_to("0^(-3)", "undef"); - assert_parsed_expression_simplify_to("0*x+B", "B"); - assert_parsed_expression_simplify_to("0*x*0*32*cos(3)", "0"); - assert_parsed_expression_simplify_to("1+2+0+cos(2)", "3+cos(2)"); - assert_parsed_expression_simplify_to("2+0", "2"); - assert_parsed_expression_simplify_to("3*A*B*C+4*cos(2)-2*A*B*C+A*B*C+ln(3)+4*A*B-5*A*B*C+cos(3)*ln(5)+cos(2)-45*cos(2)", "-3ABC+4AB-40cos(2)+cos(3)ln(5)+ln(3)"); - assert_parsed_expression_simplify_to("2*A+3*cos(2)+3+4*ln(5)+5*A+2*ln(5)+1+0", "7A+3cos(2)+6ln(5)+4"); - assert_parsed_expression_simplify_to("2.3*A+3*cos(2)+3+4*ln(5)+5*A+2*ln(5)+1.2+0.235", "73*A/10+3cos(2)+6ln(5)+4435/1000"); - assert_parsed_expression_simplify_to("2*A*B*C+2.3*A*B+3*A^2+5.2*A*B*C+4*A^2", "36/5*ABC+23/10*AB+7A^2"); - assert_parsed_expression_simplify_to("3*A^4*B^x*B^2*(A^2+2)*2*1.2", "36/5*A^6*B^(x+2)+72/5*A^4*B^(x+2)"); - assert_parsed_expression_simplify_to("A*(B+C)*(D+3)", "ABD+3AB+ACD+3AC"); - assert_parsed_expression_simplify_to("A/B", "A/B"); - assert_parsed_expression_simplify_to("-5P+3P", "-2P"); - assert_parsed_expression_simplify_to("(A*B)^2", "A^2*B^2"); - assert_parsed_expression_simplify_to("(A*B)^2*A+4*A^3", "A^3*B^2+4A^3"); - assert_parsed_expression_simplify_to("(A*3)^2*A+4*A^3", "13A^3"); - assert_parsed_expression_simplify_to("A^2^2*A+4*A^3", "A^5+4A^3"); - assert_parsed_expression_simplify_to("4^0.5", "2"); - assert_parsed_expression_simplify_to("8^0.5", "2R(2)"); - assert_parsed_expression_simplify_to("(12^4*3)^(0.5)", "144*R(3)"); - assert_parsed_expression_simplify_to("(2^A)^B", "2^(AB)"); - assert_parsed_expression_simplify_to("(2*A)^B", "2^B*A^B"); - assert_parsed_expression_simplify_to("(12^4*x)^(0.5)", "144R(x)"); - assert_parsed_expression_simplify_to("45^2", "2025"); - assert_parsed_expression_simplify_to("1-3+A-5+2A-4A", "-7-A"); - assert_parsed_expression_simplify_to("(1/2)*A/B", "A/(2B)"); - assert_parsed_expression_simplify_to("0.5+4*A*B-2.3+2*A*B-2*B*A^C-cos(4)+2*A^C*B+A*B*C*D", "ABCD+6AB-cos(4)-9/5"); - assert_parsed_expression_simplify_to("1+2", "3"); - assert_parsed_expression_simplify_to("123456789123456789+112233445566778899", "235690234690235688"); - assert_parsed_expression_simplify_to("1+2+3+4+5+6", "21"); - assert_parsed_expression_simplify_to("1-2+3-4+5-6", "-3"); - assert_parsed_expression_simplify_to("987654321123456789*998877665544332211", "986545842648570754445552922919330479"); - assert_parsed_expression_simplify_to("2/3", "2/3"); - assert_parsed_expression_simplify_to("9/17+5/4", "121/68"); - assert_parsed_expression_simplify_to("1/2*3/4", "3/8"); - assert_parsed_expression_simplify_to("0*2/3", "0"); - assert_parsed_expression_simplify_to("1+(1/(1+1/(1+1/(1+1))))", "8/5"); - assert_parsed_expression_simplify_to("1+2/(3+4/(5+6/(7+8)))", "155/101"); - assert_parsed_expression_simplify_to("3/4*16/12", "1"); - assert_parsed_expression_simplify_to("3/4*(8+8)/12", "1"); - assert_parsed_expression_simplify_to("916791/794976477", "305597/264992159"); - assert_parsed_expression_simplify_to("321654987123456789/112233445566778899", "3249040273974311/1133671167341201"); - assert_parsed_expression_simplify_to("0.1+0.2", "3/10"); - assert_parsed_expression_simplify_to("2^3", "8"); - assert_parsed_expression_simplify_to("(-1)*(-1)", "1"); - assert_parsed_expression_simplify_to("(-2)^2", "4"); - assert_parsed_expression_simplify_to("(-3)^3", "-27"); - assert_parsed_expression_simplify_to("(1/2)^-1", "2"); - assert_parsed_expression_simplify_to("R(32)", "4*R(2)"); - assert_parsed_expression_simplify_to("R(3^2)", "3"); - assert_parsed_expression_simplify_to("2^(2+P)", "4*2^P"); - assert_parsed_expression_simplify_to("R(15241578780673678515622620750190521)", "123456789123456789"); - assert_parsed_expression_simplify_to("R(P)^2", "P"); - assert_parsed_expression_simplify_to("R(P^2)", "P"); - assert_parsed_expression_simplify_to("R((-P)^2)", "P"); - assert_parsed_expression_simplify_to("R(x*144)", "12*R(x)"); - assert_parsed_expression_simplify_to("R(x*144*P^2)", "12*P*R(x)"); - assert_parsed_expression_simplify_to("R(x*144*P)", "12*R(xP)"); - assert_parsed_expression_simplify_to("abs(P)", "P"); - assert_parsed_expression_simplify_to("abs(-P)", "P"); - assert_parsed_expression_simplify_to("R(2)*R(3)", "R(6)"); - assert_parsed_expression_simplify_to("2*2^P", "2*2^P"); - assert_parsed_expression_simplify_to("A-A", "0"); - assert_parsed_expression_simplify_to("A-A+2cos(2)+B-B-cos(2)", "cos(2)"); - assert_parsed_expression_simplify_to("A^3*B*A^(-3)", "B"); - assert_parsed_expression_simplify_to("A^3*A^(-3)", "1"); - assert_parsed_expression_simplify_to("2^P*(1/2)^P", "1"); - assert_parsed_expression_simplify_to("A^3*A^(-3)", "1"); - assert_parsed_expression_simplify_to("1+A+2+B+3", "6+A+B"); - assert_parsed_expression_simplify_to("(x+1)*(x+2)", "x^2+3x+2"); - - assert_parsed_expression_simplify_to("(x+1)*(x-1)", "-1+x^2"); - assert_parsed_expression_simplify_to("11P/(22P+11P)", "1/3"); - assert_parsed_expression_simplify_to("11/(22P+11P)", "1/(3P)"); - assert_parsed_expression_simplify_to("A^2*BA^(-2)*B^(-2)", "1/B"); - assert_parsed_expression_simplify_to("A^(-1)*B^(-1)", "1/(AB)"); - assert_parsed_expression_simplify_to("-11/(22P+11P)", "-1/(3P)"); - assert_parsed_expression_simplify_to("-A", "-A"); - assert_parsed_expression_simplify_to("1/(x+1)+1/(P+2)", "(P+x+3)/((x+1)(P+2))"); - assert_parsed_expression_simplify_to("1/x^2+1/(x^2*P)", "(P+1)/(x^2*P)"); - assert_parsed_expression_simplify_to("1/x^2+1/(x^3*P)", "(Px+1)/(x^3*P)"); - assert_parsed_expression_simplify_to("4x/x^2+3P/(x^3*P)", "(4*x^2*P+3P)/(x^3*P)"); - assert_parsed_expression_simplify_to("x^(1/2)", "R(x)"); - assert_parsed_expression_simplify_to("x^(-1/2)", "1/R(x)"); - assert_parsed_expression_simplify_to("x^(1/7)", "root(x, 7)"); - assert_parsed_expression_simplify_to("x^(-1/7)", "1/root(x, 7)"); - assert_parsed_expression_simplify_to("log(12925)", "log(47)+log(11)+2*log(5)"); - assert_parsed_expression_simplify_to("ln(12925)", "ln(47)+ln(11)+2*ln(5)"); - assert_parsed_expression_simplify_to("log(1742279/12925, 6)", "log(7, 6)+3log(11, 6)+log(17,6)-log(47,6)-2*log(5,6)"); - assert_parsed_expression_simplify_to("ln(2/3)", "ln(2)-ln(3)"); - assert_parsed_expression_simplify_to("log(1742279/12925, -6)", "undef"); - assert_parsed_expression_simplify_to("(1+R(2))/5", "(1+R(2))/5"); - assert_parsed_expression_simplify_to("(2+R(6))^2", "(2+R(6))^2"); // Check for parenthesis - assert_parsed_expression_simplify_to("cos(0)", "1"); - assert_parsed_expression_simplify_to("cos(P)", "-1"); - assert_parsed_expression_simplify_to("cos(P*4/7)", "-cos(3P/7)"); - assert_parsed_expression_simplify_to("cos(P*35/29)", "-cos(P*6/29)"); - assert_parsed_expression_simplify_to("cos(-P*35/29)", "-cos(P*6/29)"); - assert_parsed_expression_simplify_to("cos(P*340000)", "1"); - assert_parsed_expression_simplify_to("cos(-P*340001)", "-1"); - assert_parsed_expression_simplify_to("cos(-P*R(2))", "cos(P*R(2))"); - assert_parsed_expression_simplify_to("cos(1311P/6)", "0"); - assert_parsed_expression_simplify_to("cos(P/12)", "(R(6)+R(2))/4"); - assert_parsed_expression_simplify_to("cos(-P/12)", "(R(6)+R(2))/4"); - assert_parsed_expression_simplify_to("cos(-P17/8)", "R(R(2)+2)/2"); - assert_parsed_expression_simplify_to("cos(41P/6)", "-R(3)/2"); - assert_parsed_expression_simplify_to("cos(P/4+1000P)", "R(2)/2"); - assert_parsed_expression_simplify_to("cos(-P/3)", "1/2"); - assert_parsed_expression_simplify_to("cos(41P/5)", "(5^(1/2)+1)*4^(-1)"); - assert_parsed_expression_simplify_to("cos(7P/10)", "-R(5/8-R(5)/8)"); - assert_parsed_expression_simplify_to("sin(0)", "0"); - assert_parsed_expression_simplify_to("sin(P)", "0"); - assert_parsed_expression_simplify_to("sin(P*35/29)", "-sin(P*6/29)"); - assert_parsed_expression_simplify_to("sin(-P*35/29)", "sin(P*6/29)"); - assert_parsed_expression_simplify_to("sin(P*340000)", "0"); - assert_parsed_expression_simplify_to("sin(P*340001)", "0"); - assert_parsed_expression_simplify_to("sin(-P*340001)", "0"); - assert_parsed_expression_simplify_to("sin(P/12)", "(R(6)-R(2))/4"); - assert_parsed_expression_simplify_to("sin(-P/12)", "(R(2)-R(6))/4"); - assert_parsed_expression_simplify_to("sin(-P*R(2))", "-sin(P*R(2))"); - assert_parsed_expression_simplify_to("sin(1311P/6)", "1"); - assert_parsed_expression_simplify_to("sin(-P17/8)", "-R(-R(2)+2)/2"); - assert_parsed_expression_simplify_to("sin(41P/6)", "1/2"); - assert_parsed_expression_simplify_to("sin(-3P/10)", "(-1-R(5))/4"); - assert_parsed_expression_simplify_to("sin(P/4+1000P)", "R(2)/2"); - assert_parsed_expression_simplify_to("sin(-P/3)", "-R(3)/2"); - assert_parsed_expression_simplify_to("sin(17P/5)", "-R(5/8+R(5)/8)"); - assert_parsed_expression_simplify_to("sin(P/5)", "R(5/8-R(5)/8)"); - - assert_parsed_expression_simplify_to("tan(0)", "0"); - assert_parsed_expression_simplify_to("tan(P)", "0"); - assert_parsed_expression_simplify_to("tan(P*35/29)", "tan(P*6/29)"); - assert_parsed_expression_simplify_to("tan(-P*35/29)", "-tan(P*6/29)"); - assert_parsed_expression_simplify_to("tan(P*340000)", "0"); - assert_parsed_expression_simplify_to("tan(P*340001)", "0"); - assert_parsed_expression_simplify_to("tan(-P*340001)", "0"); - assert_parsed_expression_simplify_to("tan(P/12)", "2-R(3)"); - assert_parsed_expression_simplify_to("tan(-P/12)", "R(3)-2"); - assert_parsed_expression_simplify_to("tan(-P*R(2))", "-tan(P*R(2))"); - assert_parsed_expression_simplify_to("tan(1311P/6)", "undef"); - assert_parsed_expression_simplify_to("tan(-P17/8)", "1-R(2)"); - assert_parsed_expression_simplify_to("tan(41P/6)", "-1/R(3)"); - assert_parsed_expression_simplify_to("tan(P/4+1000P)", "1"); - assert_parsed_expression_simplify_to("tan(-P/3)", "-R(3)"); - assert_parsed_expression_simplify_to("tan(-P/10)", "-R(1-2/R(5))"); - assert_parsed_expression_simplify_to("sin(x)/cos(x)", "tan(x)"); - assert_parsed_expression_simplify_to("cos(x)/sin(x)", "1/tan(x)"); - assert_parsed_expression_simplify_to("sin(x)*P/cos(x)", "P*tan(x)"); - assert_parsed_expression_simplify_to("sin(x)/(P*cos(x))", "tan(x)/P"); - assert_parsed_expression_simplify_to("56^56", "79164324866862966607842406018063254671922245312646690223362402918484170424104310169552592050323456"); - - assert_parsed_expression_simplify_to("acos(-1/2)", "P*2*3^(-1)"); - assert_parsed_expression_simplify_to("acos(-1.2)", "undef"); - assert_parsed_expression_simplify_to("acos(cos(2/3))", "2/3"); - assert_parsed_expression_simplify_to("acos(cos(3/2))", "3/2"); - assert_parsed_expression_simplify_to("cos(acos(3/2))", "undef"); - assert_parsed_expression_simplify_to("cos(acos(2/3))", "2/3"); - assert_parsed_expression_simplify_to("acos(cos(12))", "acos(cos(12))"); - assert_parsed_expression_simplify_to("acos(cos(4P/7))", "4P/7"); - assert_parsed_expression_simplify_to("acos(-cos(2))", "P-2"); - assert_parsed_expression_simplify_to("asin(-1/2)", "P*(-6)^(-1)"); - assert_parsed_expression_simplify_to("asin(-1.2)", "undef"); - assert_parsed_expression_simplify_to("asin(sin(2/3))", "2/3"); - assert_parsed_expression_simplify_to("sin(asin(2/3))", "2/3"); - assert_parsed_expression_simplify_to("sin(asin(3/2))", "sin(asin(3/2))"); - assert_parsed_expression_simplify_to("asin(sin(3/2))", "3/2"); - assert_parsed_expression_simplify_to("asin(sin(12))", "asin(sin(12))"); - assert_parsed_expression_simplify_to("asin(sin(-P/7))", "-P/7"); - assert_parsed_expression_simplify_to("asin(sin(-R(2)))", "-R(2)"); - assert_parsed_expression_simplify_to("atan(-1)", "P*(-4)^(-1)"); - assert_parsed_expression_simplify_to("atan(-1.2)", "atan(-1.2)"); - assert_parsed_expression_simplify_to("atan(tan(2/3))", "2/3"); - assert_parsed_expression_simplify_to("tan(atan(2/3))", "2/3"); - assert_parsed_expression_simplify_to("tan(atan(5/2))", "5/2"); - assert_parsed_expression_simplify_to("atan(tan(5/2))", "atan(tan(5/2))"); - assert_parsed_expression_simplify_to("atan(tan(5/2))", "atan(tan(5/2))"); - assert_parsed_expression_simplify_to("atan(tan(-P/7))", "-P/7"); - assert_parsed_expression_simplify_to("atan(R(3))", "P/3"); - assert_parsed_expression_simplify_to("atan(tan(-R(2)))", "-R(2)"); - - assert_parsed_expression_simplify_to("cos(0)", "1", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(180)", "-1", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(720/7)", "-cos(540/7)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(6300/29)", "-cos(1080/29)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(-6300/29)", "-cos(1080/29)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(61200000)", "1", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(-61200180)", "-1", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(-180*R(2))", "cos(180*R(2))", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(39330)", "0", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(15)", "(R(6)+R(2))/4", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(-15)", "(R(6)+R(2))/4", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(-765/2)", "R(R(2)+2)/2", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(7380/6)", "-R(3)/2", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(180045)", "R(2)/2", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(-60)", "1/2", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(7380/5)", "(5^(1/2)+1)*4^(-1)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(112.5)", "-R(2-R(2))/2", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(0)", "0", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(180)", "0", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(6300/29)", "-sin(1080/29)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(-6300/29)", "sin(1080/29)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(61200000)", "0", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(61200180)", "0", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(-61200180)", "0", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(15)", "(R(6)-R(2))/4", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(-15)", "(R(2)-R(6))/4", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(-180*R(2))", "-sin(180*R(2))", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(39330)", "1", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(-765/2)", "-R(-R(2)+2)/2", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(1230)", "1/2", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(180045)", "R(2)/2", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(-60)", "-R(3)/2", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(612)", "-R(5/8+R(5)/8)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(36)", "R(5/8-R(5)/8)", Expression::AngleUnit::Degree); - - assert_parsed_expression_simplify_to("tan(0)", "0", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(180)", "0", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(6300/29)", "tan(1080/29)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(-6300/29)", "-tan(1080/29)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(61200000)", "0", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(61200180)", "0", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(-61200180)", "0", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(15)", "2-R(3)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(-15)", "R(3)-2", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(-180*R(2))", "-tan(180*R(2))", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(39330)", "undef", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(-382.5)", "1-R(2)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(1230)", "-1/R(3)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(180045)", "1", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(-60)", "-R(3)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("acos(-1/2)", "120", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("acos(-1.2)", "undef", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("acos(cos(2/3))", "2/3", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("acos(cos(190))", "acos(cos(190))", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("acos(cos(75))", "75", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(acos(190))", "undef", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("cos(acos(75))", "undef", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("acos(cos(12))", "12", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("acos(cos(720/7))", "720/7", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("asin(-1/2)", "-30", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("asin(-1.2)", "undef", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("asin(sin(75))", "75", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(asin(75))", "undef", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("sin(asin(190))", "sin(asin(190))", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("asin(sin(32))", "32", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("asin(sin(400))", "asin(sin(400))", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("asin(sin(-180/7))", "-180/7", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("atan(-1)", "-45", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("atan(-1.2)", "atan(-1.2)", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("atan(tan(-45))", "-45", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(atan(120))", "120", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("tan(atan(2293))", "2293", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("atan(tan(2293))", "-47", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("atan(tan(1808))", "8", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("atan(tan(-180/7))", "-180/7", Expression::AngleUnit::Degree); - assert_parsed_expression_simplify_to("atan(R(3))", "60", Expression::AngleUnit::Degree); - - assert_parsed_expression_simplify_to("1/(3R(2))", "R(2)/6"); - assert_parsed_expression_simplify_to("1/(R(2)ln(3))", "R(2)/(2ln(3))"); - - - assert_parsed_expression_simplify_to("A+B-A-B", "0"); - assert_parsed_expression_simplify_to("A+B+(-1)*A+(-1)*B", "0"); - assert_parsed_expression_simplify_to("ln(R(2))", "ln(2)/2"); - assert_parsed_expression_simplify_to("R(3/2)", "R(6)/2"); - assert_parsed_expression_simplify_to("tan(3)ln(2)+P", "tan(3)ln(2)+P"); - assert_parsed_expression_simplify_to("ln(X^3)", "3"); - assert_parsed_expression_simplify_to("log(10)", "1"); - assert_parsed_expression_simplify_to("log(R(3),R(3))", "1"); - assert_parsed_expression_simplify_to("X^ln(3)", "3"); - assert_parsed_expression_simplify_to("X^ln(R(3))", "R(3)"); - assert_parsed_expression_simplify_to("P^log(R(3),P)", "R(3)"); - assert_parsed_expression_simplify_to("10^log(P)", "P"); - assert_parsed_expression_simplify_to("log(1/R(2))", "-log(2)/2"); - assert_parsed_expression_simplify_to("log(-I)", "log(-I)"); - assert_parsed_expression_simplify_to("R(-I)", "R(-I)"); - assert_parsed_expression_simplify_to("X^ln(65)", "65"); - assert_parsed_expression_simplify_to("X^ln(PX)", "PX"); - assert_parsed_expression_simplify_to("X^log(PX)", "X^(log(P)+log(X))"); - assert_parsed_expression_simplify_to("R(X^2)", "X"); - assert_parsed_expression_simplify_to("ln(X^(IP/7))", "IP/7"); - assert_parsed_expression_simplify_to("log(10^24)", "24"); - assert_parsed_expression_simplify_to("log((23P)^4,23P)", "4"); - assert_parsed_expression_simplify_to("log(10^(2+P))", "2+P"); - - //assert_parsed_expression_simplify_to("log(cos(9)^ln(6), cos(9))", "ln(2)+ln(3)"); // TODO: for this to work, we must know the sign of cos(9) - //assert_parsed_expression_simplify_to("log(cos(9)^ln(6), 9)", "ln(6)*log(cos(9), 9)"); // TODO: for this to work, we must know the sign of cos(9) - assert_parsed_expression_simplify_to("IIII", "1"); - assert_parsed_expression_simplify_to("Acos(9)IIln(2)", "-Acos(9)ln(2)"); - assert_parsed_expression_simplify_to("(R(2)+R(2)*I)/2(R(2)+R(2)*I)/2(R(2)+R(2)*I)/2", "(R(2)+R(2)*I)/(2(2R(2)+2R(2)*I)^2)"); - assert_parsed_expression_simplify_to("tan(tan(tan(tan(9))))", "tan(tan(tan(tan(9))))"); - assert_parsed_expression_simplify_to("999^999", "999^999"); - assert_parsed_expression_simplify_to("999^(10000/3)", "999^(10000/3)"); - - /* This does not work but should not as it is above k_primorial32 = 1*3*5*7*11*... (product of first 32 primes. */ - //assert_parsed_expression_simplify_to("1881676377434183981909562699940347954480361860897069^(1/3)", "123456789123456789"); - - //assert_parsed_expression_simplify_to("1/sqrt(2)", "sqrt(2)/2"); -} diff --git a/poincare/test/simplify_mix.cpp b/poincare/test/simplify_mix.cpp new file mode 100644 index 000000000..fb4e05453 --- /dev/null +++ b/poincare/test/simplify_mix.cpp @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include "helper.h" +#if POINCARE_TESTS_PRINT_EXPRESSIONS +#include "../src/expression_debug.h" +#include +using namespace std; +#endif + +using namespace Poincare; + +QUIZ_CASE(poincare_simplify_mix) { + + // Root at denominator + assert_parsed_expression_simplify_to("1/(R(2)+R(3))", "(-R(2))+R(3)"); + assert_parsed_expression_simplify_to("1/(5+R(3))", "(5-R(3))/22"); + assert_parsed_expression_simplify_to("1/(R(2)+4)", "(4-R(2))/14"); + assert_parsed_expression_simplify_to("1/(2R(2)-4)", "((-2)-R(2))/4"); + assert_parsed_expression_simplify_to("1/(-2R(2)+4)", "(2+R(2))/4"); + assert_parsed_expression_simplify_to("45^2", "2025"); + assert_parsed_expression_simplify_to("1/(R(2)ln(3))", "R(2)/(2*ln(3))"); + assert_parsed_expression_simplify_to("R(3/2)", "R(6)/2"); + + // Common operation mix + assert_parsed_expression_simplify_to("(R(2)*P + R(2)*X)/R(2)", "P+X"); + assert_parsed_expression_simplify_to("P+(3R(2)-2R(3))/25", "(3*R(2)-2*R(3)+25*P)/25"); + assert_parsed_expression_simplify_to("ln(2+3)", "ln(5)"); + assert_parsed_expression_simplify_to("3*A*B*C+4*cos(2)-2*A*B*C+A*B*C+ln(3)+4*A*B-5*A*B*C+cos(3)*ln(5)+cos(2)-45*cos(2)", "(-40*cos(2))+ln(3)+cos(3)*ln(5)+4*A*B-3*A*B*C"); + assert_parsed_expression_simplify_to("2*A+3*cos(2)+3+4*ln(5)+5*A+2*ln(5)+1+0", "4+3*cos(2)+6*ln(5)+7*A"); + assert_parsed_expression_simplify_to("2.3*A+3*cos(2)+3+4*ln(5)+5*A+2*ln(5)+1.2+0.235", "(887+600*cos(2)+1200*ln(5)+1460*A)/200"); + assert_parsed_expression_simplify_to("2*A*B*C+2.3*A*B+3*A^2+5.2*A*B*C+4*A^2", "(70*A^2+23*A*B+72*A*B*C)/10"); + assert_parsed_expression_simplify_to("(A*B)^2*A+4*A^3", "4*A^3+A^3*B^2"); + assert_parsed_expression_simplify_to("(A*3)^2*A+4*A^3", "13*A^3"); + assert_parsed_expression_simplify_to("A^2^2*A+4*A^3", "4*A^3+A^5"); + assert_parsed_expression_simplify_to("0.5+4*A*B-2.3+2*A*B-2*B*A^C-cos(4)+2*A^C*B+A*B*C*D", "((-9)-5*cos(4)+30*A*B+5*A*B*C*D)/5"); + assert_parsed_expression_simplify_to("(1+R(2))/5", "(1+R(2))/5"); + assert_parsed_expression_simplify_to("(2+R(6))^2", "(2+R(6))^2"); + assert_parsed_expression_simplify_to("tan(3)ln(2)+P", "tan(3)*ln(2)+P"); + + + //assert_parsed_expression_simplify_to("log(cos(9)^ln(6), cos(9))", "ln(2)+ln(3)"); // TODO: for this to work, we must know the sign of cos(9) + //assert_parsed_expression_simplify_to("log(cos(9)^ln(6), 9)", "ln(6)*log(cos(9), 9)"); // TODO: for this to work, we must know the sign of cos(9) + //assert_parsed_expression_simplify_to("(((R(6)-R(2))/4)/((R(6)+R(2))/4))+1", "((1/2)*R(6))/((R(6)+R(2))/4)"); // TODO: Newton binome + //assert_parsed_expression_simplify_to("1/R(I) * (R(2)-I*R(2))", "-2I"); // TODO: get rid of complex at denominator? + +} diff --git a/poincare/test/simplify_product.cpp b/poincare/test/simplify_product.cpp deleted file mode 100644 index ce1207271..000000000 --- a/poincare/test/simplify_product.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include "simplify_utils.h" - -using namespace Poincare; - -QUIZ_CASE(poincare_simplify_product_by_zero) { - assert(simplifies_to("3*0", "0")); - assert(simplifies_to("A*0", "0")); - - assert(simplifies_to("0*3", "0")); - assert(simplifies_to("0*A", "0")); - - assert(simplifies_to("3*5", "15")); - assert(simplifies_to("8*6", "48")); - - assert(simplifies_to("3*(5+4)", "27")); -} - -QUIZ_CASE(poincare_simplify_distributive_reverse) { - assert(equivalent_to("x+x", "2*x")); - assert(equivalent_to("2*x+x", "3*x")); - assert(equivalent_to("x*2+x", "3*x")); - assert(equivalent_to("2*x+2*x", "4*x")); - assert(equivalent_to("x*2+2*t", "2*(x+t)")); - assert(equivalent_to("x+x+t+t", "2*x+2*t")); - assert(equivalent_to("2*x+2*t", "2*(x+t)")); - //assert(equivalent_to("x+x+t+t", "2*(x+t)")); - assert(equivalent_to("x-x-t+t", "0)")); - assert(equivalent_to("x+t-x-t", "0")); - assert(equivalent_to("x+x*t", "x*(t+1)")); - assert(equivalent_to("x-x", "0")); - assert(equivalent_to("x-x", "0")); -} diff --git a/poincare/test/symbol.cpp b/poincare/test/symbol.cpp index 36222cf3a..8183cb388 100644 --- a/poincare/test/symbol.cpp +++ b/poincare/test/symbol.cpp @@ -10,8 +10,8 @@ using namespace Poincare; QUIZ_CASE(poincare_parse_symbol) { assert_parsed_expression_type("P", Expression::Type::Symbol); assert_parsed_expression_type("X", Expression::Type::Symbol); - assert_parsed_expression_type("I", Expression::Type::Complex); - assert_parsed_expression_type("1.2E3", Expression::Type::Complex); + assert_parsed_expression_type("I", Expression::Type::Symbol); + assert_parsed_expression_type("1.2E3", Expression::Type::Decimal); assert_parsed_expression_type("ans", Expression::Type::Symbol); } diff --git a/poincare/test/trigo.cpp b/poincare/test/trigo.cpp index 0ba08252e..ce6822008 100644 --- a/poincare/test/trigo.cpp +++ b/poincare/test/trigo.cpp @@ -47,3 +47,181 @@ QUIZ_CASE(poincare_trigo_evaluate) { Complex c3[1] = {Complex::Cartesian(-1.00027905623446556836909f, 0.000610240921376259f)}; assert_parsed_expression_evaluates_to("tanh(I-4)", c3, Radian); } + +QUIZ_CASE(poincare_trigo_simplify) { + // -- sin/cos -> tan + assert_parsed_expression_simplify_to("sin(x)/cos(x)", "tan(x)"); + assert_parsed_expression_simplify_to("cos(x)/sin(x)", "1/tan(x)"); + assert_parsed_expression_simplify_to("sin(x)*P/cos(x)", "tan(x)*P"); + assert_parsed_expression_simplify_to("sin(x)/(P*cos(x))", "tan(x)/P"); + assert_parsed_expression_simplify_to("1*tan(2)*tan(5)", "tan(2)*tan(5)"); + assert_parsed_expression_simplify_to("tan(62P/21)", "-tan(P/21)"); + assert_parsed_expression_simplify_to("cos(26P/21)/sin(25P/17)", "cos((5*P)/21)/sin((8*P)/17)"); + assert_parsed_expression_simplify_to("cos(62P/21)*P*3/sin(62P/21)", "-(3*P)/tan(P/21)"); + assert_parsed_expression_simplify_to("cos(62P/21)/(P*3*sin(62P/21))", "-1/(3*tan(P/21)*P)"); + assert_parsed_expression_simplify_to("sin(62P/21)*P*3/cos(62P/21)", "-3*tan(P/21)*P"); + assert_parsed_expression_simplify_to("sin(62P/21)/(P*3cos(62P/21))", "-tan(P/21)/(3*P)"); + assert_parsed_expression_simplify_to("-cos(P/62)ln(3)/(sin(P/62)P)", "-ln(3)/(tan(P/62)*P)"); + assert_parsed_expression_simplify_to("-2cos(P/62)ln(3)/(sin(P/62)P)", "-(2*ln(3))/(tan(P/62)*P)"); + // -- cos + assert_parsed_expression_simplify_to("cos(0)", "1"); + assert_parsed_expression_simplify_to("cos(P)", "-1"); + assert_parsed_expression_simplify_to("cos(P*4/7)", "-cos((3*P)/7)"); + assert_parsed_expression_simplify_to("cos(P*35/29)", "-cos((6*P)/29)"); + assert_parsed_expression_simplify_to("cos(-P*35/29)", "-cos((6*P)/29)"); + assert_parsed_expression_simplify_to("cos(P*340000)", "1"); + assert_parsed_expression_simplify_to("cos(-P*340001)", "-1"); + assert_parsed_expression_simplify_to("cos(-P*R(2))", "cos(R(2)*P)"); + assert_parsed_expression_simplify_to("cos(1311P/6)", "0"); + assert_parsed_expression_simplify_to("cos(P/12)", "(R(2)+R(6))/4"); + assert_parsed_expression_simplify_to("cos(-P/12)", "(R(2)+R(6))/4"); + assert_parsed_expression_simplify_to("cos(-P17/8)", "R(2+R(2))/2"); + assert_parsed_expression_simplify_to("cos(41P/6)", "-R(3)/2"); + assert_parsed_expression_simplify_to("cos(P/4+1000P)", "R(2)/2"); + assert_parsed_expression_simplify_to("cos(-P/3)", "1/2"); + assert_parsed_expression_simplify_to("cos(41P/5)", "(1+R(5))/4"); + assert_parsed_expression_simplify_to("cos(7P/10)", "-(R(2)*R(5-R(5)))/4"); + assert_parsed_expression_simplify_to("cos(0)", "1", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(180)", "-1", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(720/7)", "-cos(540/7)", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(6300/29)", "-cos(1080/29)", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(-6300/29)", "-cos(1080/29)", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(61200000)", "1", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(-61200180)", "-1", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(-180*R(2))", "cos(180*R(2))", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(39330)", "0", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(15)", "(R(2)+R(6))/4", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(-15)", "(R(2)+R(6))/4", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(-765/2)", "R(2+R(2))/2", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(7380/6)", "-R(3)/2", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(180045)", "R(2)/2", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(-60)", "1/2", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(7380/5)", "(1+R(5))/4", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(112.5)", "-R(2-R(2))/2", Expression::AngleUnit::Degree); + // -- sin + assert_parsed_expression_simplify_to("sin(0)", "0"); + assert_parsed_expression_simplify_to("sin(P)", "0"); + assert_parsed_expression_simplify_to("sin(P*35/29)", "-sin((6*P)/29)"); + assert_parsed_expression_simplify_to("sin(-P*35/29)", "sin((6*P)/29)"); + assert_parsed_expression_simplify_to("sin(P*340000)", "0"); + assert_parsed_expression_simplify_to("sin(P*340001)", "0"); + assert_parsed_expression_simplify_to("sin(-P*340001)", "0"); + assert_parsed_expression_simplify_to("sin(P/12)", "((-R(2))+R(6))/4"); + assert_parsed_expression_simplify_to("sin(-P/12)", "(R(2)-R(6))/4"); + assert_parsed_expression_simplify_to("sin(-P*R(2))", "-sin(R(2)*P)"); + assert_parsed_expression_simplify_to("sin(1311P/6)", "1"); + assert_parsed_expression_simplify_to("sin(-P17/8)", "-R(2-R(2))/2"); + assert_parsed_expression_simplify_to("sin(41P/6)", "1/2"); + assert_parsed_expression_simplify_to("sin(-3P/10)", "((-1)-R(5))/4"); + assert_parsed_expression_simplify_to("sin(P/4+1000P)", "R(2)/2"); + assert_parsed_expression_simplify_to("sin(-P/3)", "-R(3)/2"); + assert_parsed_expression_simplify_to("sin(17P/5)", "-(R(2)*R(5+R(5)))/4"); + assert_parsed_expression_simplify_to("sin(P/5)", "(R(2)*R(5-R(5)))/4"); + assert_parsed_expression_simplify_to("sin(0)", "0", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(180)", "0", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(6300/29)", "-sin(1080/29)", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(-6300/29)", "sin(1080/29)", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(61200000)", "0", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(61200180)", "0", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(-61200180)", "0", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(15)", "((-R(2))+R(6))/4", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(-15)", "(R(2)-R(6))/4", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(-180*R(2))", "-sin(180*R(2))", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(39330)", "1", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(-765/2)", "-R(2-R(2))/2", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(1230)", "1/2", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(180045)", "R(2)/2", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(-60)", "-R(3)/2", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(612)", "-(R(2)*R(5+R(5)))/4", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(36)", "(R(2)*R(5-R(5)))/4", Expression::AngleUnit::Degree); + // -- tan + assert_parsed_expression_simplify_to("tan(0)", "0"); + assert_parsed_expression_simplify_to("tan(P)", "0"); + assert_parsed_expression_simplify_to("tan(P*35/29)", "tan((6*P)/29)"); + assert_parsed_expression_simplify_to("tan(-P*35/29)", "-tan((6*P)/29)"); + assert_parsed_expression_simplify_to("tan(P*340000)", "0"); + assert_parsed_expression_simplify_to("tan(P*340001)", "0"); + assert_parsed_expression_simplify_to("tan(-P*340001)", "0"); + assert_parsed_expression_simplify_to("tan(P/12)", "2-R(3)"); + assert_parsed_expression_simplify_to("tan(-P/12)", "(-2)+R(3)"); + assert_parsed_expression_simplify_to("tan(-P*R(2))", "-tan(R(2)*P)"); + assert_parsed_expression_simplify_to("tan(1311P/6)", "undef"); + assert_parsed_expression_simplify_to("tan(-P17/8)", "1-R(2)"); + assert_parsed_expression_simplify_to("tan(41P/6)", "-R(3)/3"); + assert_parsed_expression_simplify_to("tan(P/4+1000P)", "1"); + assert_parsed_expression_simplify_to("tan(-P/3)", "-R(3)"); + assert_parsed_expression_simplify_to("tan(-P/10)", "-(R(5)*R(5-2*R(5)))/5"); + assert_parsed_expression_simplify_to("tan(0)", "0", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(180)", "0", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(6300/29)", "tan(1080/29)", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(-6300/29)", "-tan(1080/29)", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(61200000)", "0", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(61200180)", "0", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(-61200180)", "0", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(15)", "2-R(3)", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(-15)", "(-2)+R(3)", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(-180*R(2))", "-tan(180*R(2))", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(39330)", "undef", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(-382.5)", "1-R(2)", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(1230)", "-R(3)/3", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(180045)", "1", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(-60)", "-R(3)", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(tan(tan(tan(9))))", "tan(tan(tan(tan(9))))"); + // -- acos + assert_parsed_expression_simplify_to("acos(-1/2)", "(2*P)/3"); + assert_parsed_expression_simplify_to("acos(-1.2)", "undef"); + assert_parsed_expression_simplify_to("acos(cos(2/3))", "2/3"); + assert_parsed_expression_simplify_to("acos(cos(3/2))", "3/2"); + assert_parsed_expression_simplify_to("cos(acos(3/2))", "undef"); + assert_parsed_expression_simplify_to("cos(acos(2/3))", "2/3"); + assert_parsed_expression_simplify_to("acos(cos(12))", "acos(cos(12))"); + assert_parsed_expression_simplify_to("acos(cos(4P/7))", "(4*P)/7"); + assert_parsed_expression_simplify_to("acos(-cos(2))", "(-2)+P"); + assert_parsed_expression_simplify_to("acos(-1/2)", "120", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("acos(-1.2)", "undef", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("acos(cos(2/3))", "2/3", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("acos(cos(190))", "170", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("acos(cos(75))", "75", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(acos(190))", "undef", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("cos(acos(75))", "undef", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("acos(cos(12))", "12", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("acos(cos(720/7))", "720/7", Expression::AngleUnit::Degree); + // -- asin + assert_parsed_expression_simplify_to("asin(-1/2)", "-P/6"); + assert_parsed_expression_simplify_to("asin(-1.2)", "undef"); + assert_parsed_expression_simplify_to("asin(sin(2/3))", "2/3"); + assert_parsed_expression_simplify_to("sin(asin(2/3))", "2/3"); + assert_parsed_expression_simplify_to("sin(asin(3/2))", "undef"); + assert_parsed_expression_simplify_to("asin(sin(3/2))", "3/2"); + assert_parsed_expression_simplify_to("asin(sin(12))", "asin(sin(12))"); + assert_parsed_expression_simplify_to("asin(sin(-P/7))", "-P/7"); + assert_parsed_expression_simplify_to("asin(sin(-R(2)))", "-R(2)"); + assert_parsed_expression_simplify_to("asin(-1/2)", "-30", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("asin(-1.2)", "undef", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("asin(sin(75))", "75", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(asin(75))", "undef", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("sin(asin(190))", "undef", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("asin(sin(32))", "32", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("asin(sin(400))", "40", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("asin(sin(-180/7))", "-180/7", Expression::AngleUnit::Degree); + // -- atan + assert_parsed_expression_simplify_to("atan(-1)", "-P/4"); + assert_parsed_expression_simplify_to("atan(-1.2)", "-atan(6/5)"); + assert_parsed_expression_simplify_to("atan(tan(2/3))", "2/3"); + assert_parsed_expression_simplify_to("tan(atan(2/3))", "2/3"); + assert_parsed_expression_simplify_to("tan(atan(5/2))", "5/2"); + assert_parsed_expression_simplify_to("atan(tan(5/2))", "atan(tan(5/2))"); + assert_parsed_expression_simplify_to("atan(tan(5/2))", "atan(tan(5/2))"); + assert_parsed_expression_simplify_to("atan(tan(-P/7))", "-P/7"); + assert_parsed_expression_simplify_to("atan(R(3))", "P/3"); + assert_parsed_expression_simplify_to("atan(tan(-R(2)))", "-R(2)"); + assert_parsed_expression_simplify_to("atan(-1)", "-45", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("atan(-1.2)", "-atan(6/5)", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("atan(tan(-45))", "-45", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(atan(120))", "120", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("tan(atan(2293))", "2293", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("atan(tan(2293))", "-47", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("atan(tan(1808))", "8", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("atan(tan(-180/7))", "-180/7", Expression::AngleUnit::Degree); + assert_parsed_expression_simplify_to("atan(R(3))", "60", Expression::AngleUnit::Degree); +}