diff --git a/apps/regression/model/trigonometric_model.cpp b/apps/regression/model/trigonometric_model.cpp index 2475f61e0..166af2be4 100644 --- a/apps/regression/model/trigonometric_model.cpp +++ b/apps/regression/model/trigonometric_model.cpp @@ -16,6 +16,17 @@ using namespace Shared; namespace Regression { +static double toRadians(Poincare::Preferences::AngleUnit angleUnit) { + switch (Poincare::Preferences::sharedPreferences()->angleUnit()) { + case Poincare::Preferences::AngleUnit::Degree: + return M_PI/180.0; + case Poincare::Preferences::AngleUnit::Gradian: + return M_PI/200.0; + default: + return 1; + } +} + Layout TrigonometricModel::layout() { if (m_layout.isUninitialized()) { const char * s = "a·sin(b·X+c)+d"; @@ -29,7 +40,7 @@ double TrigonometricModel::evaluate(double * modelCoefficients, double x) const double b = modelCoefficients[1]; double c = modelCoefficients[2]; double d = modelCoefficients[3]; - double radianX = Poincare::Preferences::sharedPreferences()->angleUnit() == Poincare::Preferences::AngleUnit::Radian ? x : x * M_PI/180.0; + double radianX = x * toRadians(Poincare::Preferences::sharedPreferences()->angleUnit()); return a*sin(b*radianX+c)+d; } @@ -37,7 +48,7 @@ double TrigonometricModel::partialDerivate(double * modelCoefficients, int deriv double a = modelCoefficients[0]; double b = modelCoefficients[1]; double c = modelCoefficients[2]; - double radianX = Poincare::Preferences::sharedPreferences()->angleUnit() == Poincare::Preferences::AngleUnit::Radian ? x : x * M_PI/180.0; + double radianX = x * toRadians(Poincare::Preferences::sharedPreferences()->angleUnit()); if (derivateCoefficientIndex == 0) { // Derivate: sin(b*x+c) return sin(b*radianX+c); diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 8184d41ff..fea40e9a8 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -11,6 +11,7 @@ ActivateExamMode = "Start Testmodus" ExamModeActive = "Testmodus: aktiv" About = "Über" Degres = "Grad " +Gradians = "Gradians " Radian = "Bogenmaß " Decimal = "Dezimal " Engineering = "Technisch " diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n index d5ddcdbad..f0a0c3ba3 100644 --- a/apps/settings/base.en.i18n +++ b/apps/settings/base.en.i18n @@ -11,6 +11,7 @@ ActivateExamMode = "Activate exam mode" ExamModeActive = "Exam mode: active" About = "About" Degres = "Degrees " +Gradians = "Gradians " Radian = "Radians " Decimal = "Decimal " Scientific = "Scientific " diff --git a/apps/settings/base.es.i18n b/apps/settings/base.es.i18n index 8f45e53a6..7b18d1286 100644 --- a/apps/settings/base.es.i18n +++ b/apps/settings/base.es.i18n @@ -11,6 +11,7 @@ ActivateExamMode = "Activar el modo examen" ExamModeActive = "Modo examen: activo" About = "Acerca" Degres = "Grados " +Gradians = "Gradians " Radian = "Radianes " Engineering = "Ingeniería " Decimal = "Decimal " diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n index 2e2efe1f8..a3f1b3152 100644 --- a/apps/settings/base.fr.i18n +++ b/apps/settings/base.fr.i18n @@ -11,6 +11,7 @@ ActivateExamMode = "Activer le mode examen" ExamModeActive = "Mode examen: actif" About = "À propos" Degres = "Degrés " +Gradians = "Grades " Radian = "Radians " Decimal = "Décimal " Scientific = "Scientifique " diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index 12fb0d757..8b41081fe 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -11,6 +11,7 @@ ActivateExamMode = "Inicio modo de exame" ExamModeActive = "Modo de exame : ativo" About = "Acerca" Degres = "Graus " +Gradians = "Gradians " Radian = "Radianos " Decimal = "Decimal " Scientific = "Científico " diff --git a/apps/settings/main_controller_prompt_beta.cpp b/apps/settings/main_controller_prompt_beta.cpp index 5d9396f6b..cc7f58dfd 100644 --- a/apps/settings/main_controller_prompt_beta.cpp +++ b/apps/settings/main_controller_prompt_beta.cpp @@ -3,7 +3,7 @@ namespace Settings { -constexpr SettingsMessageTree s_modelAngleChildren[2] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Radian)}; +constexpr SettingsMessageTree s_modelAngleChildren[3] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Gradians), SettingsMessageTree(I18n::Message::Radian)}; constexpr SettingsMessageTree s_modelEditionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::Engineering), SettingsMessageTree(I18n::Message::SignificantFigures)}; constexpr SettingsMessageTree s_modelComplexFormatChildren[3] = {SettingsMessageTree(I18n::Message::Real), SettingsMessageTree(I18n::Message::Cartesian), SettingsMessageTree(I18n::Message::Polar)}; @@ -11,7 +11,7 @@ constexpr SettingsMessageTree s_modelExamChildren[1] = {SettingsMessageTree(I18n constexpr SettingsMessageTree s_modelAboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)}; constexpr SettingsMessageTree s_modelMenu[] = - {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren, 2), + {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren, 3), SettingsMessageTree(I18n::Message::DisplayMode, s_modelFloatDisplayModeChildren, 4), SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), diff --git a/apps/settings/main_controller_prompt_none.cpp b/apps/settings/main_controller_prompt_none.cpp index a1c3dfc09..d64d819e0 100644 --- a/apps/settings/main_controller_prompt_none.cpp +++ b/apps/settings/main_controller_prompt_none.cpp @@ -4,7 +4,7 @@ namespace Settings { // TODO: factorize most parts of the final models with main_controller_prompt_beta and main_controller_prompt_update -constexpr SettingsMessageTree s_modelAngleChildren[2] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Radian)}; +constexpr SettingsMessageTree s_modelAngleChildren[3] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Gradians), SettingsMessageTree(I18n::Message::Radian)}; constexpr SettingsMessageTree s_modelEditionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::Engineering), SettingsMessageTree(I18n::Message::SignificantFigures)}; constexpr SettingsMessageTree s_modelComplexFormatChildren[3] = {SettingsMessageTree(I18n::Message::Real), SettingsMessageTree(I18n::Message::Cartesian), SettingsMessageTree(I18n::Message::Polar)}; @@ -12,7 +12,7 @@ constexpr SettingsMessageTree s_modelExamChildren[1] = {SettingsMessageTree(I18n constexpr SettingsMessageTree s_modelAboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)}; constexpr SettingsMessageTree s_modelMenu[] = - {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren, 2), + {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren, 3), SettingsMessageTree(I18n::Message::DisplayMode, s_modelFloatDisplayModeChildren, 4), SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), diff --git a/apps/settings/main_controller_prompt_update.cpp b/apps/settings/main_controller_prompt_update.cpp index 00783f1df..f2b0b306b 100644 --- a/apps/settings/main_controller_prompt_update.cpp +++ b/apps/settings/main_controller_prompt_update.cpp @@ -7,7 +7,7 @@ namespace Settings { namespace Settings { -constexpr SettingsMessageTree s_modelAngleChildren[2] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Radian)}; +constexpr SettingsMessageTree s_modelAngleChildren[3] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Gradians), SettingsMessageTree(I18n::Message::Radian)}; constexpr SettingsMessageTree s_modelEditionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::Engineering), SettingsMessageTree(I18n::Message::SignificantFigures)}; constexpr SettingsMessageTree s_modelComplexFormatChildren[3] = {SettingsMessageTree(I18n::Message::Real), SettingsMessageTree(I18n::Message::Cartesian), SettingsMessageTree(I18n::Message::Polar)}; @@ -15,7 +15,7 @@ constexpr SettingsMessageTree s_modelExamChildren[1] = {SettingsMessageTree(I18n constexpr SettingsMessageTree s_modelAboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)}; constexpr SettingsMessageTree s_modelMenu[] = - {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren, 2), + {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren, 3), SettingsMessageTree(I18n::Message::DisplayMode, s_modelFloatDisplayModeChildren, 4), SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren, 3), diff --git a/apps/settings/sub_menu/preferences_controller.cpp b/apps/settings/sub_menu/preferences_controller.cpp index 2429a0074..7f7902cd4 100644 --- a/apps/settings/sub_menu/preferences_controller.cpp +++ b/apps/settings/sub_menu/preferences_controller.cpp @@ -58,6 +58,11 @@ Layout PreferencesController::layoutForPreferences(I18n::Message message) { const char * degEx = "90°"; return LayoutHelper::String(degEx, strlen(degEx), k_layoutFont); } + case I18n::Message::Gradians: + { + const char * degEx = "100 gon"; + return LayoutHelper::String(degEx, strlen(degEx), k_layoutFont); + } case I18n::Message::Radian: return FractionLayout::Builder( CodePointLayout::Builder(UCodePointGreekSmallLetterPi, k_layoutFont), diff --git a/apps/shared.de.i18n b/apps/shared.de.i18n index da4a09283..0fc50f192 100644 --- a/apps/shared.de.i18n +++ b/apps/shared.de.i18n @@ -21,6 +21,7 @@ FillWithFormula = "Mit einer Formel füllen" ForbiddenValue = "Verbotener Wert" FunctionColumn = "0(0) Spalte" FunctionOptions = "Funktionsoptionen" +Gon = "gon" Goto = "Gehe zu" GraphTab = "Graph" HardwareTestLaunch1 = "Sie sind dabei den Hardwaretest zu" diff --git a/apps/shared.en.i18n b/apps/shared.en.i18n index 625a37ec8..8fa627e44 100644 --- a/apps/shared.en.i18n +++ b/apps/shared.en.i18n @@ -21,6 +21,7 @@ FillWithFormula = "Fill with a formula" ForbiddenValue = "Forbidden value" FunctionColumn = "0(0) column" FunctionOptions = "Function options" +Gon = "gon" Goto = "Go to" GraphTab = "Graph" HardwareTestLaunch1 = "You are starting the hardware" diff --git a/apps/shared.es.i18n b/apps/shared.es.i18n index dda6b3622..afa03d9cf 100644 --- a/apps/shared.es.i18n +++ b/apps/shared.es.i18n @@ -21,6 +21,7 @@ FillWithFormula = "Rellenar con una fórmula" ForbiddenValue = "Valor prohibido" FunctionColumn = "Columna 0(0)" FunctionOptions = "Opciones de la función" +Gon = "gon" Goto = "Ir a" GraphTab = "Gráfico" HardwareTestLaunch1 = "Esta iniciando la prueba de" diff --git a/apps/shared.fr.i18n b/apps/shared.fr.i18n index e07ab4d63..98339a194 100644 --- a/apps/shared.fr.i18n +++ b/apps/shared.fr.i18n @@ -21,6 +21,7 @@ FillWithFormula = "Remplir avec une formule" ForbiddenValue = "Valeur interdite" FunctionColumn = "Colonne 0(0)" FunctionOptions = "Options de la fonction" +Gon = "gon" Goto = "Aller à" GraphTab = "Graphique" HardwareTestLaunch1 = "Vous allez lancer le test usine." diff --git a/apps/shared.pt.i18n b/apps/shared.pt.i18n index 6ea6a7d59..a86b7aa97 100644 --- a/apps/shared.pt.i18n +++ b/apps/shared.pt.i18n @@ -21,6 +21,7 @@ FillWithFormula = "Preencher com uma fórmula" ForbiddenValue = "Valor proibida" FunctionColumn = "Coluna 0(0)" FunctionOptions = "Opções de função" +Gon = "gon" Goto = "Ir a" GraphTab = "Gráfico" HardwareTestLaunch1 = "Você vai executar o teste da planta." diff --git a/apps/title_bar_view.cpp b/apps/title_bar_view.cpp index 24ea593ae..535ef018a 100644 --- a/apps/title_bar_view.cpp +++ b/apps/title_bar_view.cpp @@ -91,6 +91,8 @@ void TitleBarView::refreshPreferences() { assert(numberOfChar <= bufferSize); if (preferences->angleUnit() == Preferences::AngleUnit::Radian) { numberOfChar += strlcpy(buffer+numberOfChar, I18n::translate(I18n::Message::Rad), bufferSize - numberOfChar); + } else if (preferences->angleUnit() == Preferences::AngleUnit::Gradian) { + numberOfChar += strlcpy(buffer+numberOfChar, I18n::translate(I18n::Message::Gon), bufferSize - numberOfChar); } else { numberOfChar += strlcpy(buffer+numberOfChar, I18n::translate(I18n::Message::Deg), bufferSize - numberOfChar); } diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 511745046..b94435132 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -223,8 +223,9 @@ public: Expression mapOnMatrixFirstChild(ExpressionNode::ReductionContext reductionContext); static Expression ExpressionWithoutSymbols(Expression expressionWithSymbols, Context * context); - Expression radianToDegree(); - Expression degreeToRadian(); + + Expression radianToAngleUnit(Preferences::AngleUnit angleUnit); + Expression angleUnitToRadian(Preferences::AngleUnit angleUnit); /* Approximation Helper */ // These methods reset the sApproximationEncounteredComplex flag. They should not be use to implement node approximation diff --git a/poincare/include/poincare/preferences.h b/poincare/include/poincare/preferences.h index 19b17e000..e0b1dbcb1 100644 --- a/poincare/include/poincare/preferences.h +++ b/poincare/include/poincare/preferences.h @@ -28,7 +28,8 @@ public: }; enum class AngleUnit { Degree = 0, - Radian = 1 + Gradian = 1, + Radian = 2 }; Preferences(); static Preferences * sharedPreferences(); diff --git a/poincare/include/poincare/trigonometry_cheat_table.h b/poincare/include/poincare/trigonometry_cheat_table.h index 7996dd8a1..2971e522a 100644 --- a/poincare/include/poincare/trigonometry_cheat_table.h +++ b/poincare/include/poincare/trigonometry_cheat_table.h @@ -23,10 +23,11 @@ public: constexpr static int k_numberOfEntries = 37; enum class Type { AngleInDegrees = 0, - AngleInRadians = 1, - Cosine = 2, - Sine = 3, - Tangent = 4 + AngleInGradians = 1, + AngleInRadians = 2, + Cosine = 3, + Sine = 4, + Tangent = 5 }; static const TrigonometryCheatTable * Table(); Expression simplify(const Expression e, ExpressionNode::Type type, ExpressionNode::ReductionContext reductionContext) const; @@ -50,8 +51,8 @@ private: }; // END OF PAIR CLASS - constexpr Row(Pair angleInRadians, Pair angleInDegrees, Pair sine, Pair cosine, Pair tangent) : - m_pairs{angleInRadians, angleInDegrees, sine, cosine, tangent} {} + constexpr Row(Pair angleInRadians, Pair angleInGradians, Pair angleInDegrees, Pair sine, Pair cosine, Pair tangent) : + m_pairs{angleInRadians, angleInGradians, angleInDegrees, sine, cosine, tangent} {} float floatForType(Type t) const { assert(((int) t) >= 0 && ((int) t) < k_numberOfPairs); return m_pairs[(int)t].value(); @@ -61,7 +62,7 @@ private: return m_pairs[(int)t].reducedExpression(assertNotUninitialized, reductionContext); } private: - constexpr static int k_numberOfPairs = 5; + constexpr static int k_numberOfPairs = 6; const Pair m_pairs[k_numberOfPairs]; }; // END OF ROW CLASS diff --git a/poincare/src/complex_cartesian.cpp b/poincare/src/complex_cartesian.cpp index f7c101faa..8604e6017 100644 --- a/poincare/src/complex_cartesian.cpp +++ b/poincare/src/complex_cartesian.cpp @@ -150,8 +150,8 @@ Expression ComplexCartesian::argument(ExpressionNode::ReductionContext reduction Expression divab = Division::Builder(a, b.clone()); Expression arcTangent = ArcTangent::Builder(divab); divab.shallowReduce(reductionContext); - if (reductionContext.angleUnit() == Preferences::AngleUnit::Degree) { - Expression temp = arcTangent.degreeToRadian(); + if (reductionContext.angleUnit() != Preferences::AngleUnit::Radian) { + Expression temp = arcTangent.angleUnitToRadian(reductionContext.angleUnit()); arcTangent.shallowReduce(reductionContext); arcTangent = temp; } @@ -352,8 +352,8 @@ ComplexCartesian ComplexCartesian::power(ComplexCartesian & other, ExpressionNod thc.shallowReduce(reductionContext); dlnr.shallowReduce(reductionContext); - if (reductionContext.angleUnit() == Preferences::AngleUnit::Degree) { - Expression temp = argument.radianToDegree(); + if (reductionContext.angleUnit() != Preferences::AngleUnit::Radian) { + Expression temp = argument.radianToAngleUnit(reductionContext.angleUnit()); argument.shallowReduce(reductionContext); argument = temp; } diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 51dd57e58..5cc99f2f3 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -691,14 +691,28 @@ Expression Expression::mapOnMatrixFirstChild(ExpressionNode::ReductionContext re return matrix.shallowReduce(reductionContext); } -Expression Expression::radianToDegree() { - // e*180/Pi - return Multiplication::Builder(*this, Rational::Builder(180), Power::Builder(Constant::Builder(UCodePointGreekSmallLetterPi), Rational::Builder(-1))); +Expression Expression::radianToAngleUnit(Preferences::AngleUnit angleUnit) { + if (angleUnit == Preferences::AngleUnit::Degree) { + // e*180/Pi + return Multiplication::Builder(*this, Rational::Builder(180), Power::Builder(Constant::Builder(UCodePointGreekSmallLetterPi), Rational::Builder(-1))); + } + else if (angleUnit == Preferences::AngleUnit::Gradian) { + // e*200/Pi + return Multiplication::Builder(*this, Rational::Builder(200), Power::Builder(Constant::Builder(UCodePointGreekSmallLetterPi), Rational::Builder(-1))); + } + return *this; } -Expression Expression::degreeToRadian() { - // e*Pi/180 - return Multiplication::Builder(*this, Rational::Builder(1, 180), Constant::Builder(UCodePointGreekSmallLetterPi)); +Expression Expression::angleUnitToRadian(Preferences::AngleUnit angleUnit) { + if (angleUnit == Preferences::AngleUnit::Degree) { + // e*Pi/180 + return Multiplication::Builder(*this, Rational::Builder(1, 180), Constant::Builder(UCodePointGreekSmallLetterPi)); + } + else if (angleUnit == Preferences::AngleUnit::Gradian) { + // e*Pi/200 + return Multiplication::Builder(*this, Rational::Builder(1, 200), Constant::Builder(UCodePointGreekSmallLetterPi)); + } + return *this; } Expression Expression::reduce(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { diff --git a/poincare/src/trigonometry.cpp b/poincare/src/trigonometry.cpp index 3b834770b..14e3eacc5 100644 --- a/poincare/src/trigonometry.cpp +++ b/poincare/src/trigonometry.cpp @@ -21,6 +21,27 @@ namespace Poincare { +static constexpr double s_pi[] = { + 180.0, + 200.0, + M_PI +}; + +static constexpr int s_piDivisor[] { + 180, + 200, + 1 +}; + +static Expression piExpression(Preferences::AngleUnit angleUnit) { + switch (angleUnit) { + case Preferences::AngleUnit::Radian: + return static_cast(Constant::Builder(UCodePointGreekSmallLetterPi)); + default: + return static_cast(Rational::Builder(180)); + } +} + float Trigonometry::characteristicXRange(const Expression & e, Context * context, Preferences::AngleUnit angleUnit) { assert(e.numberOfChildren() == 1); @@ -43,7 +64,7 @@ float Trigonometry::characteristicXRange(const Expression & e, Context * context * derivative of child(0) for any x value. */ Poincare::Derivative derivative = Poincare::Derivative::Builder(e.childAtIndex(0).clone(), Symbol::Builder(x, 1), Float::Builder(1.0f)); float a = derivative.node()->approximate(float(), context, Preferences::ComplexFormat::Real, angleUnit).toScalar(); - float pi = angleUnit == Preferences::AngleUnit::Radian ? M_PI : 180.0f; + float pi = s_pi[(int)angleUnit]; return 2.0f*pi/std::fabs(a); } @@ -202,15 +223,15 @@ Expression Trigonometry::shallowReduceDirectFunction(Expression & e, ExpressionN && e.childAtIndex(0).childAtIndex(1).type() == ExpressionNode::Type::Constant && e.childAtIndex(0).childAtIndex(1).convert().isPi() && e.childAtIndex(0).childAtIndex(0).type() == ExpressionNode::Type::Rational) - || (reductionContext.angleUnit() == Preferences::AngleUnit::Degree + || ((reductionContext.angleUnit() == Preferences::AngleUnit::Degree || reductionContext.angleUnit() == Preferences::AngleUnit::Gradian) && e.childAtIndex(0).type() == ExpressionNode::Type::Rational)) { Rational r = reductionContext.angleUnit() == Preferences::AngleUnit::Radian ? e.childAtIndex(0).childAtIndex(0).convert() : e.childAtIndex(0).convert(); /* Step 4.1. In radians: * We first check if p/q * π is already in the right quadrant: * p/q * π < π/2 => p/q < 2 => 2p < q */ - Integer dividand = reductionContext.angleUnit() == Preferences::AngleUnit::Radian ? Integer::Addition(r.unsignedIntegerNumerator(), r.unsignedIntegerNumerator()) : r.unsignedIntegerNumerator(); - Integer divisor = reductionContext.angleUnit() == Preferences::AngleUnit::Radian ? r.integerDenominator() : Integer::Multiplication(r.integerDenominator(), Integer(90)); + Integer dividand = Integer::Addition(r.unsignedIntegerNumerator(), r.unsignedIntegerNumerator()); + Integer divisor = Integer::Multiplication(r.integerDenominator(), Integer(s_piDivisor[(int)reductionContext.angleUnit()])); if (divisor.isLowerThan(dividand)) { /* Step 4.2. p/q * π is not in the wanted trigonometrical quadrant. * We could subtract n*π to p/q with n an integer. @@ -218,9 +239,9 @@ Expression Trigonometry::shallowReduceDirectFunction(Expression & e, ExpressionN * (p/q * π - q'*π) < π/2 => r'/q < 1/2 => 2*r'(Constant::Builder(UCodePointGreekSmallLetterPi)) : static_cast(Rational::Builder(180)); + Expression pi = piExpression(reductionContext.angleUnit()); Subtraction s = Subtraction::Builder(); e.replaceWithInPlace(s); s.replaceChildAtIndexInPlace(0, pi); @@ -365,6 +386,9 @@ std::complex Trigonometry::ConvertToRadian(const std::complex c, Preferenc if (angleUnit == Preferences::AngleUnit::Degree) { return c * std::complex(M_PI/180.0); } + else if (angleUnit == Preferences::AngleUnit::Gradian) { + return c * std::complex(M_PI/200.0); + } return c; } @@ -373,6 +397,9 @@ std::complex Trigonometry::ConvertRadianToAngleUnit(const std::complex c, if (angleUnit == Preferences::AngleUnit::Degree) { return c * std::complex(180/M_PI); } + else if (angleUnit == Preferences::AngleUnit::Gradian) { + return c * std::complex(200/M_PI); + } return c; } diff --git a/poincare/src/trigonometry_cheat_table.cpp b/poincare/src/trigonometry_cheat_table.cpp index 0fb6e71e8..c7e729397 100644 --- a/poincare/src/trigonometry_cheat_table.cpp +++ b/poincare/src/trigonometry_cheat_table.cpp @@ -2,6 +2,12 @@ namespace Poincare { +static constexpr TrigonometryCheatTable::Type s_targetType[] = { + TrigonometryCheatTable::Type::AngleInDegrees, + TrigonometryCheatTable::Type::AngleInGradians, + TrigonometryCheatTable::Type::AngleInRadians +}; + Expression TrigonometryCheatTable::Row::Pair::reducedExpression(bool assertNotUninitialized, ExpressionNode::ReductionContext reductionContext) const { Expression e = Expression::Parse(m_expression); if (assertNotUninitialized) { @@ -23,7 +29,7 @@ Expression TrigonometryCheatTable::simplify(const Expression e, ExpressionNode:: || type == ExpressionNode::Type::ArcTangent); // Compute the input and output types - Type angleUnitType = reductionContext.angleUnit() == Preferences::AngleUnit::Radian ? Type::AngleInRadians : Type::AngleInDegrees; + Type angleUnitType = s_targetType[(int)reductionContext.angleUnit()]; Type trigonometricFunctionType; if (type == ExpressionNode::Type::Cosine || type == ExpressionNode::Type::ArcCosine) { trigonometricFunctionType = Type::Cosine; @@ -37,7 +43,7 @@ Expression TrigonometryCheatTable::simplify(const Expression e, ExpressionNode:: Type outputType = isIndirectType ? angleUnitType : trigonometricFunctionType; // Avoid looping if we can exclude quickly that e is in the table - if ((inputType == Type::AngleInDegrees + if (((inputType == Type::AngleInDegrees || inputType == Type::AngleInGradians) && e.type() != ExpressionNode::Type::Rational) || (inputType == Type::AngleInRadians && e.type() != ExpressionNode::Type::Rational @@ -78,186 +84,223 @@ Expression TrigonometryCheatTable::simplify(const Expression e, ExpressionNode:: const TrigonometryCheatTable * TrigonometryCheatTable::Table() { static Row sTableRows[] = { Row(Row::Pair("-90", -90.0f), + Row::Pair("-100", -100.0f), Row::Pair("π*(-2)^(-1)", -1.5707963267948966f), Row::Pair(""), Row::Pair("-1",-1.0f), Row::Pair("undef")), Row(Row::Pair("-75",-75.0), + Row::Pair("-250/3",-250.0/3), Row::Pair("π*(-5)*12^(-1)",-1.3089969389957472f), Row::Pair(""), Row::Pair("(-1)*6^(1/2)*4^(-1)-2^(1/2)*4^(-1)",-0.9659258262890683f), Row::Pair("-(3^(1/2)+2)",-3.7320508075688776f)), Row(Row::Pair("-72",-72.0), + Row::Pair("-80",-80), Row::Pair("π*2*(-5)^(-1)",-1.2566370614359172f), Row::Pair(""), Row::Pair("-(5/8+5^(1/2)/8)^(1/2)",-0.9510565162951535f), Row::Pair("-(5+2*5^(1/2))^(1/2)",-3.077683537175253f)), Row(Row::Pair("-135/2",67.5f), + Row::Pair("-75",-75.0), Row::Pair("π*(-3)*8^(-1)",-1.1780972450961724f), Row::Pair(""), Row::Pair("-(2+2^(1/2))^(1/2)*2^(-1)",-0.9238795325112867f), Row::Pair("-1-2^(1/2)",-2.4142135623730945f)), Row(Row::Pair("-60",-60.0f), + Row::Pair("-200/3",-200.0/3), Row::Pair("π*(-3)^(-1)",-1.0471975511965976f), Row::Pair(""), Row::Pair("-3^(1/2)*2^(-1)",-0.8660254037844386f), Row::Pair("-3^(1/2)",-1.7320508075688767f)), Row(Row::Pair("-54",-54.0f), + Row::Pair("-60",-60.0), Row::Pair("π*(-3)*10^(-1)",-0.9424777960769379), Row::Pair(""), Row::Pair("4^(-1)*(-1-5^(1/2))",-0.8090169943749473f), Row::Pair("-(1+2*5^(-1/2))^(1/2)",-1.3763819204711731f)), Row(Row::Pair("-45",-45.0f), + Row::Pair("-50",-50), Row::Pair("π*(-4)^(-1)",-0.7853981633974483f), Row::Pair(""), Row::Pair("(-1)*(2^(-1/2))",-0.7071067811865475f), Row::Pair("-1",-1.0f)), Row(Row::Pair("-36",-36.0f), + Row::Pair("-40",-40.0), Row::Pair("π*(-5)^(-1)",-0.6283185307179586f), Row::Pair(""), Row::Pair("-(5/8-5^(1/2)/8)^(1/2)",-0.5877852522924731f), Row::Pair("-(5-2*5^(1/2))^(1/2)",-0.7265425280053609f)), Row(Row::Pair("-30",-30.0f), + Row::Pair("-100/3",-100/3), Row::Pair("π*(-6)^(-1)",-0.5235987755982988f), Row::Pair(""), Row::Pair("-0.5",-0.5f), Row::Pair("-3^(-1/2)",-0.5773502691896256f)), Row(Row::Pair("-45/2",-22.5f), + Row::Pair("-25",-25.0), Row::Pair("π*(-8)^(-1)",-0.39269908169872414f), Row::Pair(""), Row::Pair("(2-2^(1/2))^(1/2)*(-2)^(-1)",-0.3826834323650898f), Row::Pair("1-2^(1/2)",-0.4142135623730951f)), Row(Row::Pair("-18",-18.0f), + Row::Pair("-20",-20.0), Row::Pair("π*(-10)^(-1)",-0.3141592653589793f), Row::Pair(""), Row::Pair("4^(-1)*(1-5^(1/2))",-0.3090169943749474f), Row::Pair("-(1-2*5^(-1/2))^(1/2)",-0.3249196962329063f)), Row(Row::Pair("-15",-15.0f), + Row::Pair("-50/3",-50.0/3), Row::Pair("π*(-12)^(-1)",-0.2617993877991494f), Row::Pair(""), Row::Pair("-6^(1/2)*4^(-1)+2^(1/2)*4^(-1)",-0.25881904510252074f), Row::Pair("3^(1/2)-2",-0.2679491924311227f)), Row(Row::Pair("0",0.0f), + Row::Pair("0",0.0f), Row::Pair("0",0.0f), Row::Pair("1",1.0f), Row::Pair("0",0.0f), Row::Pair("0",0.0f)), Row(Row::Pair("15",15.0f), + Row::Pair("50/3",50.0/3), Row::Pair("π*12^(-1)",0.2617993877991494f), Row::Pair("6^(1/2)*4^(-1)+2^(1/2)*4^(-1)",0.9659258262890683f), Row::Pair("6^(1/2)*4^(-1)+2^(1/2)*(-4)^(-1)",0.25881904510252074f), Row::Pair("-(3^(1/2)-2)",0.2679491924311227f)), Row(Row::Pair("18",18.0f), + Row::Pair("20",20.0), Row::Pair("π*10^(-1)",0.3141592653589793f), Row::Pair("(5/8+5^(1/2)/8)^(1/2)",0.9510565162951535f), Row::Pair("4^(-1)*(5^(1/2)-1)",0.3090169943749474f), Row::Pair("(1-2*5^(-1/2))^(1/2)",0.3249196962329063f)), Row(Row::Pair("45/2",22.5f), + Row::Pair("25",25.0), Row::Pair("π*8^(-1)",0.39269908169872414f), Row::Pair("(2+2^(1/2))^(1/2)*2^(-1)",0.9238795325112867f), Row::Pair("(2-2^(1/2))^(1/2)*2^(-1)",0.3826834323650898f), Row::Pair("2^(1/2)-1",0.4142135623730951f)), Row(Row::Pair("30",30.0f), + Row::Pair("100/3",100/3), Row::Pair("π*6^(-1)",0.5235987755982988f), Row::Pair("3^(1/2)*2^(-1)",0.8660254037844387f), Row::Pair("0.5",0.5f), Row::Pair("3^(-1/2)",0.5773502691896256f)), Row(Row::Pair("36",36.0f), + Row::Pair("40",40.0), Row::Pair("π*5^(-1)",0.6283185307179586f), Row::Pair("(5^(1/2)+1)*4^(-1)",0.8090169943749475f), Row::Pair("(5/8-5^(1/2)/8)^(1/2)",0.5877852522924731f), Row::Pair("(5-2*5^(1/2))^(1/2)",0.7265425280053609f)), Row(Row::Pair("45",45.0f), + Row::Pair("50",50), Row::Pair("π*4^(-1)",0.7853981633974483f), Row::Pair("2^(-1/2)",0.7071067811865476f), Row::Pair("2^(-1/2)",0.7071067811865475f), Row::Pair("1",1.0f)), Row(Row::Pair("54",54.0f), + Row::Pair("60",60.0), Row::Pair("π*3*10^(-1)",0.9424777960769379f), Row::Pair("(5/8-5^(1/2)/8)^(1/2)",0.5877852522924732f), Row::Pair("4^(-1)*(5^(1/2)+1)",0.8090169943749473f), Row::Pair("(1+2*5^(-1/2))^(1/2)",1.3763819204711731f)), Row(Row::Pair("60",60.0f), + Row::Pair("200/3",200.0/3), Row::Pair("π*3^(-1)",1.0471975511965976f), Row::Pair("0.5",0.5f), Row::Pair("3^(1/2)*2^(-1)",0.8660254037844386f), Row::Pair("3^(1/2)",1.7320508075688767f)), Row(Row::Pair("135/2",67.5f), + Row::Pair("75",75.0), Row::Pair("π*3*8^(-1)",1.1780972450961724f), Row::Pair("(2-2^(1/2))^(1/2)*2^(-1)",0.38268343236508984f), Row::Pair("(2+2^(1/2))^(1/2)*2^(-1)",0.9238795325112867f), Row::Pair("1+2^(1/2)",2.4142135623730945f)), Row(Row::Pair("72",72.0f), + Row::Pair("80",80), Row::Pair("π*2*5^(-1)",1.2566370614359172f), Row::Pair("(5^(1/2)-1)*4^(-1)",0.30901699437494745f), Row::Pair("(5/8+5^(1/2)/8)^(1/2)",0.9510565162951535f), Row::Pair("(5+2*5^(1/2))^(1/2)",3.077683537175253f)), Row(Row::Pair("75",75.0f), + Row::Pair("250/3",250.0/3), Row::Pair("π*5*12^(-1)",1.3089969389957472f), Row::Pair("6^(1/2)*4^(-1)+2^(1/2)*(-4)^(-1)",0.25881904510252074f), Row::Pair("6^(1/2)*4^(-1)+2^(1/2)*4^(-1)",0.9659258262890683f), Row::Pair("3^(1/2)+2",3.7320508075688776f)), Row(Row::Pair("90",90.0f), + Row::Pair("100",100.0f), Row::Pair("π*2^(-1)",1.5707963267948966f), Row::Pair("0",0.0f), Row::Pair("1",1.0f), Row::Pair("undef")), Row(Row::Pair("105",105.0f), + Row::Pair("350/3",350.0/3), Row::Pair("π*7*12^(-1)",1.832595714594046f), Row::Pair("-6^(1/2)*4^(-1)+2^(1/2)*4^(-1)",-0.25881904510252063f), Row::Pair(""), Row::Pair("")), Row(Row::Pair("108",108.0f), + Row::Pair("120",120.0), Row::Pair("π*3*5^(-1)",1.8849555921538759f), Row::Pair("(1-5^(1/2))*4^(-1)",-0.30901699437494734f), Row::Pair(""), Row::Pair("")), Row(Row::Pair("225/2",112.5f), + Row::Pair("125",125), Row::Pair("π*5*8^(-1)",1.9634954084936207f), Row::Pair("(2-2^(1/2))^(1/2)*(-2)^(-1)",-0.3826834323650897f), Row::Pair(""), Row::Pair("")), Row(Row::Pair("120",120.0f), + Row::Pair("400/3",400/3), Row::Pair("π*2*3^(-1)",2.0943951023931953f), Row::Pair("-0.5",-0.5f), Row::Pair(""), Row::Pair("")), Row(Row::Pair("126",126.0f), + Row::Pair("140",140), Row::Pair("π*7*10^(-1)",2.199114857512855f), Row::Pair("-(5*8^(-1)-5^(1/2)*8^(-1))^(1/2)",-0.587785252292473f), Row::Pair(""), Row::Pair("")), Row(Row::Pair("135",135.0f), + Row::Pair("150",150.0), Row::Pair("π*3*4^(-1)",2.356194490192345f), Row::Pair("(-1)*(2^(-1/2))",-0.7071067811865475f), Row::Pair(""), Row::Pair("")), Row(Row::Pair("144",144.0f), + Row::Pair("160",160.0), Row::Pair("π*4*5^(-1)",2.5132741228718345f), Row::Pair("(-5^(1/2)-1)*4^(-1)",-0.8090169943749473f), Row::Pair(""), Row::Pair("")), Row(Row::Pair("150",150.0f), + Row::Pair("500/3",500.0/3), Row::Pair("π*5*6^(-1)",2.6179938779914944f), Row::Pair("-3^(1/2)*2^(-1)",-0.8660254037844387f), Row::Pair(""), Row::Pair("")), Row(Row::Pair("315/2",157.5f), + Row::Pair("350",350.0), Row::Pair("π*7*8^(-1)",2.748893571891069f), Row::Pair("-(2+2^(1/2))^(1/2)*2^(-1)",-0.9238795325112867f), Row::Pair(""), Row::Pair("")), Row(Row::Pair("162",162.0f), + Row::Pair("180",180.0), Row::Pair("π*9*10^(-1)",2.827433388230814f), Row::Pair("-(5*8^(-1)+5^(1/2)*8^(-1))^(1/2)",-0.9510565162951535f), Row::Pair(""), Row::Pair("")), Row(Row::Pair("165",165.0f), + Row::Pair("550/3",550.0/3), Row::Pair("π*11*12^(-1)",2.8797932657906435f), Row::Pair("(-1)*6^(1/2)*4^(-1)-2^(1/2)*4^(-1)",-0.9659258262890682f), Row::Pair(""), Row::Pair("")), Row(Row::Pair("180",180.0f), + Row::Pair("200",200.0), Row::Pair("π",3.141592653589793f), Row::Pair("-1",-1.0f), Row::Pair("0",0.0f), diff --git a/poincare/test/approximation.cpp b/poincare/test/approximation.cpp index 90879fb3b..17ca98f76 100644 --- a/poincare/test/approximation.cpp +++ b/poincare/test/approximation.cpp @@ -394,6 +394,7 @@ QUIZ_CASE(poincare_approximation_trigonometry_functions) { // On R assert_expression_approximates_to("cos(2)", "-4.1614683654714ᴇ-1", Radian); assert_expression_approximates_to("cos(2)", "0.9993908270191", Degree); + assert_expression_approximates_to("cos(2)", "9.9950656036573ᴇ-1", Gradian); // Oscillator assert_expression_approximates_to("cos(π/2)", "0", Radian); assert_expression_approximates_to("cos(3×π/2)", "0", Radian); @@ -415,6 +416,7 @@ QUIZ_CASE(poincare_approximation_trigonometry_functions) { // On R assert_expression_approximates_to("sin(2)", "9.0929742682568ᴇ-1", Radian); assert_expression_approximates_to("sin(2)", "3.4899496702501ᴇ-2", Degree); + assert_expression_approximates_to("sin(2)", "3.1410759078128ᴇ-2", Gradian); // Oscillator assert_expression_approximates_to("sin(π/2)", "1", Radian); assert_expression_approximates_to("sin(3×π/2)", "-1", Radian); @@ -437,6 +439,7 @@ QUIZ_CASE(poincare_approximation_trigonometry_functions) { // On R assert_expression_approximates_to("tan(2)", "-2.1850398632615", Radian); assert_expression_approximates_to("tan(2)", "3.4920769491748ᴇ-2", Degree); + assert_expression_approximates_to("tan(2)", "3.1426266043351ᴇ-2", Gradian); // Tangent-style assert_expression_approximates_to("tan(π/2)", Undefined::Name(), Radian); assert_expression_approximates_to("tan(3×π/2)", Undefined::Name(), Radian); @@ -461,6 +464,7 @@ QUIZ_CASE(poincare_approximation_trigonometry_functions) { assert_expression_approximates_to("acos(0.5)", "1.0471975511966", Radian); assert_expression_approximates_to("acos(0.03)", "1.5407918249714", Radian); assert_expression_approximates_to("acos(0.5)", "60", Degree); + assert_expression_approximates_to("acos(0.5)", "66.666666666667", Gradian); // On [1, inf[ assert_expression_approximates_to("acos(2)", "1.3169578969248×𝐢", Radian); assert_expression_approximates_to("acos(2)", "75.456129290217×𝐢", Degree); @@ -483,6 +487,9 @@ QUIZ_CASE(poincare_approximation_trigonometry_functions) { assert_expression_approximates_to("acos(0)", "90", Degree); assert_expression_approximates_to("acos(-1)", "180", Degree); assert_expression_approximates_to("acos(1)", "0", Degree); + assert_expression_approximates_to("acos(0)", "100", Gradian); + assert_expression_approximates_to("acos(-1)", "200", Gradian) + assert_expression_approximates_to("acos(1)", "0", Gradian); /* asin: [-1,1] -> R * ]-inf,-1[ -> -π/2+R×i (odd) diff --git a/poincare/test/helper.h b/poincare/test/helper.h index 59e221794..806bd41d5 100644 --- a/poincare/test/helper.h +++ b/poincare/test/helper.h @@ -8,6 +8,7 @@ const char * BigOverflowedIntegerString(); // OverflowedIntegerString with a 2 o constexpr Poincare::ExpressionNode::ReductionTarget System = Poincare::ExpressionNode::ReductionTarget::System; constexpr Poincare::ExpressionNode::ReductionTarget User = Poincare::ExpressionNode::ReductionTarget::User; constexpr Poincare::Preferences::AngleUnit Degree = Poincare::Preferences::AngleUnit::Degree; +constexpr Poincare::Preferences::AngleUnit Gradian = Poincare::Preferences::AngleUnit::Gradian; constexpr Poincare::Preferences::AngleUnit Radian = Poincare::Preferences::AngleUnit::Radian; constexpr Poincare::Preferences::ComplexFormat Cartesian = Poincare::Preferences::ComplexFormat::Cartesian; constexpr Poincare::Preferences::ComplexFormat Polar = Poincare::Preferences::ComplexFormat::Polar;