From 5eb0e4f3ffd04f7db18762bdb8ff6119b5b4e304 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 12 Nov 2019 15:27:18 +0100 Subject: [PATCH 01/14] [simulator/android] Use NDK version 16 when available --- build/toolchain.android.mak | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build/toolchain.android.mak b/build/toolchain.android.mak index f24462a72..2249be610 100644 --- a/build/toolchain.android.mak +++ b/build/toolchain.android.mak @@ -9,20 +9,26 @@ endif NDK_TOOLCHAIN_PATH = $(NDK_PATH)/toolchains/llvm/prebuilt/$(NDK_HOST_TAG)/bin +# No 64 bit device has ever shipped with an API level < 21. Consequently, there +# is no toolchain for those archs on those API levels. Let's enforce NDK_VERSION +# at 21 for these archs, and 16 for the others. + ifeq ($(NDK_ABI),armeabi-v7a) NDK_TARGET = armv7a-linux-androideabi + NDK_VERSION = 16 else ifeq ($(NDK_ABI),arm64-v8a) NDK_TARGET = aarch64-linux-android + NDK_VERSION = 21 else ifeq ($(NDK_ABI),x86) NDK_TARGET = i686-linux-android + NDK_VERSION = 16 else ifeq ($(NDK_ABI),x86_64) NDK_TARGET = x86_64-linux-android + NDK_VERSION = 21 endif ifdef NDK_TARGET -NDK_VERSION ?= 21 - CC = $(NDK_TOOLCHAIN_PATH)/$(NDK_TARGET)$(NDK_VERSION)-clang CXX = $(NDK_TOOLCHAIN_PATH)/$(NDK_TARGET)$(NDK_VERSION)-clang++ LD = $(NDK_TOOLCHAIN_PATH)/$(NDK_TARGET)$(NDK_VERSION)-clang++ From b8463088666a0921f8e867679d217bb8447c59f4 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 12 Nov 2019 15:27:45 +0100 Subject: [PATCH 02/14] [simulator/android] Bump compileSdkVersion and targetSdkVersion --- ion/src/simulator/android/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ion/src/simulator/android/build.gradle b/ion/src/simulator/android/build.gradle index 7b1f27a45..eb4c8e160 100644 --- a/ion/src/simulator/android/build.gradle +++ b/ion/src/simulator/android/build.gradle @@ -22,11 +22,11 @@ allprojects { apply plugin: 'com.android.application' android { - compileSdkVersion 28 + compileSdkVersion 29 defaultConfig { applicationId "com.numworks.calculator" minSdkVersion 16 - targetSdkVersion 26 + targetSdkVersion 28 def (major, minor, patch) = System.getenv('EPSILON_VERSION').toLowerCase().tokenize('.').collect{it.toInteger()} versionCode major*1000000 + minor*10000 + patch * 100 versionName System.getenv('EPSILON_VERSION') From 3677e7b1915a7cb8dc25e5a5b9d67b8c986e4604 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 12 Nov 2019 15:00:19 +0100 Subject: [PATCH 03/14] [apps/graph/values_controller] Fix absoluteColumnForValuesColumn Abscissa columns that should not appear in the table were counted --- apps/graph/values/values_controller.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/graph/values/values_controller.cpp b/apps/graph/values/values_controller.cpp index ad48293ee..98eb2862a 100644 --- a/apps/graph/values/values_controller.cpp +++ b/apps/graph/values/values_controller.cpp @@ -255,9 +255,10 @@ int ValuesController::absoluteColumnForValuesColumn(int column) { int valuesColumns = 0; int plotTypeIndex = 0; do { - abscissaColumns++; assert(plotTypeIndex < Shared::ContinuousFunction::k_numberOfPlotTypes); - valuesColumns += m_numberOfValuesColumnsForType[plotTypeIndex++]; + const int numberOfValuesColumnsForType = m_numberOfValuesColumnsForType[plotTypeIndex++]; + valuesColumns += numberOfValuesColumnsForType; + abscissaColumns += (numberOfValuesColumnsForType > 0); } while (valuesColumns <= column); return column + abscissaColumns; } From be6b9d804ca31f8e1f1cd449fe816b88392d0c56 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 12 Nov 2019 14:58:44 +0100 Subject: [PATCH 04/14] [apps/graph/values_controller] Fix assertion in plotTypeAtColumn --- apps/graph/values/values_controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/graph/values/values_controller.cpp b/apps/graph/values/values_controller.cpp index 98eb2862a..d5783efce 100644 --- a/apps/graph/values/values_controller.cpp +++ b/apps/graph/values/values_controller.cpp @@ -237,10 +237,10 @@ int ValuesController::numberOfValuesColumns() { ContinuousFunction::PlotType ValuesController::plotTypeAtColumn(int * i) const { int plotTypeIndex = 0; - while (plotTypeIndex < ContinuousFunction::k_numberOfPlotTypes && *i >= numberOfColumnsForPlotType(plotTypeIndex)) { + while (*i >= numberOfColumnsForPlotType(plotTypeIndex)) { *i -= numberOfColumnsForPlotType(plotTypeIndex++); + assert(plotTypeIndex < ContinuousFunction::k_numberOfPlotTypes); } - assert(plotTypeIndex < ContinuousFunction::k_numberOfPlotTypes); return static_cast(plotTypeIndex); } From ecde47784c89e21dc2fdee7636bf5514503b84eb Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 12 Nov 2019 11:43:11 +0100 Subject: [PATCH 05/14] [apps/shared/values_controller] Avoid extra calls to numberOfMemoizedColumn --- apps/shared/values_controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/shared/values_controller.cpp b/apps/shared/values_controller.cpp index 8dd252be1..1b34ac3f4 100644 --- a/apps/shared/values_controller.cpp +++ b/apps/shared/values_controller.cpp @@ -291,10 +291,10 @@ void ValuesController::resetMemoization() { } char * ValuesController::memoizedBufferForCell(int i, int j) { + const int nbOfMemoizedColumns = numberOfMemoizedColumn(); // Conversion of coordinates from absolute table to values table int valuesI = valuesColumnForAbsoluteColumn(i); int valuesJ = valuesRowForAbsoluteRow(j); - int nbOfMemoizedColumns = numberOfMemoizedColumn(); /* Compute the required offset to apply to the memoized table in order to * display cell (i,j) */ int offsetI = 0; @@ -316,7 +316,7 @@ char * ValuesController::memoizedBufferForCell(int i, int j) { m_firstMemoizedColumn = m_firstMemoizedColumn + offsetI; m_firstMemoizedRow = m_firstMemoizedRow + offsetJ; // Shift already memoized cells - int numberOfMemoizedCell = k_maxNumberOfDisplayableRows*numberOfMemoizedColumn(); + const int numberOfMemoizedCell = k_maxNumberOfDisplayableRows * nbOfMemoizedColumns; size_t moveLength = (numberOfMemoizedCell - absInt(offset))*valuesCellBufferSize()*sizeof(char); if (offset > 0 && offset < numberOfMemoizedCell) { memmove(memoizedBufferAtIndex(offset), memoizedBufferAtIndex(0), moveLength); From bb83f057fe9db6347bcc1850d9504db1010d0452 Mon Sep 17 00:00:00 2001 From: Ruben Dashyan Date: Tue, 12 Nov 2019 15:25:57 +0100 Subject: [PATCH 06/14] [apps/shared/values_controller] Simplify didChangeCell Shift by m_firstMemoizedRow earlier. --- apps/shared/values_controller.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/shared/values_controller.cpp b/apps/shared/values_controller.cpp index 1b34ac3f4..ec0a2c4bd 100644 --- a/apps/shared/values_controller.cpp +++ b/apps/shared/values_controller.cpp @@ -237,14 +237,13 @@ void ValuesController::didChangeCell(int column, int row) { // the first row is never reloaded as it corresponds to title row assert(row > 0); // Conversion of coordinates from absolute table to values table - int valuesRow = valuesRowForAbsoluteRow(row); - if (m_firstMemoizedRow > valuesRow || valuesRow >= m_firstMemoizedRow + k_maxNumberOfDisplayableRows) { + int memoizedRow = valuesRowForAbsoluteRow(row) - m_firstMemoizedRow; + if (0 > memoizedRow || memoizedRow >= k_maxNumberOfDisplayableRows) { // The changed row is out of the memoized table return; } // Update the memoization of rows linked to the changed cell - int memoizedRow = valuesRow - m_firstMemoizedRow; int nbOfMemoizedColumns = numberOfMemoizedColumn(); for (int i = column+1; i < column+numberOfColumnsForAbscissaColumn(column); i++) { int memoizedI = valuesColumnForAbsoluteColumn(i) - m_firstMemoizedColumn; From 5d283a3a3cecc359982572c9b0b9ba5a16f377a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 13 Nov 2019 11:54:44 +0100 Subject: [PATCH 07/14] [build] Add missing EMSCRIPTEN_ASYNC_SYMBOLS --- build/toolchain.emscripten.mak | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/toolchain.emscripten.mak b/build/toolchain.emscripten.mak index 9ac1010a2..fb81cc14b 100644 --- a/build/toolchain.emscripten.mak +++ b/build/toolchain.emscripten.mak @@ -8,7 +8,8 @@ SAFE_HEAP_STORE \ _IonEventsEmscriptenKeyDown \ _IonEventsEmscriptenKeyUp \ _IonEventsEmscriptenPushEvent \ -__Z8ion_mainiPPc \ +_IonSimulatorCallbackDidScanKeyboard \ +__Z8ion_mainiPKPKc \ __ZN10Invocation7performEPv \ __ZN11MicroPython20ExecutionEnvironment7runCodeEPKc \ __ZN13AppsContainer13dispatchEventEN3Ion6Events5EventE \ From 5c070355ade56d81587afb2d11d30a0f27fbbdce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 13 Nov 2019 15:04:51 +0100 Subject: [PATCH 08/14] [ion/simulator] Fix missing include Compilation failed for DEBUG=1 --- ion/src/simulator/shared/events_stdin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ion/src/simulator/shared/events_stdin.cpp b/ion/src/simulator/shared/events_stdin.cpp index b3a00f3e2..4aaa96093 100644 --- a/ion/src/simulator/shared/events_stdin.cpp +++ b/ion/src/simulator/shared/events_stdin.cpp @@ -4,6 +4,8 @@ #include "events.h" #include +#include + #include #include From cfdc6344bf5bac730af893a3ad7ea123f1fc41ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 13 Nov 2019 15:18:03 +0100 Subject: [PATCH 09/14] [simulator] Increase stack size in debug mode This way we can try the tests in DEBUG mode --- ion/src/simulator/shared/main_headless.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ion/src/simulator/shared/main_headless.cpp b/ion/src/simulator/shared/main_headless.cpp index 8dd954729..0f1fee2de 100644 --- a/ion/src/simulator/shared/main_headless.cpp +++ b/ion/src/simulator/shared/main_headless.cpp @@ -14,7 +14,11 @@ #endif constexpr int kHeapSize = 131072; +#if DEBUG +constexpr int kStackSize = 32768*2; // In DEBUG mode, we increase the stack to be able to pass the tests +#else constexpr int kStackSize = 32768; +#endif char heap[kHeapSize]; extern "C" { From 6135fced52f5c2e0d86333f1216d15fbe8a10a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 13 Nov 2019 14:49:44 +0100 Subject: [PATCH 10/14] [poincare] Power: always reduce (a^b)^(-1) --- poincare/src/power.cpp | 14 +++++++++----- poincare/test/simplification.cpp | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index e5ffc985a..77bba4c05 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -625,18 +625,22 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex * --> tan(2)+tan(2)*[tan(2)^1/2]^(-1)/tan(2) * --> tan(2)^(3/2)+tan(2)^(3/2)*[tan(2)^1/2]^(-1)/tan(2)^3/2 * --> ... - * Indeed, we have to apply the rule (a^b)^c -> a^(b*c) as soon as c is an - * integer. + * Indeed, we have to apply the rule (a^b)^c -> a^(b*c) as soon as c is -1. */ if (baseType == ExpressionNode::Type::Power) { Power powerBase = static_cast(base); + bool cInteger = indexType == ExpressionNode::Type::Rational && static_cast(index).isInteger(); bool applyRule = powerBase.childAtIndex(0).sign(reductionContext.context()) == ExpressionNode::Sign::Positive // a > 0 - || (indexType == ExpressionNode::Type::Rational && static_cast(index).isInteger()); // c integer + || cInteger; // c integer + bool cMinusOne = cInteger && static_cast(index).isMinusOne(); /* If the complexFormat is real, we check that the inner power is defined * before applying the rule (a^b)^c -> a^(b*c). Otherwise, we return - * 'unreal' or we do nothing. */ - if (reductionContext.complexFormat() == Preferences::ComplexFormat::Real) { + * 'unreal' or we do nothing. + * We escape this additional check if c = -1 for two reasons: + * - (a^b)^(-1) has to be reduced to avoid infinite loop discussed above; + * - if a^b is unreal, a^(-b) also. */ + if (!cMinusOne && reductionContext.complexFormat() == Preferences::ComplexFormat::Real) { Expression approximation = powerBase.approximate(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); if (approximation.type() == ExpressionNode::Type::Unreal) { // The inner power is unreal, return "unreal" diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 23e1820aa..2699ddc57 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -107,6 +107,7 @@ QUIZ_CASE(poincare_simplification_infinity) { } QUIZ_CASE(poincare_simplification_addition) { + assert_parsed_expression_simplify_to("1/x^2+3", "\u00123×x^2+1\u0013/x^2", User, Radian, Real); assert_parsed_expression_simplify_to("1+x", "x+1"); assert_parsed_expression_simplify_to("1/2+1/3+1/4+1/5+1/6+1/7", "223/140"); assert_parsed_expression_simplify_to("1+x+4-i-2x", "-i-x+5"); From 276af2cccecc988ef8a9d698f76dd8cd6022bb88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 13 Nov 2019 14:20:10 +0100 Subject: [PATCH 11/14] [poincare/test] Test engineering notation --- poincare/test/expression_serialization.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/poincare/test/expression_serialization.cpp b/poincare/test/expression_serialization.cpp index 3c069758f..abe0d4c4a 100644 --- a/poincare/test/expression_serialization.cpp +++ b/poincare/test/expression_serialization.cpp @@ -81,6 +81,7 @@ QUIZ_CASE(poincare_serialization_decimal) { assert_expression_serialize_to(d10, "1.235ᴇ-1", ScientificMode, 4); assert_expression_serialize_to(d10, "123.5ᴇ-3", EngineeringMode, 4); + assert_expression_serialize_to(Decimal::Builder(0.25), "250ᴇ-3", EngineeringMode); assert_expression_serialize_to(Decimal::Builder(-1.23456789E30), "-1.23456789ᴇ30", ScientificMode, 14); assert_expression_serialize_to(Decimal::Builder(1.23456789E30), "1.23456789ᴇ30", ScientificMode, 14); assert_expression_serialize_to(Decimal::Builder(-1.23456789E-30), "-1.23456789ᴇ-30", ScientificMode, 14); From e4afdc475d892d846b5e93bd6d477b34dfbbc705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 13 Nov 2019 15:18:48 +0100 Subject: [PATCH 12/14] [poincare/decimal] Fix engineering notation that removed too many zeroes --- poincare/src/decimal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/decimal.cpp b/poincare/src/decimal.cpp index 3167630b6..1aed6a8a1 100644 --- a/poincare/src/decimal.cpp +++ b/poincare/src/decimal.cpp @@ -24,7 +24,7 @@ void removeZeroAtTheEnd(Integer * i, int minimalNumbersOfDigits = 1) { Integer minimum = Integer((int64_t)std::pow(10.0, minimalNumbersOfDigits-1)); Integer minusMinimum = Integer(-(int64_t)std::pow(10.0, minimalNumbersOfDigits-1)); IntegerDivision d = Integer::Division(*i, base); - while (d.remainder.isZero() && (Integer::NaturalOrder(*i, minimum) > 0 || Integer::NaturalOrder(*i, minusMinimum) < 0)) { + while (d.remainder.isZero() && (Integer::NaturalOrder(d.quotient, minimum) >= 0 || Integer::NaturalOrder(d.quotient, minusMinimum) <= 0)) { *i = d.quotient; d = Integer::Division(*i, base); } From a3da08323be74e09cd80f2c926f7f3daa5fab48e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 13 Nov 2019 15:51:03 +0100 Subject: [PATCH 13/14] [poincare/decimal] Don't always check mantissa length when removing 0s --- poincare/src/decimal.cpp | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/poincare/src/decimal.cpp b/poincare/src/decimal.cpp index 1aed6a8a1..73aaf4c9b 100644 --- a/poincare/src/decimal.cpp +++ b/poincare/src/decimal.cpp @@ -16,15 +16,41 @@ namespace Poincare { static inline int maxInt(int x, int y) { return x > y ? x : y; } -void removeZeroAtTheEnd(Integer * i, int minimalNumbersOfDigits = 1) { +void removeZeroAtTheEnd(Integer * i, int minimalNumbersOfDigits = -1) { + /* Remove the zeroes at the end of an integer, respecting the minimum number + * of digits asked for. + * + * For instance : + * + * i = 1000 + * removeZeroAtTheEnd(&i, 2) + * assert(i==10) + * + * i = 1000 + * removeZeroAtTheEnd(&i, -1) + * assert(i==1) + */ + if (i->isZero()) { return; } + + /* If we check the number of digits, we want *i to stay outside of the + * interval ]-10^numberDigits; 10^numberDigits[. */ + const bool shouldCheckMinimalNumberOfDigits = minimalNumbersOfDigits > 0; + Integer minimum = shouldCheckMinimalNumberOfDigits ? + Integer((int64_t)std::pow(10.0, minimalNumbersOfDigits-1)) : + Integer::Overflow(false); + Integer minusMinimum = shouldCheckMinimalNumberOfDigits ? + Integer(-(int64_t)std::pow(10.0, minimalNumbersOfDigits-1)) : + Integer::Overflow(false); + Integer base = Integer(10); - Integer minimum = Integer((int64_t)std::pow(10.0, minimalNumbersOfDigits-1)); - Integer minusMinimum = Integer(-(int64_t)std::pow(10.0, minimalNumbersOfDigits-1)); IntegerDivision d = Integer::Division(*i, base); - while (d.remainder.isZero() && (Integer::NaturalOrder(d.quotient, minimum) >= 0 || Integer::NaturalOrder(d.quotient, minusMinimum) <= 0)) { + while (d.remainder.isZero()) { + if (shouldCheckMinimalNumberOfDigits && (Integer::NaturalOrder(d.quotient, minimum) < 0 && Integer::NaturalOrder(d.quotient, minusMinimum) > 0)) { + break; + } *i = d.quotient; d = Integer::Division(*i, base); } @@ -136,7 +162,7 @@ int DecimalNode::convertToText(char * buffer, int bufferSize, Preferences::Print } } int exponentForEngineeringNotation = 0; - int minimalNumberOfMantissaDigits = 1; + int minimalNumberOfMantissaDigits = -1; bool removeZeroes = true; if (mode == Preferences::PrintFloatMode::Engineering) { exponentForEngineeringNotation = PrintFloat::EngineeringExponentFromBase10Exponent(exponent); From 90b3e52c0cc14f6091912dfbd1bd1df8189009b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 13 Nov 2019 15:06:14 +0100 Subject: [PATCH 14/14] [poincare] Fix multiplication symbol before Symbol Expression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes consistent 2x and 2θ (sign omission in both cases). --- poincare/include/poincare/symbol.h | 2 +- poincare/src/symbol.cpp | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index 147bf923c..e80f66836 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -34,7 +34,7 @@ public: /* Simplification */ Expression shallowReduce(ReductionContext reductionContext) override; Expression shallowReplaceReplaceableSymbols(Context * context) override; - LayoutShape leftLayoutShape() const override { return strlen(m_name) > 1 ? LayoutShape::MoreLetters : LayoutShape::OneLetter; }; + LayoutShape leftLayoutShape() const override; /* Approximation */ Evaluation approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate(context, complexFormat, angleUnit); } diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 1062d1e67..625523b2d 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -107,6 +107,15 @@ Expression SymbolNode::shallowReplaceReplaceableSymbols(Context * context) { return Symbol(this).shallowReplaceReplaceableSymbols(context); } +ExpressionNode::LayoutShape SymbolNode::leftLayoutShape() const { + UTF8Decoder decoder(m_name); + decoder.nextCodePoint(); + if (decoder.nextCodePoint() == UCodePointNull) { // nextCodePoint asserts that the first character is non-null + return LayoutShape::OneLetter; + } + return LayoutShape::MoreLetters; +} + template Evaluation SymbolNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { Symbol s(this);