連続番号 | rpn入門(中級編) [講座] | 逆ポーランド電卓の実践ウェブ rpn hacks!

逆ポーランド電卓の実践ウェブ rpn hacks!

逆ポーランド電卓rpnの実践ウェブ   
rpn hacks! アールピーエヌ・ハックスサイトマップ

rpn | 講座 | rpn入門 | rpnの使い方を基本から応用まできちんと学習。

HOME > 講座 > rpn入門 > 中級編 > 連続番号 hatena yahoo buzzurl livedoor del.icio.us nifty newsing twitter facebook rss ソーシャルブックマーク

連続番号

 今まではrpnの計算が1行のデータの中で完結していました。つまり、1行目のデータの計算結果が2行目のデータに影響することはありませんでしたし、影響させることができませんでした。

例えば、1から5までの連続した番号を表示させようとしても難しかったですよね。でも、レジスタを使うことで実はそれが可能になります。以下のデータがdata.txtに格納されているとしましょう。

  10
  20
  30
  40
  50


この5行のデータにそれぞれ1から5の番号を振ってみます。そのためには以下のようなrpn式を入力します。

  >rpn @n 1 + #n @n <data.txt
  10 1
  20 2
  30 3
  40 4
  50 5


10から50までの数値のあとに1から5の数値が付与されていることが確認できます。キーポイントは「@n 1 + #n @n」です。

  >rpn @n 1 + #n @n <data.txt
       ① ②③④ ⑤


①でnレジスタの内容を参照します。初めての参照なので0になります。次の②と③でnレジスタに1を加えています。④でnレジスタに保存しています。⑤のnレジスタ参照でスタックにnレジスタの値が積まれることになります。これをdata.txtのデータがなくなるまで繰り返すことになります。

  rpn式    スタックの内容  説明
  ======== ==============  ==========================================
           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行目のデータを処理したときにレジスタの効果が発揮されます。

  rpn式    スタックの内容  説明
  ======== ==============  ==========================================
           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式ですね。

  >rpn @n 1 + #n @n x <data.txt
  1 10
  2 20
  3 30
  4 40
  5 50


これでx軸が1から5、対応するy軸の値が10から50ということになります。xypで表示すると以下になります(npdで修飾)。

  >rpn @n 1 + #n @n x <data.txt | xyp -x,5 -y,50 -m | npd
  ^y 50                                  *
  |
  -
  |                              *
  |
  -
  |                      *
  |                         y=10x のグラフ
  -
  |              *
  |
  -
  |      *
  |                                      x
  |o                                     5
  +------|-------|-------|-------|------->


rを使って繰り返し

 上記のやり方でデータの行数に応じて行番号を付与することができました。では、データがない状態で行番号を作るにはどうしたらいいでしょうか。

rpnにはrpn式を指定した回数だけ繰り返す「-rオプション」があります。具体的に示したほうが分かりやすいですね。以下がその例です。

  >rpn @n 1 + #n @n -r 5
  1
  2
  3
  4
  5


1から5まで連続して番号が作られています。「@n 1 + #n @n」は前と同じです。違うのは「-r 5」です。この「-r 5」は「@n 1 + #n @n」を5回繰り返すように指示するオプションなのです。

先ほどのy=10xのグラフを作るためにファイルを使わないで、計算式で値を作ってみましょう。

  >rpn @n 1 + #n @n @n 10 * -r 5
  1 10
  2 20
  3 30
  4 40
  5 50


このようにすれば、前と同じデータを用意できます。このデータをxypに渡してみましょう。

  >rpn @n 1 + #n @n @n 10 * -r 5 | xyp -x,5 -y,50 -m
  ^y 50                                  *
  |
  -
  |                              *
  |
  -
  |                      *
  |
  -
  |              *
  |
  -
  |      *
  |                                      x
  |o                                     5
  +------|-------|-------|-------|------->


同じグラフですね。

ちなみにこの連続番号ですが、11から15までの連番にしたい場合は、-bオプションを使えば可能です。以下の例です。

  >rpn @n 1 + #n @n -b 10 #n -r 5
  11
  12
  13
  14
  15


「-b 10 #n」で先に10をnレジスタに格納しておくのです。このように-bオプションはrpnが計算を始める前に実行しておきたいrpn式を書くことができます。この状態で先と同じ手順を繰り返せば11から15までの連番が作られます。

試合の勝敗表再び

 あるリーグの勝敗表を再掲します。

  31   18   11
  31   19   10
  29   21   10
  24   25   11
  23   27   10
  19   32    9
  15   30   15


この勝敗表でリーグ全体の勝ち数と負け数、引き分け数を求めたいときはどうすればいいでしょうか。このケースもレジスタを使うことで可能になります。

  >rpn @t + #t @l + #l @w + #w <data.txt


これで、wレジスタに勝ち数、lレジスタに負け数、tレジスタに引き分け数が累積されているはずです。しかし、画面に数値が出てきていません。レジスタに保存しているだけでスタックに積んでいないからです。

  >rpn @t + #t @l + #l @w + #w @w @l @t <data.txt
  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式になります。試してみましょう。

  >rpn @t + #t @l + #l @w + #w -e @w @l @t <data.txt
  172 172 76


「@w @l @t」の前に「-e」を加えただけですが、希望する表示結果になっていますね。リーグ全体では勝ち数が172、負け数も172です。

ここまで、できていればリーグ全体の勝率も求めることができます。

  >rpn @t + #t @l + #l @w + #w -e @w . @l + / <data.txt
  0.5


ちょうど、50%がリーグの勝率です。

rpnの四天王的オプション

 これで、-b, -t, -eの説明を終えましたが、実は-hというオプションが残っています。この-hオプションの動作を理解するには具体例が一番です。-bオプションと-hオプションの違いで説明します。

以下の例では、-bオプションのrpn式は一回しか実行されません。

  >rpn @n 2 * #n @n -b 1 #n -r 5
  2
  4
  8
  16
  32


nレジスタに初期値1を入れて、5回2倍を繰り返しています。では、このrpn式の-bを-hに変えてみましょう。

  >rpn @n 2 * #n @n -h 1 #n -r 5
  2
  2
  2
  2
  2


全部、2になってしまいました。これはrpn式「@n 2 * #n @n」を計算する前に毎回「1 #n」を実行しているからです。

少し変わった例ですが、nの初期値は1で2倍を5回繰り返すのは同じなのですが、毎回2倍する前に値を1大きくしたいとします。こういった場合、以下のrpn式のように-hオプションを使うと便利です。

  >rpn @n 2 * #n @n -b 1 #n -h @n 1 + #n -r 5
  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つ組みのオプションです。

  [rpn式とbegin, head, tail, endの関係]

       +-----------------------+
       |                       |
       +---+     begin     +---+
  +------+ +---------------+ +------+
  |      +---+ +-------+ +---+      |
  |   head   | | rpn式 | |   tail   |
  |      +---+ +-------+ +---+      |
  +------+ +---------------+ +------+
       +---+      end      +---+
       |                       |
       +-----------------------+


上図にあるように、rpnは4つのオプションbegin、head、tail、endでrpn式を包み込むことで、全方位をカバーしています。こうすることで、ほとんど無限の計算パターンに対応できるように設計してあるのです。

オプション指定するbegin,head,tail,endも逆ポーランド記法で記述するので、中央のrpn式との本質的な違いはありません。単にどのrpnと結合してどの段階でrpn式が実行されるかの違いだけになります。

警告文字で作られた図表や式が崩れることがあります。ブラウザによっては固定幅フォントをMSゴシックにするときれいに表示されます。それでも崩れる場合は図表や式をメモ帳にコピー後、閲覧下さい。

警告rpn試用版と標準版(2kリビジョン)はダブルクォートで囲ってください。

rpn 1 2 + ⇒ rpn "1 2 +"
rpn 1 -c foo ⇒ rpn "1" -c "foo"

ダブルクォートは省略できることが多いのですが、慣れない間は囲んだほうが無難です。なお、本ウェブサイトの記事ではrpn標準版(98リビジョン)を使用しているため囲っていません。詳しくは技術サポートの「rpn TIPS参照ください。

注意rpnの障害情報はこちら

警告rpn試用版の場合、複雑なプログラムや処理時間のかかるプログラムの一部には動作しないものがあるかもしれません。あくまで無料提供であることを勘案・了承ください。rpn標準版は、すべてのプログラムが動作します。