diff --git a/apps/statistics/series_context.cpp b/apps/statistics/series_context.cpp index d02587d02..68b875705 100644 --- a/apps/statistics/series_context.cpp +++ b/apps/statistics/series_context.cpp @@ -13,7 +13,7 @@ void SeriesContext::setExpressionForSymbolName(const Expression * expression, co } const Expression * SeriesContext::expressionForSymbol(const Symbol * symbol) { - if (symbol->isSeriesSymbol()) { + if (Symbol::isSeriesSymbol(symbol->name())) { const char * seriesName = Symbol::textForSpecialSymbols(symbol->name()); assert(strlen(seriesName) == 2); diff --git a/apps/statistics/store_controller.cpp b/apps/statistics/store_controller.cpp index 3ea77f6ed..b0ebad399 100644 --- a/apps/statistics/store_controller.cpp +++ b/apps/statistics/store_controller.cpp @@ -21,12 +21,30 @@ StoreController::StoreController(Responder * parentResponder, Store * store, But void StoreController::fillColumnWithFormula(Expression * formula) { int currentColumn = selectedColumn(); - // Fetch the series used in the formula to: - // - Make sure the current filled column is not inside - // - Compute the size of the filled in series + // Fetch the series used in the formula to compute the size of the filled in series + char variables[7] = {0, 0, 0, 0, 0, 0, 0}; + int numberOfVariables = formula->getVariables(Symbol::isSeriesSymbol, variables); + assert(numberOfVariables >= 0); + int numberOfValuesToCompute = -1; + int index = 0; + while (variables[index] != 0) { + const char * seriesName = Symbol::textForSpecialSymbols(variables[index]); + assert(strlen(seriesName) == 2); + int series = (int)(seriesName[1] - '0') - 1; + assert(series >= 0 && series < FloatPairStore::k_numberOfSeries); + if (numberOfValuesToCompute == -1) { + numberOfValuesToCompute = m_store->numberOfPairsOfSeries(series); + } else { + numberOfValuesToCompute = min(numberOfValuesToCompute, m_store->numberOfPairsOfSeries(series)); + } + index++; + } + if (numberOfValuesToCompute == -1) { + numberOfValuesToCompute = m_store->numberOfPairsOfSeries(selectedColumn()/FloatPairStore::k_numberOfColumnsPerSeries); + } SeriesContext seriesContext(m_store, const_cast(static_cast(app()->container()))->globalContext()); - for (int j = 0; j < 2; j++) { + for (int j = 0; j < numberOfValuesToCompute; j++) { // Set the context seriesContext.setSeriesPairIndex(j); // Compute the new value using the formula diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index c8e2467c7..dbf547b4e 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -238,6 +238,15 @@ public: 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); + + /* getVariables fills the table variables with the variable present in the + * expression and returns the number of entries in filled in variables. + * For instance getVariables('x+y+2*w/cos(4)') would result in + * variables = « xyw » and would return 3. If the final number of + * variables would overflow the maxNumberOfVariables, getVariables return -1 */ + static constexpr int k_maxNumberOfVariables = 6; + typedef bool (*isVariableTest)(char c); + virtual int getVariables(isVariableTest isVariable, char * variables) const; protected: /* Constructor */ Expression() : m_parent(nullptr) {} diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index 26a89aac4..a5cddd6db 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -45,11 +45,12 @@ public: Sign sign() const override; bool isMatrixSymbol() const; bool isScalarSymbol() const; - bool isSeriesSymbol() const; + static bool isSeriesSymbol(char c); bool isApproximate(Context & context) const; float characteristicXRange(Context & context, AngleUnit angleUnit = AngleUnit::Default) const override; bool hasAnExactRepresentation(Context & context) const; static const char * textForSpecialSymbols(char name); + int getVariables(isVariableTest isVariable, char * variables) const override; private: Expression * replaceSymbolWithExpression(char symbol, Expression * expression) override; /* Simplification */ diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 61ba5af80..1efb4f095 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -371,6 +371,20 @@ template T Expression::epsilon() { return epsilon; } +/* Get variables */ + +int Expression::getVariables(isVariableTest isVariable, char * variables) const { + int numberOfVariables = 0; + for (int i = 0; i < numberOfOperands(); i++) { + int n = operand(i)->getVariables(isVariable, variables); + if (n < 0) { + return -1; + } + numberOfVariables = n > numberOfVariables ? n : numberOfVariables; + } + return numberOfVariables; +} + } template Poincare::Expression * Poincare::Expression::approximate(Context& context, AngleUnit angleUnit) const; diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 63b60dd40..911620d47 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -71,6 +71,26 @@ const char * Symbol::textForSpecialSymbols(char name) { } } +int Symbol::getVariables(isVariableTest isVariable, char * variables) const { + size_t variablesLength = strlen(variables); + if (isVariable(m_name)) { + char * currentChar = variables; + while (*currentChar != 0) { + if (*currentChar == m_name) { + return variablesLength; + } + currentChar++; + } + if (variablesLength < k_maxNumberOfVariables) { + variables[variablesLength] = m_name; + variables[variablesLength+1] = 0; + return variablesLength+1; + } + return -1; + } + return variablesLength; +} + Symbol::SpecialSymbols Symbol::matrixSymbol(char index) { switch (index - '0') { case 0: @@ -244,7 +264,7 @@ ExpressionLayout * Symbol::privateCreateLayout(PrintFloat::Mode floatDisplayMode false), false); } - if (isMatrixSymbol() || isSeriesSymbol()) { + if (isMatrixSymbol() || isSeriesSymbol(m_name)) { return LayoutEngine::createStringLayout(textForSpecialSymbols(m_name), 2); } return LayoutEngine::createStringLayout(&m_name, 1); @@ -281,8 +301,8 @@ bool Symbol::isScalarSymbol() const { return false; } -bool Symbol::isSeriesSymbol() const { - if (m_name >= (char)SpecialSymbols::V1 && m_name <= (char)SpecialSymbols::N3) { +bool Symbol::isSeriesSymbol(char c) { + if (c >= (char)SpecialSymbols::V1 && c <= (char)SpecialSymbols::N3) { return true; } return false;