diff --git a/poincare/Makefile b/poincare/Makefile index 2502f51a0..319c33552 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -57,6 +57,7 @@ objs += $(addprefix poincare/src/,\ matrix_complex.o\ multiplication.o\ n_ary_expression_node.o\ + naperian_logarithm.o\ nth_root.o\ number.o\ parenthesis.o\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index e06546ee4..4a24cea32 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -115,6 +115,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 4f208531f..66f9df20c 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -28,6 +28,7 @@ class Expression : public TreeByValue { friend class Matrix; template friend class LogarithmNode; + friend class NaperianLogarithmNode; template friend class ExceptionExpressionNode; public: diff --git a/poincare/include/poincare/naperian_logarithm.h b/poincare/include/poincare/naperian_logarithm.h index cd3796229..f110ed987 100644 --- a/poincare/include/poincare/naperian_logarithm.h +++ b/poincare/include/poincare/naperian_logarithm.h @@ -1,29 +1,49 @@ #ifndef POINCARE_NAPERIAN_LOGARITHM_H #define POINCARE_NAPERIAN_LOGARITHM_H -#include -#include #include +#include +#include +#include namespace Poincare { -class NaperianLogarithm : public StaticHierarchy<1> { - using StaticHierarchy<1>::StaticHierarchy; +class NaperianLogarithmNode : public ExpressionNode { public: - Type type() const override; + // Allocation Failure + static NaperianLogarithmNode * FailedAllocationStaticNode(); + NaperianLogarithmNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); } + + // TreeNode + size_t size() const override { return sizeof(NaperianLogarithmNode); } + int numberOfChildren() const override { return 1; } +#if POINCARE_TREE_LOG + virtual void logNodeName(std::ostream & stream) const override { + stream << "NaperianLogarithm"; + } +#endif + + // Properties + Type type() const override { return Type::NaperianLogarithm; } + private: - /* Layout */ - LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { + // Layout + LayoutReference createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return LayoutHelper::Prefix(this, floatDisplayMode, numberOfSignificantDigits, name()); } int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override { return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, name()); } - const char * name() const { return "ln"; } - /* Simplification */ - Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) override; + static const char * name() { return "ln"; } + // Simplification + Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const override; /* Evaluation */ - template static std::complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit); + template static Complex computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit) { + /* ln has a branch cut on ]-inf, 0]: it is then multivalued on this cut. We + * followed the convention chosen by the lib c++ of llvm on ]-inf+0i, 0+0i] + * (warning: ln takes the other side of the cut values on ]-inf-0i, 0-0i]). */ + return std::log(c); + } Evaluation approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return ApproximationHelper::Map(this, context, angleUnit,computeOnComplex); } @@ -32,6 +52,16 @@ private: } }; +class NaperianLogarithm : public Expression { +public: + NaperianLogarithm() : Expression(TreePool::sharedPool()->createTreeNode()) {} + NaperianLogarithm(const NaperianLogarithmNode * n) : Expression(n) {} + NaperianLogarithm(Expression operand) : NaperianLogarithm() { + replaceChildAtIndexInPlace(0, operand); + } + Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit) const; +}; + } #endif diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index 7b1c27066..e90d611df 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -140,8 +140,8 @@ im { poincare_expression_yylval.expression = new ImaginaryPart(); return FUNCTIO int { poincare_expression_yylval.expression = new Integral(); return FUNCTION; } inverse { poincare_expression_yylval.expression = new MatrixInverse(); return FUNCTION; } lcm { poincare_expression_yylval.expression = new LeastCommonMultiple(); return FUNCTION; } -ln { poincare_expression_yylval.expression = new NaperianLogarithm(); return FUNCTION; } */ +ln { poincare_expression_yylval.expression = NaperianLogarithm(); return FUNCTION; } log { return LOGFUNCTION; } /*permute { poincare_expression_yylval.expression = new PermuteCoefficient(); return FUNCTION; } prediction95 { poincare_expression_yylval.expression = new PredictionInterval(); return FUNCTION; } diff --git a/poincare/src/naperian_logarithm.cpp b/poincare/src/naperian_logarithm.cpp index 55a3128ee..b7b4e8736 100644 --- a/poincare/src/naperian_logarithm.cpp +++ b/poincare/src/naperian_logarithm.cpp @@ -2,46 +2,31 @@ #include #include #include -extern "C" { -#include -#include -} -#include -#include namespace Poincare { -Expression::Type NaperianLogarithm::type() const { - return Type::NaperianLogarithm; +NaperianLogarithmNode * NaperianLogarithmNode::FailedAllocationStaticNode() { + static AllocationFailureExpressionNode failure; + TreePool::sharedPool()->registerStaticNodeIfRequired(&failure); + return &failure; } -Expression * NaperianLogarithm::clone() const { - NaperianLogarithm * a = new NaperianLogarithm(m_operands, true); - return a; +Expression NaperianLogarithmNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const { + return NaperianLogarithm(this).shallowReduce(context, angleUnit); } -Expression NaperianLogarithm::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) { - Expression * e = Expression::defaultShallowReduce(context, angleUnit); - if (e != this) { +Expression NaperianLogarithm::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const { + Expression e = Expression::defaultShallowReduce(context, angleUnit); + if (e.isUndefinedOrAllocationFailure()) { return e; } #if MATRIX_EXACT_REDUCING - if (operand(0)->type() == Type::Matrix) { - return SimplificationHelper::Map(this, context, angleUnit); + if (childAtIndex(0).type() == ExpressionNode::Type::Matrix) { + return SimplificationHelper::Map(*this, context, angleUnit); } #endif - const Expression * logOperands[2] = {operand(0)->clone(), new Symbol(Ion::Charset::Exponential)}; - Logarithm * l = new Logarithm(logOperands, 2, false); - replaceWith(l, true); - return l->shallowReduce(context, angleUnit); -} - -template -std::complex NaperianLogarithm::computeOnComplex(const std::complex c, Preferences::AngleUnit angleUnit) { - /* ln has a branch cut on ]-inf, 0]: it is then multivalued on this cut. We - * followed the convention chosen by the lib c++ of llvm on ]-inf+0i, 0+0i] - * (warning: ln takes the other side of the cut values on ]-inf-0i, 0-0i]). */ - return std::log(c); + Logarithm l = Logarithm(childAtIndex(0), Symbol(Ion::Charset::Exponential)); + return l.shallowReduce(context, angleUnit); } } diff --git a/poincare/test/logarithm.cpp b/poincare/test/logarithm.cpp index b510aa395..9efdc2ab3 100644 --- a/poincare/test/logarithm.cpp +++ b/poincare/test/logarithm.cpp @@ -10,14 +10,14 @@ QUIZ_CASE(poincare_logarithm_evaluate) { assert_parsed_expression_evaluates_to("log(2,64)", "0.1666667"); assert_parsed_expression_evaluates_to("log(6,7)", "0.9207822211616"); assert_parsed_expression_evaluates_to("log(5)", "0.69897"); -// assert_parsed_expression_evaluates_to("ln(5)", "1.6094379124341"); + assert_parsed_expression_evaluates_to("ln(5)", "1.6094379124341"); assert_parsed_expression_evaluates_to("log(2+5*I,64)", "0.4048317+0.2862042*I"); assert_parsed_expression_evaluates_to("log(6,7+4*I)", "8.0843880717528E-1-2.0108238082167E-1*I"); assert_parsed_expression_evaluates_to("log(5+2*I)", "0.731199+0.1652518*I"); -// assert_parsed_expression_evaluates_to("ln(5+2*I)", "1.6836479149932+3.8050637711236E-1*I"); + assert_parsed_expression_evaluates_to("ln(5+2*I)", "1.6836479149932+3.8050637711236E-1*I"); // WARNING: evaluate on branch cut can be multivalued -// assert_parsed_expression_evaluates_to("ln(-4)", "1.3862943611199+3.1415926535898*I"); + assert_parsed_expression_evaluates_to("ln(-4)", "1.3862943611199+3.1415926535898*I"); } QUIZ_CASE(poincare_logarithm_simplify) {