数式のデバッグ
スタックを使いながら計算する電卓がrpnです。計算した結果は、最終的にスタックに残った値を表示するようになっています。例えば、1に2を足すと答えの3がスタックに残っているので、その3が表示されるわけです。
3
簡単な数式ならよいのですが、複雑になってくるとスタックに積まれる数字も多くなります。rpnで計算していると以下のようなエラーも多発してきて、頭が混乱してきたりします。
rpn:スタックがアンダーフローしました <-- オペランドの数が合っていない
rpn:ゼロで割りました <-- 分母が0になっている
sqrt: DOMAIN error <-- マイナスの平方根を取っている
log: DOMAIN error <-- マイナスの対数を取っている
:
等々
:
例えば、rpn基礎の逆ポーランド記法のまとめにあるような複雑な数式の場合、rpn式に組み立てるのはちょっと大変です(再掲)。
--------------------
(8.33 - 7.46) * 0.32
√ { --------------------------------- }
4.3 * (3.15 - 2.75) - 1.72 * 2.01
このような数式でもrpnに慣れてくれば、一発でrpn式に変換できるのですが、確実にrpn式を作るにはどうすればよいのでしょうか。
基本的なrpn式の組み立て方
逆説的ですが、一番の方法は初めから間違いのないrpn式を書くことです。例えば、上の式を変形した小さな数式で試してみましょう。
√ ---------------------
(8.33 - 7.46) * -0.32
この数式をいくつかのパートに分けて考えます。この程度の式であれば、分子と分母に分けて考えればOKです。これなら簡単にrpn式になります。
-9.996
>rpn 8.33 7.46 - -0.32 *
-0.2784
最後に分子を分母で割って、平方根を取って終了です。
5.99209
式をまとめると次のようになります。
5.99209
上掲の複雑な式なら、3つのパートに分けて考えると間違えずに、rpn式を組み立てられます。
-------------------- ---
(8.33 - 7.46) * 0.32 b
√ { --------------------------------- } ⇔ √ { ----- }
4.3 * (3.15 - 2.75) - 1.72 * 2.01 c
【パートa】
>rpn 8.33 4 5.2 - *
-9.996
【パートb】
>rpn 8.33 7.46 - 0.32 *
0.2784
【パートc】
>rpn 4.3 3.15 2.75 - * 1.72 2.01 * -
-1.7372
【まとめ】
>rpn -9.996 0.2784 / -1.7372 / r
4.54625
大丈夫そうなら、式をまとめます。以下が全部一緒に書いたrpn式です。
4.57278
微妙に値が違うのは数値計算の誤差です。
複雑なrpn式のデバッグ
初心忘するべからずで、数式を分解して考えるのもいいのですが、やはり慣れてくると一気にrpn式に変換していくことになります。その際にちょっとした手違いでうまく計算できないことが起こります。
そんな時は、数式を分解する方法の延長線になるのですが、レジスタを使って計算すれば少しはスッキリします。
レジスタを利用する方法
例えば、2つ以上の数値を計算している部分(要は周りと比べて複雑な数式部分)をレジスタで置き換えます。
√ --------------------- ⇔ √ ---------
(8.33 - 7.46) * -0.32 b * -0.32
8.33や-0.32は数字1つなので放っておくとして、その他の(4 - 5.2)や(8.33 - 7.46)の部分をレジスタで置き換えます。例ではレジスタaとレジスタbに計算値を格納しています。
可能ならば以下のrpn式のように、先に計算しておいてもいいでしょう。
---------- -------------- ------------------------
レジスタa レジスタb 数式
ちょっと分かりやすくなりますね。頭の整理にもなります。
ファイルに格納する方法
もし、レジスタにする数式部分がとても長い数式の場合は一旦、ファイルに確保するのも方法です。
>rpn 8.33 7.46 - >b
>paste a b | rpn #b #a 8.33 @a * @b -0.32 * / r
5.99209
レジスタがファイルに変わっただけです。最後にpasteで横に結合して、再度レジスタに値を保存してから計算です。
スタック値を確認する方法
rpn式が分からなくなったら、このように数式を分解して再計算するのが基本なのですが、せっかく作ったrpn式を崩したくないという人もいます。数式をデバッグ(プログラムの虫取り)するような感覚ですね。そんな人には以下の方法がオススメです。
スタック値を表示してくれる記号「`=」を使うことで、rpn式のデバッグがちょっと楽になります。以下の式で説明しましょう。
√ ---------------------
(8.33 - 7.46) * -0.32
普通にrpn式で表すと次のようになりましたね。
5.99209
検算のため、分子の値をまず表示してみましょう。rpn式の分子の計算結果がスタックに詰まれたところに「`=」を挿入します。
-9.996
5.99209
最終的な答えの前に-9.996とあります。これが分子の値です。次に分母の値も同時に表示してみましょう。
-9.996
-0.2784
5.99209
分子と分母の値が出ていますね。それぞれの数字で割り算と平方根をとれば、答えが一致するはずです(計算誤差がなければ)。
5.99209
きちんと合ってますね。
この記号はスタック最上段にある値を表示するだけです。スタックに変更が及ばないことに注意してください(表示した値がスタックから削除されたりはしない)。
スタック表示は再計算も可能
なお、スタック値の表示で出力された数値は、今までと同様に再計算することができます。以下は計算の途中経過をスタック値で表示したものです。
1
2
3
4
5
次は従来のスタック計算です。ともに同じ表示になっています。
1
2
3
4
5
これらの計算結果を他のプログラムにそのまま引き渡すことができます。さっそく、1から5までの合計を計算してみましょう。
15
>rpn @n 1 + `= #n -r 5 | rpn -c sum
15
上下段のrpn式のどちらも計算できていますね。
ただし、デバッグ過程なら下段のrpn式でもよいのですが、記録に残すといった正式なものは上段のrpn式を使うべきです。あくまで「`=」はデバッグ用と割り切ってください。
ちなみに「`$」を使えば、スタック値を表示した後に改行しないようにできます。スタック値を続けて表示したい場合に使用します。
その意味では正式なrpn式をベースに数式を展開して、デバッグ時に「`=」を追加しながら確認するのを習慣にしたほうがいいでしょう。「`=」を消した後に再度、デバッグする堂々巡りは避けたいですからね。
要は、以下のrpn式のように「`=」があってもなくても、計算結果が同じくなるようにデバッグするわけです。
そうすれば、デバッグの終了時に「`=」を消すだけで正式版になります。
pasteは講座サポートで公開されています。