From 25a5748f85e205547918bbcae60951b1bd2bbbbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 15 Dec 2017 11:40:12 +0100 Subject: [PATCH] [apps] Sequence: add a customizable initial rank in sequence --- apps/sequence/sequence.cpp | 42 ++++++++++++++++++++++++++++++-------- apps/sequence/sequence.h | 9 ++++++-- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index 252ccc6a7..51a929391 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -23,7 +23,8 @@ Sequence::Sequence(const char * text, KDColor color) : m_nameLayout(nullptr), m_definitionName(nullptr), m_firstInitialConditionName(nullptr), - m_secondInitialConditionName(nullptr) + m_secondInitialConditionName(nullptr), + m_initialRank(0) { } @@ -71,6 +72,7 @@ Sequence& Sequence::operator=(const Sequence& other) { const char * secondInitialText = other.m_secondInitialConditionText; Function::operator=(other); setType(other.m_type); + setInitialRank(other.m_initialRank); setContent(contentText); setFirstInitialConditionContent(firstInitialText); setSecondInitialConditionContent(secondInitialText); @@ -82,9 +84,11 @@ uint32_t Sequence::checksum() { strlcpy(data, text(), TextField::maxBufferSize()); strlcpy(data+TextField::maxBufferSize(), firstInitialConditionText(), TextField::maxBufferSize()); strlcpy(data+2*TextField::maxBufferSize(), secondInitialConditionText(), TextField::maxBufferSize()); + int * intAdress = (int *)(&data[3*TextField::maxBufferSize()]); + *intAdress = m_initialRank; data[k_dataLengthInBytes-3] = (char)m_type; data[k_dataLengthInBytes-2] = name()!= nullptr ? name()[0] : 0; - data[k_dataLengthInBytes-1] = isActive() ? 1 : 0; + data[k_dataLengthInBytes-1] = (char)(isActive() ? 1 : 0); return Ion::crc32((uint32_t *)data, k_dataLengthInBytes/sizeof(uint32_t)); } @@ -101,6 +105,9 @@ Sequence::Type Sequence::type() { } void Sequence::setType(Type type) { + if (m_type == Type::Explicite) { + setInitialRank(0); + } m_type = type; tidy(); /* Reset all contents */ @@ -128,6 +135,18 @@ void Sequence::setType(Type type) { setSecondInitialConditionContent(""); } +void Sequence::setInitialRank(int rank) { + m_initialRank = rank; + if (m_firstInitialConditionName != nullptr) { + delete m_firstInitialConditionName; + m_firstInitialConditionName = nullptr; + } + if (m_secondInitialConditionName != nullptr) { + delete m_secondInitialConditionName; + m_secondInitialConditionName = nullptr; + } +} + Poincare::Expression * Sequence::firstInitialConditionExpression(Context * context) const { if (m_firstInitialConditionExpression == nullptr) { m_firstInitialConditionExpression = Poincare::Expression::parse(m_firstInitialConditionText); @@ -229,21 +248,25 @@ Poincare::ExpressionLayout * Sequence::definitionName() { } Poincare::ExpressionLayout * Sequence::firstInitialConditionName() { + char buffer[k_initialRankNumberOfDigits+1]; + Integer(m_initialRank).writeTextInBuffer(buffer, k_initialRankNumberOfDigits+1); if (m_firstInitialConditionName == nullptr) { if (m_type == Type::SingleRecurrence) { - m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("0", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); } if (m_type == Type::DoubleRecurrence) { - m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("0", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); } } return m_firstInitialConditionName; } Poincare::ExpressionLayout * Sequence::secondInitialConditionName() { + char buffer[k_initialRankNumberOfDigits+1]; + Integer(m_initialRank+1).writeTextInBuffer(buffer, k_initialRankNumberOfDigits+1); if (m_secondInitialConditionName == nullptr) { if (m_type == Type::DoubleRecurrence) { - m_secondInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("1", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_secondInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); } } @@ -284,6 +307,9 @@ T Sequence::templatedApproximateAtAbscissa(T x, SequenceContext * sqctx) const { template T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { + if (n < m_initialRank || n < 0) { + return NAN; + } CacheContext ctx = CacheContext(sqctx); T un = sqctx->valueOfSequenceAtPreviousRank(0, 0); T unm1 = sqctx->valueOfSequenceAtPreviousRank(0, 1); @@ -307,7 +333,7 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { } case Type::SingleRecurrence: { - if (n == 0) { + if (n == m_initialRank) { return firstInitialConditionExpression(sqctx)->template approximateToScalar(*sqctx); } ctx.setValueForSymbol(un, &un1Symbol); @@ -320,10 +346,10 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const { } default: { - if (n == 0) { + if (n == m_initialRank) { return firstInitialConditionExpression(sqctx)->template approximateToScalar(*sqctx); } - if (n == 1) { + if (n == m_initialRank+1) { return secondInitialConditionExpression(sqctx)->template approximateToScalar(*sqctx); } ctx.setValueForSymbol(unm1, &un1Symbol); diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index 8f678de83..c72e96efe 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -22,6 +22,9 @@ public: Sequence(Sequence&& other) = delete; uint32_t checksum() override; Type type(); + int initialRank() const { + return m_initialRank; + } const char * firstInitialConditionText(); const char * secondInitialConditionText(); Poincare::Expression * firstInitialConditionExpression(Poincare::Context * context) const; @@ -32,6 +35,7 @@ public: * or setSecondInitialConditionContent, the sequence context needs to * invalidate the cache because the sequences evaluations might have changed. */ void setType(Type type); + void setInitialRank(int rank); void setContent(const char * c) override; void setFirstInitialConditionContent(const char * c); void setSecondInitialConditionContent(const char * c); @@ -51,10 +55,10 @@ public: template T approximateToNextRank(int n, SequenceContext * sqctx) const; double sumOfTermsBetweenAbscissa(double start, double end, Poincare::Context * context); void tidy() override; - + constexpr static int k_initialRankNumberOfDigits = 3; // m_initialRank is capped by 999 private: constexpr static double k_maxNumberOfTermsInSum = 100000.0; - constexpr static size_t k_dataLengthInBytes = (3*TextField::maxBufferSize()+3)*sizeof(char)+1; + constexpr static size_t k_dataLengthInBytes = (3*TextField::maxBufferSize()+3)*sizeof(char)+sizeof(int)+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 templatedApproximateAtAbscissa(T x, SequenceContext * sqctx) const; @@ -69,6 +73,7 @@ private: Poincare::ExpressionLayout * m_definitionName; Poincare::ExpressionLayout * m_firstInitialConditionName; Poincare::ExpressionLayout * m_secondInitialConditionName; + int m_initialRank; }; }