はじめに
店先で洗剤のグラム単価を比べたり、消費税や源泉徴収金額計算など、ちょっとした計算アプリを作ることにしました。
このためにGUIとの入出力機能を追加したRPNインタプリタを開発しました。
SigBoxView(RPN.K2)(サイトの起動まで時間がかかるかも)
RPN.K2 解説
RPNの基本と使いにくい点
RPNでは、数値が入力されるとスタックに積み上げ、演算子が入力されると積み上げられたスタックの上の数値を取り出し、演算を適用し、その結果をスタックに積み上げます。例えば、「2,3,+」が入力されると、2+3の演算結果である「5」がスタックに残ります。
2 3 +
結果: 5
RPN電卓では、スタックの数値を入れ替えたり(SWAP)、複製(DUP)。削除(DROP)する、スタック操作コマンドが用意されています。これらを利用することで、やや込み入った計算も可能になります。
1 2 3 SWAP DUMP
//DUMP: 1,3,2
1 2 3 DUP DUMP
//DUMP: 1,2,3,3
1 2 3 DROP DUMP
//DUMP: 1,2
RPNの独自拡張RPN.K2の概要
そこで、RPNの計算機能や制御機能の独自に拡張したRPN.K2のインタプリタを開発しました。
拡張1 行列の導入
配列、行ベクトル、列ベクトル、2次元行列に対応する。インデックスは0から始まる。2次元行列の1次元配列への格納はカラムメジャーオーダーによる。
例)[ 1 2 ; 3 4 ] [ 1 4 ] RESHAPE
結果:[ 1 2 3 4 ]
同型の行列の要素間のスカラー処理(ドット演算)に対応。
例) 二項演算 [ 1 2 3 ] [ 2 1 0 ] .*
結果: [ 2 2 0 ]
例) 単項演算 [ 0 0.5 1 1.5 ] #PI * .sin
結果: [ 0 1 0 -1 ]
拡張2 複素数の導入
行列演算、四則演算、極座標変換、対数、FFTなど実装
[ 1 2 ] 1+1i * // 行ベクトル (1,2)に 1+iを掛ける
1.00+1.00i 2.00+2.00i
1+1i arg #PI / // 1+iの偏角を求めπで割る
0.250
拡張3 文字列への対応
数字や予約語以外は文字列として扱う。空白は区切り文字として扱われるため、空白を含む文字列は、バックスラッシュでエスケープするか、ダブルクオートで囲む。
文字列は「+」演算子で連結できる。
例) "前半" " 後半" +
結果:"前半 後半"
拡張4 ユーザー定義処理(サブルーチン)呼び出し
スタックトップに積まれた文字列を実行する。
2 “2 *” CALL
結果: 4
拡張5 GUI変数の導入
パラメータの入力や、計算結果の表示や一時保存のため、GUI部品とのインターフェースを行うGUI変数を導入した。
1 2 + SET.%X //計算結果をテキストボックス(X)に書き込む
2 3 + \%X SET //同上
%X 2 * // テキストボックス(X)の文字を数値に変換しスタックに積み2倍する
拡張6 グローバル変数
RPNでは、スタックに積まれた数値は、スタックTOPから何番目か指定することで数値を取り出したり、数値を挿入することができる。しかし、スタックの深さは、計算処理の途中で動的に深さが変化するため、スタックのどこにどのような数字が格納されているか管理することが大変困難になる。
そこで、計算のパラメータを名前の付けられた変数に格納することができれば、変数名でパラメータを取り出したり、格納できるため管理が簡単になる。
そこで、「$」で始まる文字列をグローバル変数変数に対応させる。
- スタックトップの数値の変数への書き込みは
SET.$変数名 - 変数を読み出してスタックに積む操作は
$変数名 - 変数を読み出して、文字列をコマンドとして実行する操作は
$変数名.call - 変数の削除は
$変数名.delete
“2 *" SET.$W //2倍するプログラムを$Wにセット
3 $W.call // 3を積んて$Wを呼び出す
結果:6
拡張7 ローカル変数
変数名の干渉を避けるためローカル変数を導入。ローカル変数は、サブルーチン内及び、呼び出したサブルーチンの中で使用できる。プレフィックスは$$。
10 SET.$$a // $$aに10をセット
[ 1 2 3 ] "$$a *" MAP // 配列1,2,3の各要素に$$aを掛ける