From 1af2d1792779c5df637b0f499c2e9e8ebf6cbb18 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Mon, 24 Jun 2019 19:22:30 +0200 Subject: [PATCH 1/4] [poincare] Generalize trigonometry engine a bit --- poincare/src/trigonometry.cpp | 35 +++++++++++++++++------ poincare/src/trigonometry_cheat_table.cpp | 7 ++++- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/poincare/src/trigonometry.cpp b/poincare/src/trigonometry.cpp index c54d4b12f..44830733c 100644 --- a/poincare/src/trigonometry.cpp +++ b/poincare/src/trigonometry.cpp @@ -21,6 +21,25 @@ namespace Poincare { +static constexpr double s_pi[] = { + 180.0, + M_PI +}; + +static constexpr int s_piDivisor[] { + 180, + 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 +62,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); } @@ -197,8 +216,8 @@ Expression Trigonometry::shallowReduceDirectFunction(Expression & e, Context& co /* 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 = angleUnit == Preferences::AngleUnit::Radian ? Integer::Addition(r.unsignedIntegerNumerator(), r.unsignedIntegerNumerator()) : r.unsignedIntegerNumerator(); - Integer divisor = 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)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. @@ -206,9 +225,9 @@ Expression Trigonometry::shallowReduceDirectFunction(Expression & e, Context& co * (p/q * π - q'*π) < π/2 => r'/q < 1/2 => 2*r'(Constant::Builder(UCodePointGreekSmallLetterPi)) : static_cast(Rational::Builder(180)); + Expression pi = piExpression(angleUnit); Subtraction s = Subtraction::Builder(); e.replaceWithInPlace(s); s.replaceChildAtIndexInPlace(0, pi); @@ -347,7 +366,7 @@ std::complex Trigonometry::ConvertToRadian(const std::complex c, Preferenc } return c; } - + template std::complex Trigonometry::ConvertRadianToAngleUnit(const std::complex c, Preferences::AngleUnit angleUnit) { if (angleUnit == Preferences::AngleUnit::Degree) { diff --git a/poincare/src/trigonometry_cheat_table.cpp b/poincare/src/trigonometry_cheat_table.cpp index 58b2cba17..23b45c6e6 100644 --- a/poincare/src/trigonometry_cheat_table.cpp +++ b/poincare/src/trigonometry_cheat_table.cpp @@ -2,6 +2,11 @@ namespace Poincare { +static constexpr TrigonometryCheatTable::Type s_targetType[] = { + TrigonometryCheatTable::Type::AngleInDegrees, + TrigonometryCheatTable::Type::AngleInRadians +}; + Expression TrigonometryCheatTable::Row::Pair::reducedExpression(bool assertNotUninitialized, Context & context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) const { Expression e = Expression::Parse(m_expression); if (assertNotUninitialized) { @@ -23,7 +28,7 @@ Expression TrigonometryCheatTable::simplify(const Expression e, ExpressionNode:: || type == ExpressionNode::Type::ArcTangent); // Compute the input and output types - Type angleUnitType = angleUnit == Preferences::AngleUnit::Radian ? Type::AngleInRadians : Type::AngleInDegrees; + Type angleUnitType = s_targetType[(int)angleUnit]; Type trigonometricFunctionType; if (type == ExpressionNode::Type::Cosine || type == ExpressionNode::Type::ArcCosine) { trigonometricFunctionType = Type::Cosine; From 2d06110822d693995f186afc0940bc07bd6d6cef Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Mon, 24 Jun 2019 19:53:02 +0200 Subject: [PATCH 2/4] [poincare] Add support for gradians --- poincare/include/poincare/expression.h | 4 +- poincare/include/poincare/preferences.h | 3 +- .../poincare/trigonometry_cheat_table.h | 15 +++---- poincare/src/complex_cartesian.cpp | 8 ++-- poincare/src/expression.cpp | 26 +++++++++--- poincare/src/trigonometry.cpp | 10 ++++- poincare/src/trigonometry_cheat_table.cpp | 40 ++++++++++++++++++- poincare/test/helper.h | 1 + poincare/test/trigo.cpp | 7 ++++ 9 files changed, 92 insertions(+), 22 deletions(-) diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 2d3a09fe8..4371fc697 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -212,8 +212,8 @@ public: Expression reduce(Context & context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); 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 1b4e84170..8da04693f 100644 --- a/poincare/include/poincare/preferences.h +++ b/poincare/include/poincare/preferences.h @@ -25,7 +25,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 0ae4f678a..e09f647bb 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, Context & context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) 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, context, complexFormat, angleUnit, target); } 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 000156c78..d2ec1d674 100644 --- a/poincare/src/complex_cartesian.cpp +++ b/poincare/src/complex_cartesian.cpp @@ -145,8 +145,8 @@ Expression ComplexCartesian::argument(Context & context, Preferences::ComplexFor Expression divab = Division::Builder(a, b.clone()); Expression arcTangent = ArcTangent::Builder(divab); divab.shallowReduce(context, complexFormat, angleUnit, target); - if (angleUnit == Preferences::AngleUnit::Degree) { - Expression temp = arcTangent.degreeToRadian(); + if (angleUnit != Preferences::AngleUnit::Radian) { + Expression temp = arcTangent.angleUnitToRadian(angleUnit); arcTangent.shallowReduce(context, complexFormat, angleUnit, target); arcTangent = temp; } @@ -347,8 +347,8 @@ ComplexCartesian ComplexCartesian::power(ComplexCartesian & other, Context & con thc.shallowReduce(context, complexFormat, angleUnit, target); dlnr.shallowReduce(context, complexFormat, angleUnit, target); - if (angleUnit == Preferences::AngleUnit::Degree) { - Expression temp = argument.radianToDegree(); + if (angleUnit != Preferences::AngleUnit::Radian) { + Expression temp = argument.radianToAngleUnit(angleUnit); argument.shallowReduce(context, complexFormat, angleUnit, target); argument = temp; } diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 1b3618bb0..c3450ce28 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -512,14 +512,28 @@ Expression Expression::ExpressionWithoutSymbols(Expression e, Context & context) return e; } -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 44830733c..f8ac2784c 100644 --- a/poincare/src/trigonometry.cpp +++ b/poincare/src/trigonometry.cpp @@ -23,11 +23,13 @@ namespace Poincare { static constexpr double s_pi[] = { 180.0, + 200.0, M_PI }; static constexpr int s_piDivisor[] { 180, + 200, 1 }; @@ -209,7 +211,7 @@ Expression Trigonometry::shallowReduceDirectFunction(Expression & e, Context& co && 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) - || (angleUnit == Preferences::AngleUnit::Degree + || ((angleUnit == Preferences::AngleUnit::Degree || angleUnit == Preferences::AngleUnit::Gradian) && e.childAtIndex(0).type() == ExpressionNode::Type::Rational)) { Rational r = angleUnit == Preferences::AngleUnit::Radian ? e.childAtIndex(0).childAtIndex(0).convert() : e.childAtIndex(0).convert(); @@ -364,6 +366,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; } @@ -372,6 +377,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 23b45c6e6..d60092318 100644 --- a/poincare/src/trigonometry_cheat_table.cpp +++ b/poincare/src/trigonometry_cheat_table.cpp @@ -4,6 +4,7 @@ namespace Poincare { static constexpr TrigonometryCheatTable::Type s_targetType[] = { TrigonometryCheatTable::Type::AngleInDegrees, + TrigonometryCheatTable::Type::AngleInGradians, TrigonometryCheatTable::Type::AngleInRadians }; @@ -42,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 @@ -83,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/helper.h b/poincare/test/helper.h index 091d68d74..1f8250253 100644 --- a/poincare/test/helper.h +++ b/poincare/test/helper.h @@ -11,6 +11,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; diff --git a/poincare/test/trigo.cpp b/poincare/test/trigo.cpp index c7a9df4a7..f268e789d 100644 --- a/poincare/test/trigo.cpp +++ b/poincare/test/trigo.cpp @@ -28,6 +28,7 @@ QUIZ_CASE(poincare_trigo_evaluate) { // On R assert_parsed_expression_evaluates_to("cos(2)", "-4.1614683654714ᴇ-1", System, Radian); assert_parsed_expression_evaluates_to("cos(2)", "0.9993908270191", System, Degree); + assert_parsed_expression_evaluates_to("cos(2)", "9.9950656036573ᴇ-1", System, Gradian); // Oscillator assert_parsed_expression_evaluates_to("cos(π/2)", "0", System, Radian); assert_parsed_expression_evaluates_to("cos(3×π/2)", "0", System, Radian); @@ -49,6 +50,7 @@ QUIZ_CASE(poincare_trigo_evaluate) { // On R assert_parsed_expression_evaluates_to("sin(2)", "9.0929742682568ᴇ-1", System, Radian); assert_parsed_expression_evaluates_to("sin(2)", "3.4899496702501ᴇ-2", System, Degree); + assert_parsed_expression_evaluates_to("sin(2)", "3.1410759078128ᴇ-2", System, Gradian); // Oscillator assert_parsed_expression_evaluates_to("sin(π/2)", "1", System, Radian); assert_parsed_expression_evaluates_to("sin(3×π/2)", "-1", System, Radian); @@ -71,6 +73,7 @@ QUIZ_CASE(poincare_trigo_evaluate) { // On R assert_parsed_expression_evaluates_to("tan(2)", "-2.1850398632615", System, Radian); assert_parsed_expression_evaluates_to("tan(2)", "3.4920769491748ᴇ-2", System, Degree); + assert_parsed_expression_evaluates_to("tan(2)", "3.1426266043351ᴇ-2", System, Gradian); // Tangent-style assert_parsed_expression_evaluates_to("tan(π/2)", Undefined::Name(), System, Radian); assert_parsed_expression_evaluates_to("tan(3×π/2)", Undefined::Name(), System, Radian); @@ -95,6 +98,7 @@ QUIZ_CASE(poincare_trigo_evaluate) { assert_parsed_expression_evaluates_to("acos(0.5)", "1.0471975511966", System, Radian); assert_parsed_expression_evaluates_to("acos(0.03)", "1.5407918249714", System, Radian); assert_parsed_expression_evaluates_to("acos(0.5)", "60", System, Degree); + assert_parsed_expression_evaluates_to("acos(0.5)", "66.666666666667", System, Gradian); // On [1, inf[ assert_parsed_expression_evaluates_to("acos(2)", "1.3169578969248×𝐢", System, Radian); assert_parsed_expression_evaluates_to("acos(2)", "75.456129290217×𝐢", System, Degree); @@ -117,6 +121,9 @@ QUIZ_CASE(poincare_trigo_evaluate) { assert_parsed_expression_evaluates_to("acos(0)", "90", System, Degree); assert_parsed_expression_evaluates_to("acos(-1)", "180", System, Degree); assert_parsed_expression_evaluates_to("acos(1)", "0", System, Degree); + assert_parsed_expression_evaluates_to("acos(0)", "100", System, Gradian); + assert_parsed_expression_evaluates_to("acos(-1)", "200", System, Gradian); + assert_parsed_expression_evaluates_to("acos(1)", "0", System, Gradian); /* asin: [-1,1] -> R * ]-inf,-1[ -> -π/2+R×i (odd) From a289e4989ed0aa7c3c302017b84ef1d2a8861459 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Mon, 24 Jun 2019 20:13:15 +0200 Subject: [PATCH 3/4] [apps] Add gradians support --- apps/settings/base.de.i18n | 1 + apps/settings/base.en.i18n | 1 + apps/settings/base.es.i18n | 1 + apps/settings/base.fr.i18n | 1 + apps/settings/base.pt.i18n | 1 + apps/settings/main_controller.cpp | 4 ++-- apps/settings/sub_menu/preferences_controller.cpp | 5 +++++ apps/shared.de.i18n | 1 + apps/shared.en.i18n | 1 + apps/shared.es.i18n | 1 + apps/shared.fr.i18n | 1 + apps/shared.pt.i18n | 1 + apps/title_bar_view.cpp | 2 ++ 13 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 3ed41780d..ad4a10cd4 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 " Scientific = "Wissenschaftlich " diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n index 3b706c0e7..2c5302376 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 7c14e1e10..c086e79a2 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 " Decimal = "Decimal " Scientific = "Científico " diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n index 9a6cc3547..b5aba4e39 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 85d70c976..47e66766c 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.cpp b/apps/settings/main_controller.cpp index df748f77e..8d2ac8404 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -7,7 +7,7 @@ using namespace Poincare; namespace Settings { -const SettingsMessageTree angleChildren[2] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Radian)}; +const SettingsMessageTree angleChildren[3] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Gradians),SettingsMessageTree(I18n::Message::Radian)}; const SettingsMessageTree editionModeChildren[2] = {SettingsMessageTree(I18n::Message::Edition2D), SettingsMessageTree(I18n::Message::EditionLinear)}; const SettingsMessageTree floatDisplayModeChildren[3] = {SettingsMessageTree(I18n::Message::Decimal), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::SignificantFigures)}; const SettingsMessageTree complexFormatChildren[3] = {SettingsMessageTree(I18n::Message::Real), SettingsMessageTree(I18n::Message::Cartesian), SettingsMessageTree(I18n::Message::Polar)}; @@ -19,7 +19,7 @@ const SettingsMessageTree menu[9] = #else const SettingsMessageTree menu[8] = #endif - {SettingsMessageTree(I18n::Message::AngleUnit, angleChildren, 2), + {SettingsMessageTree(I18n::Message::AngleUnit, angleChildren, 3), SettingsMessageTree(I18n::Message::DisplayMode, floatDisplayModeChildren, 3), SettingsMessageTree(I18n::Message::EditionMode, editionModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, complexFormatChildren, 3), diff --git a/apps/settings/sub_menu/preferences_controller.cpp b/apps/settings/sub_menu/preferences_controller.cpp index 527a4a530..6a82a9afd 100644 --- a/apps/settings/sub_menu/preferences_controller.cpp +++ b/apps/settings/sub_menu/preferences_controller.cpp @@ -57,6 +57,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 b47c7f3a5..2e208c0ca 100644 --- a/apps/title_bar_view.cpp +++ b/apps/title_bar_view.cpp @@ -90,6 +90,8 @@ void TitleBarView::refreshPreferences() { } 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); } From 1c40194ac1f952fe092feab09f9e701857c44bbe Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Mon, 24 Jun 2019 22:32:55 +0200 Subject: [PATCH 4/4] [regression] Add gradians support --- apps/regression/model/trigonometric_model.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/regression/model/trigonometric_model.cpp b/apps/regression/model/trigonometric_model.cpp index d090ede6b..7810912e3 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"; @@ -50,7 +61,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; } @@ -58,7 +69,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);