ＲＸマイコンで動作する関数電卓

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58667/80d38e4d-fdcb-bbef-8705-e4c70d4a1ccc.jpeg" width="50%"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58667/6498077c-803c-ca1c-839d-41c73d7eeb5f.jpeg" width="50%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58667/0759fd33-a70f-14b6-4cb5-1697da7c53a7.jpeg" width="50%"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58667/24c6dd5d-a8f3-ae86-7c8b-a1d8b7866593.jpeg" width="50%">

[CALC_sample](https://github.com/hirakuni45/RX/tree/master/CALC_sample)

---

## 関数電卓

以前に、[RX マイコンで実現する関数電卓の記事](https://qiita.com/hira_kuni_45/items/202cd2ad1f2644c07d75)を書きましたが、２進、１６進の機能などを追加したので、改めて紹介します。
又、前回あまり触れなかった内部的な構成なども解説します。
※２進、１６進の機能が入った事で、多少、実用性もあるものと思えます。

基本的な部分は同等なのですが、２進、１０進、１６進を含めた計算が出来、表示も切り替えが出来ます。
良くある、「１６進８桁」みたいな制限もありませんし、小数点以下の計算も行えます。

ルネサス社は、LCD 付き RX マイコン製品として、RX65N Envision Kit、RX72N Envision Kit があり、480x272 ピクセルの LCD とタッチパネルを装備していて、このどちらでも動作するようにしてあります。
※持っている人は、実行バイナリーを書き込むだけで試せるようにしてありますので、実際に触ってみて下さい。

[RX65N Envision Kit](https://github.com/hirakuni45/RX/blob/master/CALC_sample/RX65N/calc_sample.mot)
[RX72N Envision Kit](https://github.com/hirakuni45/RX/blob/master/CALC_sample/RX72N/calc_sample.mot)

又、GUI を持たない、RX マイコンでも、シリアルターミナルを接続して、対話形式で動作させる事が出来ます。
※現在、RX62N、RX631、RX64M、RX71M、RX66T、RX72T などでも動作します。（ROM が 512K 以上の製品）

このバージョンを試すには、git から RX マイコン C++ フレームワークを取得して、ソースコードをコンパイルする必要があります。
[gcc、g++を使ったルネサスRXマイコン開発](https://qiita.com/hira_kuni_45/items/a890e9ec613b88ca9a5f)

---

## 関数電卓について

マイコンの制作記事で「電卓」は良くある題材ですが、「関数電卓」は少ないと思えます。

- 関数電卓の場合、キーの数が多く、物理的に作りずらい
- 表示装置に適当な物が少ない（横長である程度の解像度が必要）
- 一般に市販されている関数電卓が安価で実用性が高い
- 一つのアプリとして実装する場合、意外とハードルが高い
- スマートフォン用アプリが色々リリースされているので自分で作る意欲が沸かない

ですが、プログラミングの学習用「題材」として、かなり良いものだと思えます

又、gmp、mpfr ライブラリを使う事で、多倍長の計算を簡単に導入出来ます。
安易に、「float」、「double」で行う物より、ワンランク上のアプリケーションとなります。

このアプリケーションは、C++ に非常にマッチした構成となっていますので、C++ 学習用としても参考になる部分は多いものと思います。
適度に難しく、適度に複雑だと思え、丁度良いと思います。
あまりに簡単なサンプルは、基本を学ぶには良いのですが、「なるほどねー」で終わってしまうのがオチです。

```mermaid
graph TD;
main.cpp-->calc_gui.hpp;
main.cpp-->calc_cmd.hpp;
calc_gui.hpp-->calc_cmd.hpp;
basic_arith.hpp-->mpfr.hpp;
calc_cmd.hpp-->basic_arith.hpp
calc_cmd.hpp-->calc_symbol.hpp
calc_cmd.hpp-->calc_func.hpp
```

### basic_arith.hpp

このクラスは、ー＋＊／（）などを評価して一般的な数学の優先度で計算を行います。
※「逆ポーランド記法」などの電卓がありますが、自分としてはメリットを感じません。

```C++
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	Arithmetic クラス
		@param[in]	NVAL	基本型
		@param[in]	SYMBOL	変数クラス型
		@param[in]	FUNC	関数クラス型
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class NVAL, class SYMBOL, class FUNC>
	struct basic_arith {
```

- NVAL は 数値の基本型（mpfr をラップした型を与える）
- SYMBOL はシンボルを管理するクラスの型
- FUNC は関数を管理するクラスの型
- 計算の優先順位を評価する際、スタック利用した構成になっています
- 深度が深くなるとスタックを消費するので、深度の閾値を設けて、ある程度の深度以上でエラーになるようにしてあります
- 「0b」、「0x」を先頭に付ける事で、２進数、１６進数の数値を取り込む事が出来るようにしてあります
- ８進数については、通常使わないと思えますのでサポートしていません

```mermaid
graph TD;
analize-->expression;
expression-->term;
term-->factor;
factor-->expression;
factor-->number;
number-->factor;
number-->symbol;
number-->function;
```
- number は数値を取り込む関数
- factor は「（」の優先度を評価します
- term は「＊、／、＾」を評価します
- expression は「＋、－」を評価します

[basic_arith.hpp](https://github.com/hirakuni45/RX/blob/master/common/basic_arith.hpp?ts=4)

### mpfr.hpp

このクラスは、mpfr ライブラリをラップして、C++ から利用するようにしてあります。

```C++
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  mpfr オブジェクト
		@param[in]	NUM		有効桁数
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t NUM>
	class value : public value_base {
```

- mpfr の有効桁数をテンプレートパラメータとします
- mpfr の C++ ラップクラスは、既に色々と選択肢がありますが、組み込みマイコンの制限で、iostream に起因した構成を取る事が難しいので、独自に実装しています
- mpfr では、２進数、１６進数の表示が独特なので、それを一般化するようにしています

[mpfr.hpp](https://github.com/hirakuni45/RX/blob/master/common/mpfr.hpp?ts=4)

### fixed_map.hpp, fixed_string.hpp

RX マイコンの RAM が少ないデバイスで動かす場合、記憶割り当てを利用しない事が必要です。

- そこで、固定長の map, string クラスを導入しています
- RAM が十分あるなら、std::map, std::string に置き換える事も出来ます
- typedef を変更すれば、同じように動くハズです
- fixed_map は、メモリ消費を少なくするのが目的なので、速度は二の次です

※実装は、イマイチの部分が多く、あまり参考にならないかもしれません

[fixed_map.hpp](https://github.com/hirakuni45/RX/blob/master/common/fixed_map.hpp?ts=4)
[fixed_string.hpp](https://github.com/hirakuni45/RX/blob/master/common/fixed_string.hpp?ts=4)

### calc_cmd.hpp

シリアルターミナルを接続して、対話形式で、計算を行うクラスです。

- 計算式をタイプして、改行すれば答えを表示します
- 関数電卓の機能評価は、GUI を作る前に十分行いたいので、対話形式で事前に評価します

[calc_cmd.hpp](https://github.com/hirakuni45/RX/blob/master/CALC_sample/calc_cmd.hpp?ts=4)

### calc_gui.hpp

グラフィックス LCD を備えたマイコン用のクラスで、表示リソース、widget、応答などが実装されています。

- 現在は、widget::button くらいしか使っていません
- C++17 を積極利用しています
- ボタンが押された場合の応答をラムダ式で記述しています（非常に便利）

[calc_gui.hpp](https://github.com/hirakuni45/RX/blob/master/CALC_sample/calc_gui.hpp?ts=4)

### calc_func.hpp

関数名と機能を管理するクラスです。

- basic_arith のテンプレートクラスとして、関数名をキーとして、mpfr の関数を呼び出します
- 関数名から機能を呼び出す仕組みとして、fixed_map を使っています

[calc_func.hpp](https://github.com/hirakuni45/RX/blob/master/CALC_sample/calc_func.hpp?ts=4)

### calc_symbol.hpp

シンボル名と値を管理するクラスです。

- basic_arith のテンプレートとして、シンボル名をキーとして、mpfr の定数を定義します
- シンボル名から数値を取り出す仕組みとして、fixed_map を使っています

[calc_symbol.hpp](https://github.com/hirakuni45/RX/blob/master/CALC_sample/calc_symbol.hpp?ts=4)

---

## 対話形式

このアプリケーションの核となります。

- 入力された文字列をパースして、実際に計算を行い、結果を表示します

```sh
# Start CALC sample for 'RX72T DIY' 200[MHz]
# Rad
# tan(355/226)
-7'497'258.185'325'587'089'863'352'83
# Hex
# ANS
-0x72'662A.2F71'7F67'A9B7'F
```

ヘルプ表示：

```sh
# ?
  PI        constant
  LOG2      constant
  EULER     constant
  ANS       constant
  V[0-9]    Memory symbol 0..9
  Min[0-9]  Memory In 0..9
  ListSym   List symbol
  Rad       0 to 2*PI
  Grad      0 to 400
  Deg       0 to 360
  Dec       Decimal mode
  Hex       Hexadecimal mode
  Bin       Binary mode
  Sep       Separate mode
  sin(x)
  cos(x)
  tan(x)
  asin(x)
  acos(x)
  atan(x)
  sinh(x)
  cosh(x)
  tanh(x)
  asinh(x)
  acosh(x)
  atanh(x)
  sqrt(x)
  log(x)
  ln(x)
  eint(x)
  exp10(x)
  gamma(x)
  zeta(x)
  abs(x)
  rint(x)
  frac(x)
```

---

## 今後の機能追加

現在、グラフ表示が行える電卓は、それなりに高価です。
RX65N,RX72N Envision Kit で出来れば、面白いと思います。

- 方程式を入力して、グラフ表示を行う
- BASIC 並のプログラミング言語の入力と実行が行える機能
- 数式処理（これは目処がたっていません）
- RX マイコン、液晶、物理ボタンを使ったキットの販売

---

## ライセンス

- 自分が作成したコードは MIT ライセンス
- gmp、mpfr ライブラリは、GPL ライセンス
- 詳細は各ライセンス表記を参照下さい