From 0ac57bbbe1bad9aad6100b3e1e26913e517e3f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 3 Feb 2017 10:42:58 +0100 Subject: [PATCH 1/4] [poincare] Create a class hyperbolic cosine Change-Id: I1080cbc4026035937dfef47955a566a4621600fb --- poincare/Makefile | 1 + poincare/include/poincare.h | 1 + poincare/include/poincare/expression.h | 1 + poincare/include/poincare/hyperbolic_cosine.h | 16 +++++ poincare/src/expression_lexer.l | 1 + poincare/src/hyperbolic_cosine.cpp | 63 +++++++++++++++++++ 6 files changed, 83 insertions(+) create mode 100644 poincare/include/poincare/hyperbolic_cosine.h create mode 100644 poincare/src/hyperbolic_cosine.cpp diff --git a/poincare/Makefile b/poincare/Makefile index e1891c279..1cb7db63c 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -15,6 +15,7 @@ objs += $(addprefix poincare/src/,\ fraction.o\ function.o\ global_context.o\ + hyperbolic_cosine.o\ integer.o\ integral.o\ list_data.o\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index 809cfd181..ab044fd09 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index e1735af4a..3dd5ecdf4 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -15,6 +15,7 @@ class Expression { Cosine, Derivative, Float, + HyperbolicCosine, Integer, Integral, Logarithm, diff --git a/poincare/include/poincare/hyperbolic_cosine.h b/poincare/include/poincare/hyperbolic_cosine.h new file mode 100644 index 000000000..740fec627 --- /dev/null +++ b/poincare/include/poincare/hyperbolic_cosine.h @@ -0,0 +1,16 @@ +#ifndef POINCARE_HYPERBOLIC_COSINE_H +#define POINCARE_HYPERBOLIC_COSINE_H + +#include + +class HyperbolicCosine : public Function { +public: + HyperbolicCosine(); + float approximate(Context & context, AngleUnit angleUnit = AngleUnit::Radian) const override; + Type type() const override; + Expression * cloneWithDifferentOperands(Expression ** newOperands, + int numberOfOperands, bool cloneOperands = true) const override; + Expression * evaluate(Context& context, AngleUnit angleUnit = AngleUnit::Radian) const override; +}; + +#endif diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index 40b966d46..052d4541d 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -89,6 +89,7 @@ diff { poincare_expression_yylval.expression = new Derivative(); return FUNCTION ans { poincare_expression_yylval.character = Symbol::SpecialSymbols::Ans; return SYMBOL; } sin { poincare_expression_yylval.expression = new Sine(); return FUNCTION; } cos { poincare_expression_yylval.expression = new Cosine(); return FUNCTION; } +cosh { poincare_expression_yylval.expression = new HyperbolicCosine(); return FUNCTION; } int { poincare_expression_yylval.expression = new Integral(); return FUNCTION; } tan { poincare_expression_yylval.expression = new Tangent(); return FUNCTION; } log { poincare_expression_yylval.expression = new Logarithm(); return FUNCTION; } diff --git a/poincare/src/hyperbolic_cosine.cpp b/poincare/src/hyperbolic_cosine.cpp new file mode 100644 index 000000000..c2b3b3a57 --- /dev/null +++ b/poincare/src/hyperbolic_cosine.cpp @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +extern "C" { +#include +#include +} + +HyperbolicCosine::HyperbolicCosine() : + Function("cosh") +{ +} + +Expression::Type HyperbolicCosine::type() const { + return Type::HyperbolicCosine; +} + +Expression * HyperbolicCosine::cloneWithDifferentOperands(Expression** newOperands, + int numberOfOperands, bool cloneOperands) const { + assert(numberOfOperands == 1); + assert(newOperands != nullptr); + HyperbolicCosine * hc = new HyperbolicCosine(); + hc->setArgument(newOperands, numberOfOperands, cloneOperands); + return hc; +} + +float HyperbolicCosine::approximate(Context& context, AngleUnit angleUnit) const { + return (expf(m_args[0]->approximate(context, angleUnit))+expf(-m_args[0]->approximate(context, angleUnit)))/2.0f; +} + +Expression * HyperbolicCosine::evaluate(Context& context, AngleUnit angleUnit) const { + Expression * evaluation = m_args[0]->evaluate(context, angleUnit); + assert(evaluation->type() == Type::Matrix || evaluation->type() == Type::Complex); + if (evaluation->type() == Type::Matrix) { + delete evaluation; + return new Complex(NAN); + } + Expression * arguments[2]; + arguments[0] = new Complex(M_E); + arguments[1] = evaluation; + Expression * exp1 = new Power(arguments, true); + arguments[1] = new Opposite(evaluation, true); + Expression * exp2 = new Power(arguments, true); + delete arguments[1]; + delete arguments[0]; + delete evaluation; + arguments[0] = exp1; + arguments[1] = exp2; + Expression * sum = new Addition(arguments, true); + delete exp1; + delete exp2; + arguments[0] = sum; + arguments[1] = new Complex(2.0f); + Expression * result = new Fraction(arguments, true); + delete arguments[1]; + delete arguments[0]; + Expression * resultEvaluation = result->evaluate(context, angleUnit); + delete result; + return resultEvaluation; +} From 74f722efb949df278c9bd334eb83f8bd8e9ff5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 3 Feb 2017 10:55:25 +0100 Subject: [PATCH 2/4] [poincare] Create a class hyperbolic sine Change-Id: I3895897ffeaae5fc1b267eab56ab03dd8632fd5b --- poincare/Makefile | 1 + poincare/include/poincare.h | 1 + poincare/include/poincare/expression.h | 1 + poincare/include/poincare/hyperbolic_sine.h | 16 ++++++ poincare/src/expression_lexer.l | 1 + poincare/src/hyperbolic_sine.cpp | 63 +++++++++++++++++++++ 6 files changed, 83 insertions(+) create mode 100644 poincare/include/poincare/hyperbolic_sine.h create mode 100644 poincare/src/hyperbolic_sine.cpp diff --git a/poincare/Makefile b/poincare/Makefile index 1cb7db63c..2b635dcdb 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -16,6 +16,7 @@ objs += $(addprefix poincare/src/,\ function.o\ global_context.o\ hyperbolic_cosine.o\ + hyperbolic_sine.o\ integer.o\ integral.o\ list_data.o\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index ab044fd09..c228f50b3 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 3dd5ecdf4..c06d693f2 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -16,6 +16,7 @@ class Expression { Derivative, Float, HyperbolicCosine, + HyperbolicSine, Integer, Integral, Logarithm, diff --git a/poincare/include/poincare/hyperbolic_sine.h b/poincare/include/poincare/hyperbolic_sine.h new file mode 100644 index 000000000..baabf0421 --- /dev/null +++ b/poincare/include/poincare/hyperbolic_sine.h @@ -0,0 +1,16 @@ +#ifndef POINCARE_HYPERBOLIC_SINE_H +#define POINCARE_HYPERBOLIC_SINE_H + +#include + +class HyperbolicSine : public Function { +public: + HyperbolicSine(); + float approximate(Context & context, AngleUnit angleUnit = AngleUnit::Radian) const override; + Type type() const override; + Expression * cloneWithDifferentOperands(Expression ** newOperands, + int numberOfOperands, bool cloneOperands = true) const override; + Expression * evaluate(Context& context, AngleUnit angleUnit = AngleUnit::Radian) const override; +}; + +#endif diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index 052d4541d..b94d4501a 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -88,6 +88,7 @@ abs { poincare_expression_yylval.expression = new AbsoluteValue(); return FUNCTI diff { poincare_expression_yylval.expression = new Derivative(); return FUNCTION; } ans { poincare_expression_yylval.character = Symbol::SpecialSymbols::Ans; return SYMBOL; } sin { poincare_expression_yylval.expression = new Sine(); return FUNCTION; } +sinh { poincare_expression_yylval.expression = new HyperbolicSine(); return FUNCTION; } cos { poincare_expression_yylval.expression = new Cosine(); return FUNCTION; } cosh { poincare_expression_yylval.expression = new HyperbolicCosine(); return FUNCTION; } int { poincare_expression_yylval.expression = new Integral(); return FUNCTION; } diff --git a/poincare/src/hyperbolic_sine.cpp b/poincare/src/hyperbolic_sine.cpp new file mode 100644 index 000000000..c07849be4 --- /dev/null +++ b/poincare/src/hyperbolic_sine.cpp @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +extern "C" { +#include +#include +} + +HyperbolicSine::HyperbolicSine() : + Function("sinh") +{ +} + +Expression::Type HyperbolicSine::type() const { + return Type::HyperbolicSine; +} + +Expression * HyperbolicSine::cloneWithDifferentOperands(Expression** newOperands, + int numberOfOperands, bool cloneOperands) const { + assert(numberOfOperands == 1); + assert(newOperands != nullptr); + HyperbolicSine * hs = new HyperbolicSine(); + hs->setArgument(newOperands, numberOfOperands, cloneOperands); + return hs; +} + +float HyperbolicSine::approximate(Context& context, AngleUnit angleUnit) const { + return (expf(m_args[0]->approximate(context, angleUnit))-expf(-m_args[0]->approximate(context, angleUnit)))/2.0f; +} + +Expression * HyperbolicSine::evaluate(Context& context, AngleUnit angleUnit) const { + Expression * evaluation = m_args[0]->evaluate(context, angleUnit); + assert(evaluation->type() == Type::Matrix || evaluation->type() == Type::Complex); + if (evaluation->type() == Type::Matrix) { + delete evaluation; + return new Complex(NAN); + } + Expression * arguments[2]; + arguments[0] = new Complex(M_E); + arguments[1] = evaluation; + Expression * exp1 = new Power(arguments, true); + arguments[1] = new Opposite(evaluation, true); + Expression * exp2 = new Power(arguments, true); + delete arguments[1]; + delete arguments[0]; + delete evaluation; + arguments[0] = exp1; + arguments[1] = exp2; + Expression * sub = new Subtraction(arguments, true); + delete exp1; + delete exp2; + arguments[0] = sub; + arguments[1] = new Complex(2.0f); + Expression * result = new Fraction(arguments, true); + delete arguments[1]; + delete arguments[0]; + Expression * resultEvaluation = result->evaluate(context, angleUnit); + delete result; + return resultEvaluation; +} From 1adc5fa38d1109eead5978ffc7ffa3745567ec28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 3 Feb 2017 11:13:12 +0100 Subject: [PATCH 3/4] [poincare] Create a class hyperbolic tangent Change-Id: Ib810a31912d3d0f5e32dae31acb792dae8315d4a --- poincare/Makefile | 1 + poincare/include/poincare.h | 1 + poincare/include/poincare/expression.h | 1 + .../include/poincare/hyperbolic_tangent.h | 16 ++++++ poincare/src/expression_lexer.l | 1 + poincare/src/hyperbolic_tangent.cpp | 53 +++++++++++++++++++ 6 files changed, 73 insertions(+) create mode 100644 poincare/include/poincare/hyperbolic_tangent.h create mode 100644 poincare/src/hyperbolic_tangent.cpp diff --git a/poincare/Makefile b/poincare/Makefile index 2b635dcdb..542dfcdd2 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -17,6 +17,7 @@ objs += $(addprefix poincare/src/,\ global_context.o\ hyperbolic_cosine.o\ hyperbolic_sine.o\ + hyperbolic_tangent.o\ integer.o\ integral.o\ list_data.o\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index c228f50b3..351162662 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index c06d693f2..517538fb1 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -17,6 +17,7 @@ class Expression { Float, HyperbolicCosine, HyperbolicSine, + HyperbolicTangent, Integer, Integral, Logarithm, diff --git a/poincare/include/poincare/hyperbolic_tangent.h b/poincare/include/poincare/hyperbolic_tangent.h new file mode 100644 index 000000000..6db771ed9 --- /dev/null +++ b/poincare/include/poincare/hyperbolic_tangent.h @@ -0,0 +1,16 @@ +#ifndef POINCARE_HYPERBOLIC_TANGENT_H +#define POINCARE_HYPERBOLIC_TANGENT_H + +#include + +class HyperbolicTangent : public Function { +public: + HyperbolicTangent(); + float approximate(Context & context, AngleUnit angleUnit = AngleUnit::Radian) const override; + Type type() const override; + Expression * cloneWithDifferentOperands(Expression ** newOperands, + int numberOfOperands, bool cloneOperands = true) const override; + Expression * evaluate(Context& context, AngleUnit angleUnit = AngleUnit::Radian) const override; +}; + +#endif diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index b94d4501a..e9bddd8ec 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -93,6 +93,7 @@ cos { poincare_expression_yylval.expression = new Cosine(); return FUNCTION; } cosh { poincare_expression_yylval.expression = new HyperbolicCosine(); return FUNCTION; } int { poincare_expression_yylval.expression = new Integral(); return FUNCTION; } tan { poincare_expression_yylval.expression = new Tangent(); return FUNCTION; } +tanh { poincare_expression_yylval.expression = new HyperbolicTangent(); return FUNCTION; } log { poincare_expression_yylval.expression = new Logarithm(); return FUNCTION; } ln { poincare_expression_yylval.expression = new NaperianLogarithm(); return FUNCTION; } root { poincare_expression_yylval.expression = new NthRoot(); return FUNCTION; } diff --git a/poincare/src/hyperbolic_tangent.cpp b/poincare/src/hyperbolic_tangent.cpp new file mode 100644 index 000000000..d122e99fd --- /dev/null +++ b/poincare/src/hyperbolic_tangent.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +extern "C" { +#include +#include +} + +HyperbolicTangent::HyperbolicTangent() : + Function("tanh") +{ +} + +Expression::Type HyperbolicTangent::type() const { + return Type::HyperbolicTangent; +} + +Expression * HyperbolicTangent::cloneWithDifferentOperands(Expression** newOperands, + int numberOfOperands, bool cloneOperands) const { + assert(numberOfOperands == 1); + assert(newOperands != nullptr); + HyperbolicTangent * ht = new HyperbolicTangent(); + ht->setArgument(newOperands, numberOfOperands, cloneOperands); + return ht; +} + +float HyperbolicTangent::approximate(Context& context, AngleUnit angleUnit) const { + return (expf(m_args[0]->approximate(context, angleUnit))-expf(-m_args[0]->approximate(context, angleUnit)))/ + (expf(m_args[0]->approximate(context, angleUnit))+expf(-m_args[0]->approximate(context, angleUnit))); +} + +Expression * HyperbolicTangent::evaluate(Context& context, AngleUnit angleUnit) const { + Expression * evaluation = m_args[0]->evaluate(context, angleUnit); + assert(evaluation->type() == Type::Matrix || evaluation->type() == Type::Complex); + if (evaluation->type() == Type::Matrix) { + delete evaluation; + return new Complex(NAN); + } + Expression * arguments[2]; + arguments[0] = new HyperbolicSine(); + ((Function *)arguments[0])->setArgument(&evaluation, 1, true); + arguments[1] = new HyperbolicCosine(); + ((Function *)arguments[1])->setArgument(&evaluation, 1, true); + delete evaluation; + Expression * result = new Fraction(arguments, true); + delete arguments[1]; + delete arguments[0]; + Expression * resultEvaluation = result->evaluate(context, angleUnit); + delete result; + return resultEvaluation; +} From 66daecee844050261ee257cf50b867f80ad29cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 3 Feb 2017 14:50:26 +0100 Subject: [PATCH 4/4] [Kandinsky] New glyph for i complex Change-Id: Icbba7712898af55846072f96f3bc3ad53af2adb0 --- kandinsky/fonts/LargeSourcePixel.ttf | Bin 223408 -> 223440 bytes kandinsky/fonts/SmallSourcePixel.ttf | Bin 171136 -> 171092 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/kandinsky/fonts/LargeSourcePixel.ttf b/kandinsky/fonts/LargeSourcePixel.ttf index db90c796ee1bb49cd626adf8fa1d6d520e05cf30..9cc44fbb1082b30315b2ba20f559b310e7612d38 100644 GIT binary patch delta 5028 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 delta 4893 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 F=)d@9EX@D_ diff --git a/kandinsky/fonts/SmallSourcePixel.ttf b/kandinsky/fonts/SmallSourcePixel.ttf index 5acc17fcac4588c3cfd60003a566b1aa5702e00f..239c7607a6f965956694748394a885b0eaace662 100644 GIT binary patch delta 4544 zcmYk=e^k}=9mnz4`+74{Oe_*Cw%BBgHmbX%qN2qX85SnxEy-xnqPo>BZ%K+q-CL64 zIcx_{q^@p_iX3fh-IOU7=~bz&ddr*Ll#=q6q*$bsS4AV;v$mb>kH`Idzn{ZtTu z8axO~uVU5z2ap?^o$XQbb&en3amhT~)iVC!$SMsmp8(T-wb)6WL)-%9*if%|j zCAjW#q8wbmDR_{O-YP~!dOH);h>#QEEYgLfw2||TLG(zQ=(CC8HqmD@Lu_tBSbjxG zj#eNhy^{+sqSCwBAmLpSworIW8M-kj#kh_Ir1#i=@B1|@Z6$uI55#Y!`TN|zUx!wZ z6K9yX2kp`aS)k7c&3-<5q;07vK_e2l{HfcvX-00v> zk`pxQX+cc-I1|-~pkMl=4879MTvWinln)LQBqkUj!F{4z`ZN#qpwVYVpx7?fT|RV5 zy)^7?0I{FvBM2Jorp9iX?@mg47<5k?hNQky5YtD@-a<5@gZIC;NBSZS6#s%^Usi$% z`^(WTeU%FKz6ycleL1KFdHc!RUxp@-GeF^i2E?VWGvP)nxc?>~9U%7rbq{n&$x;M) z{|AeugN@Q55)Szgl@4dYgCS{*u3i<|ssmY*;Gl5S2NzP>vw@={_MFRp>;YYye#Jzq2dkx3l|XzbHgR_DdIHvb~3q!~QkYyoQ>k#FbL7G$xzO_2e>CBmQsxYYDox10+r%U`j5SdP+SQ zsEi@X3Q#4xE(^q8pAK@a=X`1n24!wHdSo}0qg!?(b#4sFrV%@>MOL1QVl0*2BrxDj zO}ziM2Zv+NEU z-ARMHJTeb;JPhTjLpyq9ce8hQC7KYy5bysU7if4-Cx&GA7J~bG3Gi~}twIC3K-2qD zkqZjlp9SLY_n}8NgTZD{d`4X6BhFWZYP2DWe%S-;Kaht~_yc^jBL)s1OaW6q=tdnn z!2V1c&Sa38&7e`WKwNbRyl6lhqUe`Bl!kmz=b>sep&fA~WwRK3Rxv;SvzUBV5M3CM z&E{Y>2eUn(=xhd<-7BkMu$p{Sq7F2x>6XoLA`foxFmu?SLz6i}vbhXBm;Jf5XaNs7 zm;HxxP>u%P|HEM}lCoNYYb(%*i0l!b@R59Y(F}?{$`Fqhf}tO60>eF;;3?SmyFgJt z!}&w#l?Bp3e1P~s5Y!C}$sWsv8}+>Z$0+hxzwB`eJYES3Ki(~yNAkQPP;eeG^ZI0U zJZW7uxPKxYoIk;UPb@_jh?$=XiqEI%{06jwv-u1G(JFghs09N)-z$58xEGqh)4s^r zi`06t9-Xq5T$I2A_F7tHFA?(+doP92BU|R={V&S~4VJab{*w70jj~p*TN&bI&R?eK zU)lRxIpVUmd^CZt@b7NW@E`m_9Y(i4@mK*J| zw+q1<$pQ}%X+;F&Z*-v)Ua-HB;Wjb&rV503|C>`}n=6r!MQIf6lD$KrcZ$)BsO;Tb zl!N;%so;7G4P&gadf9tH*;Xg0v$X-eviH;BL0lHkMlJeeA7p~uZS>ey!~5UXBHNw^ zg16U!Cfhq@-CnezNA_U>*#D4XALXJEVHyAKw;jap7?AbkpacPM*2CV%r3it6KFP;Y zbjfxy_)hY6`Uy&qm>@AhVuHg&pX}2@G=qkpasF8yD71_HUF`3QfZX16(4@B!?Xu5P z;X?}sWxHv#o7_Fb?WqB|d&u3>FYBYOzmLs6n(WO5iF>3!+=LKMfV&Z2zEafMx^rpz+rp(C3>p-v2jMT*PDtnD9UuyddyE z3)oLmD9L`3LI(>#u|vcja-kFyJJbjUIK~BX`FA1NF$(e@4LjC|2!>?GU7+^y zupG*S7j5X5!}7qr`8jl?qXuy~hGm0;VNK}7pd8LZaPDlE Z-jC?$crWV~$vLBR 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 J`hWio@=xEl%uxUU