連続番号
今まではrpnの計算が1行のデータの中で完結していました。つまり、1行目のデータの計算結果が2行目のデータに影響することはありませんでしたし、影響させることができませんでした。
例えば、1から5までの連続した番号を表示させようとしても難しかったですよね。でも、レジスタを使うことで実はそれが可能になります。以下のデータがdata.txtに格納されているとしましょう。
20
30
40
50
この5行のデータにそれぞれ1から5の番号を振ってみます。そのためには以下のようなrpn式を入力します。
10 1
20 2
30 3
40 4
50 5
10から50までの数値のあとに1から5の数値が付与されていることが確認できます。キーポイントは「@n 1 + #n @n」です。
① ②③④ ⑤
①でnレジスタの内容を参照します。初めての参照なので0になります。次の②と③でnレジスタに1を加えています。④でnレジスタに保存しています。⑤のnレジスタ参照でスタックにnレジスタの値が積まれることになります。これをdata.txtのデータがなくなるまで繰り返すことになります。
======== ============== ==========================================
10 最初に「10」がスタック
@n 10 0 nレジスタの値をスタック
1 10 0 1 1をスタック
+ 10 1 0と1を加えて計算結果の1をスタック
#n 10 1をnレジスタに移動
@n 10 1 nレジスタの値をスタック
これがdata.txtの1行目のデータを処理したときのrpnの動きになります。そして、2行目のデータを処理したときにレジスタの効果が発揮されます。
======== ============== ==========================================
20 最初に「20」がスタック
@n 20 1 nレジスタの値をスタック
1 20 1 1 1をスタック
+ 20 2 1と1を加えて計算結果の2をスタック
#n 20 2をnレジスタに移動
@n 20 2 nレジスタの値をスタック
分かりましたか、1行目を処理したときに保存したnレジスタの値が2行目の処理をするときにも生きていますよね。この繰り返しで、1から5をdata.txtの行末に付与していったというわけです。
ついでなので、このデータをxypでグラフ化しましょう。xypはx軸、y軸の順にデータが並んでいると表示が楽なので、xで順番を交換します。以下のrpn式ですね。
1 10
2 20
3 30
4 40
5 50
これでx軸が1から5、対応するy軸の値が10から50ということになります。xypで表示すると以下になります(npdで修飾)。
^y 50 *
|
-
| *
|
-
| *
| y=10x のグラフ
-
| *
|
-
| *
| x
|o 5
+------|-------|-------|-------|------->
rを使って繰り返し
上記のやり方でデータの行数に応じて行番号を付与することができました。では、データがない状態で行番号を作るにはどうしたらいいでしょうか。
rpnにはrpn式を指定した回数だけ繰り返す「-rオプション」があります。具体的に示したほうが分かりやすいですね。以下がその例です。
1
2
3
4
5
1から5まで連続して番号が作られています。「@n 1 + #n @n」は前と同じです。違うのは「-r 5」です。この「-r 5」は「@n 1 + #n @n」を5回繰り返すように指示するオプションなのです。
先ほどのy=10xのグラフを作るためにファイルを使わないで、計算式で値を作ってみましょう。
1 10
2 20
3 30
4 40
5 50
このようにすれば、前と同じデータを用意できます。このデータをxypに渡してみましょう。
^y 50 *
|
-
| *
|
-
| *
|
-
| *
|
-
| *
| x
|o 5
+------|-------|-------|-------|------->
同じグラフですね。
ちなみにこの連続番号ですが、11から15までの連番にしたい場合は、-bオプションを使えば可能です。以下の例です。
11
12
13
14
15
「-b 10 #n」で先に10をnレジスタに格納しておくのです。このように-bオプションはrpnが計算を始める前に実行しておきたいrpn式を書くことができます。この状態で先と同じ手順を繰り返せば11から15までの連番が作られます。
試合の勝敗表再び
あるリーグの勝敗表を再掲します。
31 19 10
29 21 10
24 25 11
23 27 10
19 32 9
15 30 15
この勝敗表でリーグ全体の勝ち数と負け数、引き分け数を求めたいときはどうすればいいでしょうか。このケースもレジスタを使うことで可能になります。
これで、wレジスタに勝ち数、lレジスタに負け数、tレジスタに引き分け数が累積されているはずです。しかし、画面に数値が出てきていません。レジスタに保存しているだけでスタックに積んでいないからです。
31 18 11
62 37 21
91 58 31
115 83 42
138 110 52
157 142 61
172 172 76
これで表示されました。しかし、欲しいのは最後の行だけで途中経過は要らないので邪魔な表示が多いですね。そこで、rpnは-eオプションを用意しています。-eオプションはrpnが全てのデータを処理し終わった後に実行されるrpn式になります。試してみましょう。
172 172 76
「@w @l @t」の前に「-e」を加えただけですが、希望する表示結果になっていますね。リーグ全体では勝ち数が172、負け数も172です。
ここまで、できていればリーグ全体の勝率も求めることができます。
0.5
ちょうど、50%がリーグの勝率です。
rpnの四天王的オプション
これで、-b, -t, -eの説明を終えましたが、実は-hというオプションが残っています。この-hオプションの動作を理解するには具体例が一番です。-bオプションと-hオプションの違いで説明します。
以下の例では、-bオプションのrpn式は一回しか実行されません。
2
4
8
16
32
nレジスタに初期値1を入れて、5回2倍を繰り返しています。では、このrpn式の-bを-hに変えてみましょう。
2
2
2
2
2
全部、2になってしまいました。これはrpn式「@n 2 * #n @n」を計算する前に毎回「1 #n」を実行しているからです。
少し変わった例ですが、nの初期値は1で2倍を5回繰り返すのは同じなのですが、毎回2倍する前に値を1大きくしたいとします。こういった場合、以下のrpn式のように-hオプションを使うと便利です。
4
10
22
46
94
rpn式の「@n 2 * #n @n」を実行する前に毎回、nレジスタの値を1つ増やしていることが分かりますね。-hオプションは-tや-b、-eに比べると使用頻度は低いですが、必ず使う機会がやってきます。
ちなみに、-bはbegin、-eはend、-hはhead、-tはtailの略です。実は、これらのオプションはrpnにとって、とても重要な4つ組みのオプションです。
+-----------------------+
| |
+---+ begin +---+
+------+ +---------------+ +------+
| +---+ +-------+ +---+ |
| head | | rpn式 | | tail |
| +---+ +-------+ +---+ |
+------+ +---------------+ +------+
+---+ end +---+
| |
+-----------------------+
上図にあるように、rpnは4つのオプションbegin、head、tail、endでrpn式を包み込むことで、全方位をカバーしています。こうすることで、ほとんど無限の計算パターンに対応できるように設計してあるのです。
オプション指定するbegin,head,tail,endも逆ポーランド記法で記述するので、中央のrpn式との本質的な違いはありません。単にどのrpnと結合してどの段階でrpn式が実行されるかの違いだけになります。