From d7a0914d13594ac877f0258e518d060e4d4fccbf Mon Sep 17 00:00:00 2001 From: Arthur Date: Wed, 20 May 2020 11:09:14 +0200 Subject: [PATCH] [Apps/CalculationStore] Changed the way to store calculations -No more limit to the number of calculations -All calculations are memoized -Added tests to test/calculation_store.cpp Change-Id: Ia10e2b009576eaf4496ba44a0c88f6e7e76f6cef --- apps/calculation/app.cpp | 4 - apps/calculation/app.h | 1 - apps/calculation/calculation.h | 4 +- apps/calculation/calculation_store.cpp | 234 ++++++++------------ apps/calculation/calculation_store.h | 68 +++--- apps/calculation/test/calculation_store.cpp | 170 ++++++++------ 6 files changed, 223 insertions(+), 258 deletions(-) diff --git a/apps/calculation/app.cpp b/apps/calculation/app.cpp index a880ec224..e2a501a62 100644 --- a/apps/calculation/app.cpp +++ b/apps/calculation/app.cpp @@ -34,10 +34,6 @@ App::Descriptor * App::Snapshot::descriptor() { return &descriptor; } -void App::Snapshot::tidy() { - m_calculationStore.tidy(); -} - App::App(Snapshot * snapshot) : ExpressionFieldDelegateApp(snapshot, &m_editExpressionController), m_historyController(&m_editExpressionController, snapshot->calculationStore()), diff --git a/apps/calculation/app.h b/apps/calculation/app.h index be7f73e17..9df67194e 100644 --- a/apps/calculation/app.h +++ b/apps/calculation/app.h @@ -24,7 +24,6 @@ public: Descriptor * descriptor() override; CalculationStore * calculationStore() { return &m_calculationStore; } private: - void tidy() override; CalculationStore m_calculationStore; }; static App * app() { diff --git a/apps/calculation/calculation.h b/apps/calculation/calculation.h index ed6e9f2b2..10f4e0662 100644 --- a/apps/calculation/calculation.h +++ b/apps/calculation/calculation.h @@ -21,6 +21,7 @@ class CalculationStore; class Calculation { friend CalculationStore; public: + static constexpr int k_numberOfExpressions = 4; enum class EqualSign : uint8_t { Unknown, Approximation, @@ -48,7 +49,7 @@ public: * calculations instead of clearing less space, then fail to serialize, clear * more space, fail to serialize, clear more space, etc., until reaching * sufficient free space. */ - static int MinimalSize() { return sizeof(uint8_t) + 2*sizeof(KDCoordinate) + sizeof(uint8_t) + 3*Constant::MaxSerializedExpressionSize; } + static int MinimalSize() { return sizeof(uint8_t) + 2*sizeof(KDCoordinate) + sizeof(uint8_t) + 3*Constant::MaxSerializedExpressionSize + sizeof(Calculation *); } Calculation() : m_displayOutput(DisplayOutput::Unknown), @@ -93,7 +94,6 @@ public: // Additional Information AdditionalInformationType additionalInformationType(Poincare::Context * context); private: - static constexpr int k_numberOfExpressions = 4; static constexpr KDCoordinate k_heightComputationFailureHeight = 50; static constexpr const char * k_maximalIntegerWithAdditionalInformation = "10000000000000000"; diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp index d39684424..be2055ced 100644 --- a/apps/calculation/calculation_store.cpp +++ b/apps/calculation/calculation_store.cpp @@ -11,58 +11,47 @@ using namespace Shared; namespace Calculation { -CalculationStore::CalculationStore() : - m_bufferEnd(m_buffer), - m_numberOfCalculations(0), - m_slidedBuffer(false), - m_indexOfFirstMemoizedCalculationPointer(0) +CalculationStore::CalculationStore(char * buffer, int size) : + m_buffer(buffer), + m_bufferSize(size), + m_calculationAreaEnd(m_buffer), + m_numberOfCalculations(0) { - resetMemoizedModelsAfterCalculationIndex(-1); + assert(m_buffer != nullptr); + assert(m_bufferSize > 0); } +// Returns an expiring pointer to the calculation of index i ExpiringPointer CalculationStore::calculationAtIndex(int i) { - assert(!m_slidedBuffer); assert(i >= 0 && i < m_numberOfCalculations); - assert(m_indexOfFirstMemoizedCalculationPointer >= 0); - if (i >= m_indexOfFirstMemoizedCalculationPointer && i < m_indexOfFirstMemoizedCalculationPointer + k_numberOfMemoizedCalculationPointers) { - // The calculation is within the range of memoized calculations - Calculation * c = m_memoizedCalculationPointers[i-m_indexOfFirstMemoizedCalculationPointer]; - if (c != nullptr) { - // The pointer was memoized - return ExpiringPointer(c); - } - c = bufferCalculationAtIndex(i); - m_memoizedCalculationPointers[i-m_indexOfFirstMemoizedCalculationPointer] = c; - return c; + // m_buffer is the adress of the oldest calculation in calculation store + Calculation * c = (Calculation *) m_buffer; + if (i != m_numberOfCalculations-1) { + // The calculation we want is not the oldest one so we get its pointer + c = *reinterpret_cast(addressOfPointerToCalculationOfIndex(i+1)); } - // Slide the memoization buffer - if (i >= m_indexOfFirstMemoizedCalculationPointer) { - // Slide the memoization buffer to the left - memmove(m_memoizedCalculationPointers, m_memoizedCalculationPointers+1, (k_numberOfMemoizedCalculationPointers - 1) * sizeof(Calculation *)); - m_memoizedCalculationPointers[k_numberOfMemoizedCalculationPointers - 1] = nullptr; - m_indexOfFirstMemoizedCalculationPointer++; - } else { - // Slide the memoization buffer to the right - memmove(m_memoizedCalculationPointers+1, m_memoizedCalculationPointers, (k_numberOfMemoizedCalculationPointers - 1) * sizeof(Calculation *)); - m_memoizedCalculationPointers[0] = nullptr; - m_indexOfFirstMemoizedCalculationPointer--; - } - return calculationAtIndex(i); + return ExpiringPointer(c); } +// Pushes an expression in the store ExpiringPointer CalculationStore::push(const char * text, Context * context, HeightComputer heightComputer) { - /* Compute ans now, before the buffer is slided and before the calculation + /* Compute ans now, before the buffer is updated and before the calculation * might be deleted */ Expression ans = ansExpression(context); - // Prepare the buffer for the new calculation - int minSize = Calculation::MinimalSize(); - assert(k_bufferSize > minSize); - while (remainingBufferSize() < minSize || m_numberOfCalculations > k_maxNumberOfCalculations) { - deleteLastCalculation(); + /* Prepare the buffer for the new calculation + *The minimal size to store the new calculation is the minimal size of a calculation plus the pointer to its end */ + int minSize = Calculation::MinimalSize() + sizeof(Calculation *); + assert(m_bufferSize > minSize); + while (remainingBufferSize() < minSize) { + // If there is no more space to store a calculation, we delete the oldest one + deleteOldestCalculation(); } - char * newCalculationsLocation = slideCalculationsToEndOfBuffer(); - char * nextSerializationLocation = m_buffer; + + // Getting the adresses of the limits of the free space + char * beginingOfFreeSpace = (char *)m_calculationAreaEnd; + char * endOfFreeSpace = beginingOfMemoizationArea(); + char * previousCalc = beginingOfFreeSpace; // Add the beginning of the calculation { @@ -70,23 +59,23 @@ ExpiringPointer CalculationStore::push(const char * text, Context * * available, so this memmove will not overide anything. */ Calculation newCalc = Calculation(); size_t calcSize = sizeof(newCalc); - memmove(nextSerializationLocation, &newCalc, calcSize); - nextSerializationLocation += calcSize; + memcpy(beginingOfFreeSpace, &newCalc, calcSize); + beginingOfFreeSpace += calcSize; } /* Add the input expression. * We do not store directly the text entered by the user because we do not * want to keep Ans symbol in the calculation store. */ - const char * inputSerialization = nextSerializationLocation; + const char * inputSerialization = beginingOfFreeSpace; { Expression input = Expression::Parse(text, context).replaceSymbolWithExpression(Symbol::Ans(), ans); - if (!pushSerializeExpression(input, nextSerializationLocation, &newCalculationsLocation)) { + if (!pushSerializeExpression(input, beginingOfFreeSpace, &endOfFreeSpace)) { /* If the input does not fit in the store (event if the current * calculation is the only calculation), just replace the calculation with * undef. */ return emptyStoreAndPushUndef(context, heightComputer); } - nextSerializationLocation += strlen(nextSerializationLocation) + 1; + beginingOfFreeSpace += strlen(beginingOfFreeSpace) + 1; } // Compute and serialize the outputs @@ -109,30 +98,27 @@ ExpiringPointer CalculationStore::push(const char * text, Context * if (i == numberOfOutputs - 1) { numberOfSignificantDigits = Poincare::Preferences::sharedPreferences()->numberOfSignificantDigits(); } - if (!pushSerializeExpression(outputs[i], nextSerializationLocation, &newCalculationsLocation, numberOfSignificantDigits)) { + if (!pushSerializeExpression(outputs[i], beginingOfFreeSpace, &endOfFreeSpace, numberOfSignificantDigits)) { /* If the exat/approximate output does not fit in the store (event if the * current calculation is the only calculation), replace the output with * undef if it fits, else replace the whole calcualtion with undef. */ Expression undef = Undefined::Builder(); - if (!pushSerializeExpression(undef, nextSerializationLocation, &newCalculationsLocation)) { + if (!pushSerializeExpression(undef, beginingOfFreeSpace, &endOfFreeSpace)) { return emptyStoreAndPushUndef(context, heightComputer); } } - nextSerializationLocation += strlen(nextSerializationLocation) + 1; + beginingOfFreeSpace += strlen(beginingOfFreeSpace) + 1; } } + // Storing the pointer of the end of the new calculation + memcpy(endOfFreeSpace-sizeof(Calculation*),&beginingOfFreeSpace,sizeof(beginingOfFreeSpace)); - // Restore the other calculations - size_t slideSize = m_buffer + k_bufferSize - newCalculationsLocation; - memcpy(nextSerializationLocation, newCalculationsLocation, slideSize); - m_slidedBuffer = false; + // The new calculation is now stored m_numberOfCalculations++; - m_bufferEnd+= nextSerializationLocation - m_buffer; - // Clean the memoization - resetMemoizedModelsAfterCalculationIndex(-1); - - ExpiringPointer calculation = ExpiringPointer(reinterpret_cast(m_buffer)); + // The end of the calculation storage area is updated + m_calculationAreaEnd += beginingOfFreeSpace - previousCalc; + ExpiringPointer calculation = ExpiringPointer(reinterpret_cast(previousCalc)); /* Heights are computed now to make sure that the display output is decided * accordingly to the remaining size in the Poincare pool. Once it is, it * can't change anymore: the calculation heights are fixed which ensures that @@ -143,36 +129,42 @@ ExpiringPointer CalculationStore::push(const char * text, Context * return calculation; } +// Delete the calculation of index i void CalculationStore::deleteCalculationAtIndex(int i) { assert(i >= 0 && i < m_numberOfCalculations); - assert(!m_slidedBuffer); - ExpiringPointer calcI = calculationAtIndex(i); - char * nextCalc = reinterpret_cast(calcI->next()); - assert(m_bufferEnd >= nextCalc); - size_t slidingSize = m_bufferEnd - nextCalc; - memmove((char *)(calcI.pointer()), nextCalc, slidingSize); - m_bufferEnd -= (nextCalc - (char *)(calcI.pointer())); - m_numberOfCalculations--; - resetMemoizedModelsAfterCalculationIndex(i); -} - -void CalculationStore::deleteAll() { - /* We might call deleteAll because the app closed due to a pool allocation - * failure, so we cannot assert that m_slidedBuffer is false. */ - m_slidedBuffer = false; - m_bufferEnd = m_buffer; - m_numberOfCalculations = 0; - resetMemoizedModelsAfterCalculationIndex(-1); -} - -void CalculationStore::tidy() { - if (m_slidedBuffer) { - deleteAll(); + if (i == 0) { + ExpiringPointer lastCalculationPointer = calculationAtIndex(0); + m_calculationAreaEnd = (char *)(lastCalculationPointer.pointer()); + m_numberOfCalculations--; return; } - resetMemoizedModelsAfterCalculationIndex(-1); + char * calcI = (char *)calculationAtIndex(i).pointer(); + char * nextCalc = (char *) calculationAtIndex(i-1).pointer(); + assert(m_calculationAreaEnd >= nextCalc); + size_t slidingSize = m_calculationAreaEnd - nextCalc; + // Slide the i-1 most recent calculations right after the i+1'th + memmove(calcI, nextCalc, slidingSize); + m_calculationAreaEnd -= nextCalc - calcI; + // Recompute pointer to calculations after the i'th + recomputeMemoizedPointersAfterCalculationIndex(i); + m_numberOfCalculations--; } +// Delete the oldest calculation in the store and returns the amount of space freed by the operation +size_t CalculationStore::deleteOldestCalculation() { + char * oldBufferEnd = (char *) m_calculationAreaEnd; + deleteCalculationAtIndex(numberOfCalculations()-1); + char * newBufferEnd = (char *) m_calculationAreaEnd; + return oldBufferEnd - newBufferEnd; +} + +// Delete all calculations +void CalculationStore::deleteAll() { + m_calculationAreaEnd = m_buffer; + m_numberOfCalculations = 0; +} + +// Replace "Ans" by its expression Expression CalculationStore::ansExpression(Context * context) { if (numberOfCalculations() == 0) { return Rational::Builder(0); @@ -191,92 +183,42 @@ Expression CalculationStore::ansExpression(Context * context) { return mostRecentCalculation->exactOutput(); } -Calculation * CalculationStore::bufferCalculationAtIndex(int i) { - int currentIndex = 0; - for (Calculation * c : *this) { - if (currentIndex == i) { - return c; - } - currentIndex++; - } - assert(false); - return nullptr; -} - +// Push converted expression in the buffer bool CalculationStore::pushSerializeExpression(Expression e, char * location, char * * newCalculationsLocation, int numberOfSignificantDigits) { - assert(m_slidedBuffer); - assert(*newCalculationsLocation <= m_buffer + k_bufferSize); + assert(*newCalculationsLocation <= m_buffer + m_bufferSize); bool expressionIsPushed = false; while (true) { size_t locationSize = *newCalculationsLocation - location; expressionIsPushed = (PoincareHelpers::Serialize(e, location, locationSize, numberOfSignificantDigits) < (int)locationSize-1); - if (expressionIsPushed || *newCalculationsLocation >= m_buffer + k_bufferSize) { + if (expressionIsPushed || *newCalculationsLocation >= m_buffer + m_bufferSize) { break; } - *newCalculationsLocation = *newCalculationsLocation + deleteLastCalculation(); - assert(*newCalculationsLocation <= m_buffer + k_bufferSize); + *newCalculationsLocation = *newCalculationsLocation + deleteOldestCalculation(); + assert(*newCalculationsLocation <= m_buffer + m_bufferSize); } return expressionIsPushed; } -char * CalculationStore::slideCalculationsToEndOfBuffer() { - int calculationsSize = m_bufferEnd - m_buffer; - char * calculationsNewPosition = m_buffer + k_bufferSize - calculationsSize; - memmove(calculationsNewPosition, m_buffer, calculationsSize); - m_slidedBuffer = true; - return calculationsNewPosition; -} -size_t CalculationStore::deleteLastCalculation(const char * calculationsStart) { - assert(m_numberOfCalculations > 0); - size_t result; - if (!m_slidedBuffer) { - assert(calculationsStart == nullptr); - const char * previousBufferEnd = m_bufferEnd; - m_bufferEnd = lastCalculationPosition(m_buffer); - assert(previousBufferEnd > m_bufferEnd); - result = previousBufferEnd - m_bufferEnd; - } else { - assert(calculationsStart != nullptr); - const char * lastCalc = lastCalculationPosition(calculationsStart); - assert(*lastCalc == 0); - result = m_buffer + k_bufferSize - lastCalc; - memmove(const_cast(calculationsStart + result), calculationsStart, m_buffer + k_bufferSize - calculationsStart - result); - } - m_numberOfCalculations--; - resetMemoizedModelsAfterCalculationIndex(-1); - return result; -} - -const char * CalculationStore::lastCalculationPosition(const char * calculationsStart) const { - assert(calculationsStart >= m_buffer && calculationsStart < m_buffer + k_bufferSize); - Calculation * c = reinterpret_cast(const_cast(calculationsStart)); - int calculationIndex = 0; - while (calculationIndex < m_numberOfCalculations - 1) { - c = c->next(); - calculationIndex++; - } - return reinterpret_cast(c); -} Shared::ExpiringPointer CalculationStore::emptyStoreAndPushUndef(Context * context, HeightComputer heightComputer) { /* We end up here as a result of a failed calculation push. The store * attributes are not necessarily clean, so we need to reset them. */ - m_slidedBuffer = false; deleteAll(); return push(Undefined::Name(), context, heightComputer); } -void CalculationStore::resetMemoizedModelsAfterCalculationIndex(int index) { - if (index < m_indexOfFirstMemoizedCalculationPointer) { - memset(&m_memoizedCalculationPointers, 0, k_numberOfMemoizedCalculationPointers * sizeof(Calculation *)); - return; - } - if (index >= m_indexOfFirstMemoizedCalculationPointer + k_numberOfMemoizedCalculationPointers) { - return; - } - for (int i = index - m_indexOfFirstMemoizedCalculationPointer; i < k_numberOfMemoizedCalculationPointers; i++) { - m_memoizedCalculationPointers[i] = nullptr; +// Recompute memoized pointers to the calculations after index i +void CalculationStore::recomputeMemoizedPointersAfterCalculationIndex(int index) { + assert(index < m_numberOfCalculations); + // Clear pointer and recompute new ones + Calculation * c = calculationAtIndex(index).pointer(); + Calculation * nextCalc; + while (index != 0) { + nextCalc = c->next(); + memcpy(addressOfPointerToCalculationOfIndex(index), &nextCalc, sizeof(Calculation *)); + c = nextCalc; + index--; } } diff --git a/apps/calculation/calculation_store.h b/apps/calculation/calculation_store.h index 9f69d3edf..53bc3fdf4 100644 --- a/apps/calculation/calculation_store.h +++ b/apps/calculation/calculation_store.h @@ -7,37 +7,45 @@ namespace Calculation { -/* To optimize the storage space, we use one big buffer for all calculations. - * - * The previous solution was to keep 10 calculations, each containing 3 buffers - * (for input and outputs). To optimize the storage, we then wanted to put all - * outputs in a cache where they could be deleted to add a new entry, and - * recomputed on cache miss. However, the computation depends too much on the - * state of the memory for this to be possible. For instance: - * 6->a - * a+1 - * Perform some big computations that remove a+1 from the cache - * Delete a from the variable box. - * Scroll up to display a+1 : a does not exist anymore so the outputs won't be - * recomputed correctly. - * - * Now we do not cap the number of calculations and just delete the oldests to - * create space for a new calculation. */ +/* + To optimize the storage space, we use one big buffer for all calculations. + The calculations are stored one after another while pointers to the end of each + calculation are stored at the end of the buffer, in the opposite direction. + By doing so, we can memoize every calculation entered while not limiting + the number of calculation stored in the buffer. + + If the remaining space is too small for storing a new calculation, we + delete the oldest one. + + Memory layout : + <- Available space for new calculations -> ++--------------------------------------------------------------------------------------------------------------------+ +| | | | | | | | | | +| Calculation 3 | Calculation 2 | Calculation 1 | Calculation O | |p0|p1|p2|p3| +| Oldest | | | | | | | | | ++--------------------------------------------------------------------------------------------------------------------+ +^ ^ ^ ^ ^ ^ +m_buffer p3 p2 p1 p0 a + +m_calculationAreaEnd = p0 +a = addressOfPointerToCalculation(0) +*/ class CalculationStore { public: CalculationStore(); + CalculationStore(char * buffer, int size); Shared::ExpiringPointer calculationAtIndex(int i); typedef KDCoordinate (*HeightComputer)(Calculation * c, bool expanded); Shared::ExpiringPointer push(const char * text, Poincare::Context * context, HeightComputer heightComputer); void deleteCalculationAtIndex(int i); void deleteAll(); + int remainingBufferSize() const { assert(m_calculationAreaEnd >= m_buffer); return m_bufferSize - (m_calculationAreaEnd - m_buffer) - m_numberOfCalculations*sizeof(Calculation*); } int numberOfCalculations() const { return m_numberOfCalculations; } Poincare::Expression ansExpression(Poincare::Context * context); - void tidy(); + int bufferSize() { return m_bufferSize; } + private: - static constexpr int k_maxNumberOfCalculations = 25; - static constexpr int k_bufferSize = 10 * Calculation::k_numberOfExpressions * Constant::MaxSerializedExpressionSize; class CalculationIterator { public: @@ -53,26 +61,22 @@ private: }; CalculationIterator begin() const { return CalculationIterator(m_buffer); } - CalculationIterator end() const { return CalculationIterator(m_bufferEnd); } + CalculationIterator end() const { return CalculationIterator(m_calculationAreaEnd); } - Calculation * bufferCalculationAtIndex(int i); - int remainingBufferSize() const { assert(m_bufferEnd >= m_buffer); return k_bufferSize - (m_bufferEnd - m_buffer); } bool pushSerializeExpression(Poincare::Expression e, char * location, char * * newCalculationsLocation, int numberOfSignificantDigits = Poincare::PrintFloat::k_numberOfStoredSignificantDigits); - char * slideCalculationsToEndOfBuffer(); // returns the new position of the calculations - size_t deleteLastCalculation(const char * calculationsStart = nullptr); - const char * lastCalculationPosition(const char * calculationsStart) const; Shared::ExpiringPointer emptyStoreAndPushUndef(Poincare::Context * context, HeightComputer heightComputer); - char m_buffer[k_bufferSize]; - const char * m_bufferEnd; + char * m_buffer; + int m_bufferSize; + const char * m_calculationAreaEnd; int m_numberOfCalculations; - bool m_slidedBuffer; + + size_t deleteOldestCalculation(); + char * addressOfPointerToCalculationOfIndex(int i) {return m_buffer + m_bufferSize - (m_numberOfCalculations - i)*sizeof(Calculation *);} // Memoization - static constexpr int k_numberOfMemoizedCalculationPointers = 10; - void resetMemoizedModelsAfterCalculationIndex(int index); - int m_indexOfFirstMemoizedCalculationPointer; - mutable Calculation * m_memoizedCalculationPointers[k_numberOfMemoizedCalculationPointers]; + char * beginingOfMemoizationArea() {return addressOfPointerToCalculationOfIndex(0);}; + void recomputeMemoizedPointersAfterCalculationIndex(int index); }; } diff --git a/apps/calculation/test/calculation_store.cpp b/apps/calculation/test/calculation_store.cpp index eb2045778..1ce0c4fe1 100644 --- a/apps/calculation/test/calculation_store.cpp +++ b/apps/calculation/test/calculation_store.cpp @@ -5,9 +5,17 @@ #include #include "../calculation_store.h" +typedef ::Calculation::Calculation::DisplayOutput DisplayOutput; +typedef ::Calculation::Calculation::EqualSign EqualSign ; +typedef ::Calculation::Calculation::NumberOfSignificantDigits NumberOfSignificantDigits; + using namespace Poincare; using namespace Calculation; +static constexpr int calculationBufferSize = 10 * (sizeof(::Calculation::Calculation) + ::Calculation::Calculation::k_numberOfExpressions * ::Constant::MaxSerializedExpressionSize + sizeof(::Calculation::Calculation *)); +char calculationBuffer[calculationBufferSize]; + + void assert_store_is(CalculationStore * store, const char * * result) { for (int i = 0; i < store->numberOfCalculations(); i++) { quiz_assert(strcmp(store->calculationAtIndex(i)->inputText(), result[i]) == 0); @@ -18,7 +26,7 @@ KDCoordinate dummyHeight(::Calculation::Calculation * c, bool expanded) { return QUIZ_CASE(calculation_store) { Shared::GlobalContext globalContext; - CalculationStore store; + CalculationStore store(calculationBuffer,calculationBufferSize); // Store is now {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} const char * result[] = {"9", "8", "7", "6", "5", "4", "3", "2", "1", "0"}; for (int i = 0; i < 10; i++) { @@ -29,101 +37,117 @@ QUIZ_CASE(calculation_store) { assert_store_is(&store, result); for (int i = 9; i > 0; i = i-2) { - store.deleteCalculationAtIndex(i); + store.deleteCalculationAtIndex(i); } // Store is now {9, 7, 5, 3, 1} const char * result2[] = {"9", "7", "5", "3", "1"}; assert_store_is(&store, result2); store.deleteAll(); + + // Checking if the store handles correctly the delete of the oldest calculation when full + static int minSize = ::Calculation::Calculation::MinimalSize(); + char text[2] = {'0', 0}; + while (store.remainingBufferSize() > minSize) { + store.push(text, &globalContext, dummyHeight); + } + int numberOfCalculations1 = store.numberOfCalculations(); + /* The buffer is now to full to push a new calculation. + * Trying to push a new one should delete the oldest one*/ + store.push(text, &globalContext, dummyHeight); + int numberOfCalculations2 = store.numberOfCalculations(); + // The numberOfCalculations should be the same + quiz_assert(numberOfCalculations1 == numberOfCalculations2); + store.deleteAll(); + quiz_assert(store.remainingBufferSize() == store.bufferSize()); } QUIZ_CASE(calculation_ans) { Shared::GlobalContext globalContext; - CalculationStore store; + CalculationStore store(calculationBuffer,calculationBufferSize); store.push("1+3/4", &globalContext, dummyHeight); store.push("ans+2/3", &globalContext, dummyHeight); Shared::ExpiringPointer<::Calculation::Calculation> lastCalculation = store.calculationAtIndex(0); - quiz_assert(lastCalculation->displayOutput(&globalContext) == ::Calculation::Calculation::DisplayOutput::ExactAndApproximate); + quiz_assert(lastCalculation->displayOutput(&globalContext) == DisplayOutput::ExactAndApproximate); quiz_assert(strcmp(lastCalculation->exactOutputText(),"29/12") == 0); store.push("ans+0.22", &globalContext, dummyHeight); lastCalculation = store.calculationAtIndex(0); - quiz_assert(lastCalculation->displayOutput(&globalContext) == ::Calculation::Calculation::DisplayOutput::ExactAndApproximateToggle); - quiz_assert(strcmp(lastCalculation->approximateOutputText(::Calculation::Calculation::NumberOfSignificantDigits::Maximal),"2.6366666666667") == 0); + quiz_assert(lastCalculation->displayOutput(&globalContext) == DisplayOutput::ExactAndApproximateToggle); + quiz_assert(strcmp(lastCalculation->approximateOutputText(NumberOfSignificantDigits::Maximal),"2.6366666666667") == 0); store.deleteAll(); } -void assertCalculationIs(const char * input, ::Calculation::Calculation::DisplayOutput display, ::Calculation::Calculation::EqualSign sign, const char * exactOutput, const char * displayedApproximateOutput, const char * storedApproximateOutput, Context * context, CalculationStore * store) { +void assertCalculationIs(const char * input, DisplayOutput display, EqualSign sign, const char * exactOutput, const char * displayedApproximateOutput, const char * storedApproximateOutput, Context * context, CalculationStore * store) { store->push(input, context, dummyHeight); Shared::ExpiringPointer<::Calculation::Calculation> lastCalculation = store->calculationAtIndex(0); quiz_assert(lastCalculation->displayOutput(context) == display); - if (sign != ::Calculation::Calculation::EqualSign::Unknown) { + if (sign != EqualSign::Unknown) { quiz_assert(lastCalculation->exactAndApproximateDisplayedOutputsAreEqual(context) == sign); } if (exactOutput) { quiz_assert_print_if_failure(strcmp(lastCalculation->exactOutputText(), exactOutput) == 0, input); } if (displayedApproximateOutput) { - quiz_assert_print_if_failure(strcmp(lastCalculation->approximateOutputText(::Calculation::Calculation::NumberOfSignificantDigits::UserDefined), displayedApproximateOutput) == 0, input); + quiz_assert_print_if_failure(strcmp(lastCalculation->approximateOutputText(NumberOfSignificantDigits::UserDefined), displayedApproximateOutput) == 0, input); } if (storedApproximateOutput) { - quiz_assert_print_if_failure(strcmp(lastCalculation->approximateOutputText(::Calculation::Calculation::NumberOfSignificantDigits::Maximal), storedApproximateOutput) == 0, input); + quiz_assert_print_if_failure(strcmp(lastCalculation->approximateOutputText(NumberOfSignificantDigits::Maximal), storedApproximateOutput) == 0, input); } store->deleteAll(); } QUIZ_CASE(calculation_significant_digits) { Shared::GlobalContext globalContext; - CalculationStore store; + CalculationStore store(calculationBuffer,calculationBufferSize); - assertCalculationIs("123456789", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "123456789", "1.234568ᴇ8", "123456789", &globalContext, &store); - assertCalculationIs("1234567", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Equal, "1234567", "1234567", "1234567", &globalContext, &store); + assertCalculationIs("123456789", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "123456789", "1.234568ᴇ8", "123456789", &globalContext, &store); + assertCalculationIs("1234567", DisplayOutput::ApproximateOnly, EqualSign::Equal, "1234567", "1234567", "1234567", &globalContext, &store); } QUIZ_CASE(calculation_display_exact_approximate) { Shared::GlobalContext globalContext; - CalculationStore store; + CalculationStore store(calculationBuffer,calculationBufferSize); - assertCalculationIs("1/2", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Equal, nullptr, nullptr, nullptr, &globalContext, &store); - assertCalculationIs("1/3", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, nullptr, nullptr, nullptr, &globalContext, &store); - assertCalculationIs("1/0", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, "undef", "undef", "undef", &globalContext, &store); - assertCalculationIs("2x-x", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, "undef", "undef", "undef", &globalContext, &store); - assertCalculationIs("[[1,2,3]]", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); - assertCalculationIs("[[1,x,3]]", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "undef", "undef", &globalContext, &store); - assertCalculationIs("28^7", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); - assertCalculationIs("3+√(2)→a", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "√(2)+3", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("1/2", DisplayOutput::ExactAndApproximate, EqualSign::Equal, nullptr, nullptr, nullptr, &globalContext, &store); + assertCalculationIs("1/3", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, nullptr, nullptr, nullptr, &globalContext, &store); + assertCalculationIs("1/0", DisplayOutput::ApproximateOnly, EqualSign::Unknown, "undef", "undef", "undef", &globalContext, &store); + assertCalculationIs("2x-x", DisplayOutput::ApproximateOnly, EqualSign::Unknown, "undef", "undef", "undef", &globalContext, &store); + assertCalculationIs("[[1,2,3]]", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); + assertCalculationIs("[[1,x,3]]", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "undef", "undef", &globalContext, &store); + assertCalculationIs("28^7", DisplayOutput::ExactAndApproximate, EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); + assertCalculationIs("3+√(2)→a", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "√(2)+3", nullptr, nullptr, &globalContext, &store); Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); - assertCalculationIs("3+2→a", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Equal, "5", "5", "5", &globalContext, &store); + assertCalculationIs("3+2→a", DisplayOutput::ApproximateOnly, EqualSign::Equal, "5", "5", "5", &globalContext, &store); Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); - assertCalculationIs("3→a", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Equal, "3", "3", "3", &globalContext, &store); + assertCalculationIs("3→a", DisplayOutput::ApproximateOnly, EqualSign::Equal, "3", "3", "3", &globalContext, &store); Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); - assertCalculationIs("3+x→f(x)", ::Calculation::Calculation::DisplayOutput::ExactOnly, ::Calculation::Calculation::EqualSign::Unknown, "x+3", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("3+x→f(x)", DisplayOutput::ExactOnly, EqualSign::Unknown, "x+3", nullptr, nullptr, &globalContext, &store); Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); - assertCalculationIs("1+1+random()", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); - assertCalculationIs("1+1+round(1.343,2)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "3.34", "3.34", &globalContext, &store); - assertCalculationIs("randint(2,2)+3", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, "5", "5", "5", &globalContext, &store); - assertCalculationIs("confidence(0.5,2)+3", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); - assertCalculationIs("prediction(0.5,2)+3", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); - assertCalculationIs("prediction95(0.5,2)+3", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); + assertCalculationIs("1+1+random()", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); + assertCalculationIs("1+1+round(1.343,2)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "3.34", "3.34", &globalContext, &store); + assertCalculationIs("randint(2,2)+3", DisplayOutput::ApproximateOnly, EqualSign::Unknown, "5", "5", "5", &globalContext, &store); + assertCalculationIs("confidence(0.5,2)+3", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); + assertCalculationIs("prediction(0.5,2)+3", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); + assertCalculationIs("prediction95(0.5,2)+3", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); } QUIZ_CASE(calculation_symbolic_computation) { Shared::GlobalContext globalContext; - CalculationStore store; + CalculationStore store(calculationBuffer,calculationBufferSize); - assertCalculationIs("x+x+1+3+√(π)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, "undef", "undef", "undef", &globalContext, &store); - assertCalculationIs("f(x)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, "undef", "undef", "undef", &globalContext, &store); - assertCalculationIs("1+x→f(x)", ::Calculation::Calculation::DisplayOutput::ExactOnly, ::Calculation::Calculation::EqualSign::Unknown, "x+1", nullptr, nullptr, &globalContext, &store); - assertCalculationIs("f(x)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, "undef", "undef", "undef", &globalContext, &store); - assertCalculationIs("f(2)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Equal, "3", "3", "3", &globalContext, &store); - assertCalculationIs("2→x", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Equal, "2", nullptr, nullptr, &globalContext, &store); - assertCalculationIs("f(x)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Equal, "3", nullptr, nullptr, &globalContext, &store); - assertCalculationIs("x+x+1+3+√(π)", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "√(π)+8", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("x+x+1+3+√(π)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, "undef", "undef", "undef", &globalContext, &store); + assertCalculationIs("f(x)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, "undef", "undef", "undef", &globalContext, &store); + assertCalculationIs("1+x→f(x)", DisplayOutput::ExactOnly, EqualSign::Unknown, "x+1", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("f(x)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, "undef", "undef", "undef", &globalContext, &store); + assertCalculationIs("f(2)", DisplayOutput::ApproximateOnly, EqualSign::Equal, "3", "3", "3", &globalContext, &store); + assertCalculationIs("2→x", DisplayOutput::ApproximateOnly, EqualSign::Equal, "2", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("f(x)", DisplayOutput::ApproximateOnly, EqualSign::Equal, "3", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("x+x+1+3+√(π)", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "√(π)+8", nullptr, nullptr, &globalContext, &store); Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); Ion::Storage::sharedStorage()->recordNamed("x.exp").destroy(); @@ -131,18 +155,18 @@ QUIZ_CASE(calculation_symbolic_computation) { QUIZ_CASE(calculation_symbolic_computation_and_parametered_expressions) { Shared::GlobalContext globalContext; - CalculationStore store; + CalculationStore store(calculationBuffer,calculationBufferSize); - assertCalculationIs("int((ℯ^(-x))-x^(0.5), x, 0, 3)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); // Tests a bug with symbolic computation - assertCalculationIs("int(x,x,0,2)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "2", "2", &globalContext, &store); - assertCalculationIs("sum(x,x,0,2)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "3", "3", &globalContext, &store); - assertCalculationIs("product(x,x,1,2)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "2", "2", &globalContext, &store); - assertCalculationIs("diff(x^2,x,3)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "6", "6", &globalContext, &store); - assertCalculationIs("2→x", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); - assertCalculationIs("int(x,x,0,2)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "2", "2", &globalContext, &store); - assertCalculationIs("sum(x,x,0,2)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "3", "3", &globalContext, &store); - assertCalculationIs("product(x,x,1,2)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "2", "2", &globalContext, &store); - assertCalculationIs("diff(x^2,x,3)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "6", "6", &globalContext, &store); + assertCalculationIs("int((ℯ^(-x))-x^(0.5), x, 0, 3)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); // Tests a bug with symbolic computation + assertCalculationIs("int(x,x,0,2)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "2", "2", &globalContext, &store); + assertCalculationIs("sum(x,x,0,2)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "3", "3", &globalContext, &store); + assertCalculationIs("product(x,x,1,2)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "2", "2", &globalContext, &store); + assertCalculationIs("diff(x^2,x,3)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "6", "6", &globalContext, &store); + assertCalculationIs("2→x", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, nullptr, nullptr, &globalContext, &store); + assertCalculationIs("int(x,x,0,2)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "2", "2", &globalContext, &store); + assertCalculationIs("sum(x,x,0,2)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "3", "3", &globalContext, &store); + assertCalculationIs("product(x,x,1,2)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "2", "2", &globalContext, &store); + assertCalculationIs("diff(x^2,x,3)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "6", "6", &globalContext, &store); Ion::Storage::sharedStorage()->recordNamed("x.exp").destroy(); } @@ -150,34 +174,34 @@ QUIZ_CASE(calculation_symbolic_computation_and_parametered_expressions) { QUIZ_CASE(calculation_complex_format) { Shared::GlobalContext globalContext; - CalculationStore store; + CalculationStore store(calculationBuffer,calculationBufferSize); Poincare::Preferences::sharedPreferences()->setComplexFormat(Poincare::Preferences::ComplexFormat::Real); - assertCalculationIs("1+𝐢", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "1+𝐢", "1+𝐢", &globalContext, &store); - assertCalculationIs("√(-1)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, "unreal", nullptr, nullptr, &globalContext, &store); - assertCalculationIs("ln(-2)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "unreal", "unreal", &globalContext, &store); - assertCalculationIs("√(-1)×√(-1)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "unreal", "unreal", &globalContext, &store); - assertCalculationIs("(-8)^(1/3)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "-2", "-2", &globalContext, &store); - assertCalculationIs("(-8)^(2/3)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "4", "4", &globalContext, &store); - assertCalculationIs("(-2)^(1/4)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "unreal", "unreal", &globalContext, &store); + assertCalculationIs("1+𝐢", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "1+𝐢", "1+𝐢", &globalContext, &store); + assertCalculationIs("√(-1)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, "unreal", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("ln(-2)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "unreal", "unreal", &globalContext, &store); + assertCalculationIs("√(-1)×√(-1)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "unreal", "unreal", &globalContext, &store); + assertCalculationIs("(-8)^(1/3)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "-2", "-2", &globalContext, &store); + assertCalculationIs("(-8)^(2/3)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "4", "4", &globalContext, &store); + assertCalculationIs("(-2)^(1/4)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "unreal", "unreal", &globalContext, &store); Poincare::Preferences::sharedPreferences()->setComplexFormat(Poincare::Preferences::ComplexFormat::Cartesian); - assertCalculationIs("1+𝐢", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "1+𝐢", "1+𝐢", &globalContext, &store); - assertCalculationIs("√(-1)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "𝐢", "𝐢", &globalContext, &store); - assertCalculationIs("ln(-2)", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "ln(-2)", nullptr, nullptr, &globalContext, &store); - assertCalculationIs("√(-1)×√(-1)", ::Calculation::Calculation::DisplayOutput::ApproximateOnly, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "-1", "-1", &globalContext, &store); - assertCalculationIs("(-8)^(1/3)", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "1+√(3)×𝐢", nullptr, nullptr, &globalContext, &store); - assertCalculationIs("(-8)^(2/3)", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "-2+2×√(3)×𝐢", nullptr, nullptr, &globalContext, &store); - assertCalculationIs("(-2)^(1/4)", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "root(8,4)/2+root(8,4)/2×𝐢", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("1+𝐢", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "1+𝐢", "1+𝐢", &globalContext, &store); + assertCalculationIs("√(-1)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "𝐢", "𝐢", &globalContext, &store); + assertCalculationIs("ln(-2)", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "ln(-2)", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("√(-1)×√(-1)", DisplayOutput::ApproximateOnly, EqualSign::Unknown, nullptr, "-1", "-1", &globalContext, &store); + assertCalculationIs("(-8)^(1/3)", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "1+√(3)×𝐢", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("(-8)^(2/3)", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "-2+2×√(3)×𝐢", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("(-2)^(1/4)", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "root(8,4)/2+root(8,4)/2×𝐢", nullptr, nullptr, &globalContext, &store); Poincare::Preferences::sharedPreferences()->setComplexFormat(Poincare::Preferences::ComplexFormat::Polar); - assertCalculationIs("1+𝐢", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "√(2)×ℯ^\u0012π/4×𝐢\u0013", nullptr, nullptr, &globalContext, &store); - assertCalculationIs("√(-1)", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "ℯ^\u0012π/2×𝐢\u0013", nullptr, nullptr, &globalContext, &store); - assertCalculationIs("ln(-2)", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "ln(-2)", nullptr, nullptr, &globalContext, &store); - assertCalculationIs("√(-1)×√(-1)", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "ℯ^\u00123.141593×𝐢\u0013", "ℯ^\u00123.1415926535898×𝐢\u0013", &globalContext, &store); - assertCalculationIs("(-8)^(1/3)", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "2×ℯ^\u0012π/3×𝐢\u0013", nullptr, nullptr, &globalContext, &store); - assertCalculationIs("(-8)^(2/3)", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "4×ℯ^\u0012\u00122×π\u0013/3×𝐢\u0013", nullptr, nullptr, &globalContext, &store); - assertCalculationIs("(-2)^(1/4)", ::Calculation::Calculation::DisplayOutput::ExactAndApproximate, ::Calculation::Calculation::EqualSign::Approximation, "root(2,4)×ℯ^\u0012π/4×𝐢\u0013", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("1+𝐢", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "√(2)×ℯ^\u0012π/4×𝐢\u0013", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("√(-1)", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "ℯ^\u0012π/2×𝐢\u0013", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("ln(-2)", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "ln(-2)", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("√(-1)×√(-1)", DisplayOutput::ExactAndApproximate, EqualSign::Unknown, nullptr, "ℯ^\u00123.141593×𝐢\u0013", "ℯ^\u00123.1415926535898×𝐢\u0013", &globalContext, &store); + assertCalculationIs("(-8)^(1/3)", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "2×ℯ^\u0012π/3×𝐢\u0013", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("(-8)^(2/3)", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "4×ℯ^\u0012\u00122×π\u0013/3×𝐢\u0013", nullptr, nullptr, &globalContext, &store); + assertCalculationIs("(-2)^(1/4)", DisplayOutput::ExactAndApproximate, EqualSign::Approximation, "root(2,4)×ℯ^\u0012π/4×𝐢\u0013", nullptr, nullptr, &globalContext, &store); Poincare::Preferences::sharedPreferences()->setComplexFormat(Poincare::Preferences::ComplexFormat::Cartesian); }