データ処理 | rpn入門(中級編) [講座] | 逆ポーランド電卓の実践ウェブ rpn hacks!

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

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

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

HOME > 講座 > rpn入門 > 中級編 > データ処理

hatena twitter facebook rss ソーシャルブックマーク

データ処理

コンピュータが得意とする分野にデータ処理があります。計算式自体はそれほど複雑ではないのですが、データ量が多いのが特徴です。そして、大抵の場合、データには計算に不要なものが含まれています。そのため、要らないデータを削除するなど計算以外の雑多な作業が発生します。

勝率の計算に引き分けは不要

 rpnはデータ処理も得意な電卓です。スタックに積んだデータを操作することで、データを削除したり、順番を変えることができます。これによって、柔軟に計算できるようになるのです。

以下はあるリーグの各チーム毎の勝ち数、負け数、引き分け数です。それぞれ、1位から7位まで並んでいます。

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


data.txtにデータが格納されているとして、それぞれのチーム勝率を計算したいとします。勝率は勝ち数÷(勝ち数+負け数)で計算できますので、データの中で引き分け数が不要です。そこで、引き分け数を削除して、勝率計算するrpn式は以下のとおりです。

  >rpn -t _ } . } + / <data.txt
  0.632653
  0.62
  0.58
  0.489796
  0.46
  0.372549
  0.333333


7チーム分の勝率が一気に計算されていますね。

勝率計算の過程

 -tオプションは前回の説明どおりです。データはdata.txtからリダイレクトで受け取っていますので、今回はrpn式の「_ } . } + /」がdata.txtのそれぞれの行の最後に連結することになりますね。

例えば、以下のようにです。

  >rpn 31 18 11 _ } . } + /


ここで、「_」と「.」と「}」がスタック操作記号です。「_」はスタック最後の数値を削除します。例を挙げると以下のようになります。

  >rpn 1 2 3 _
  1 2


スタックに「1 2 3」が積まれていましたが、3が削除されて「1 2」になっていますね。今回の場合は引き分け数を削除しています。

「}」はスタックに積まれた数値を向かって右に1つローテーション(回転)します。一番右端の数値は一番左端に移ります。具体的にrpn式で見るとすぐに分かります。

  >rpn 1 2 3 4 5 }
  5 1 2 3 4


先に引き分けを削除しているので、残った勝ち数と負け数の数値が右に1つローテーションします。つまり、勝ち数と負け数がクルッとひっくり返ったことになります。

次の「.」はスタック最後の数値をコピーします。既に勝ち数と負け数がひっくり返っているので、勝ち数をコピーしたことになります。これで、負け数、勝ち数、勝ち数の三つの数値がスタックにあることになりますね。あとはもう一回右にローテーションして「+」と「/」で計算すれば勝率が求まります。

計算の経過が分かりづらい人は、次の解説を見てください。スタックの内容を表形式で示してあります。

  rpn式    スタックの内容  説明
  ======== ==============  ==========================================
           31 18 11        最初に「31 18 11」がスタック
  _        31 18           _で11が削除(引き分け数が削除)
  }        18 31           }で右に1回ローテーション
  .        18 31 31        .で31をコピー(勝ち数が2つに)
  }        31 18 31        再度、}で右に1回ローテーション
  +        31 49           +で勝ち数と負け数を加算(全試合数)
  /        0.632653        /で勝ち数を全試合数で割って勝率


引き分け数を先に消しているので、残っているのは勝ち数と負け数だけです。2つしかスタックに数値が残っていないため、同じスタック操作記号の「u」を使っても結果は同じです。

情報uはスタックを逆順にひっくり返す操作を行います。

つまり、以下の2つのrpn式は同じ計算結果になります。

  >rpn -t _ } . } + / <data.txt
  >rpn -t _ u . u + / <data.txt


ただし、2つ以上の数値がスタックにあるときは動作は異なります。以下の例で「{」「}」「u」の違いが理解できると思います。

  >rpn 1 2 3 {
  2 3 1
  >rpn 1 2 3 }
  3 1 2
  >rpn 1 2 3 u
  3 2 1


実は-tは省略できる

 今まで-tオプションを使ってrpn式を書いてきました。しかし、-tはよく使うのでなるべく手間をなくすために、-tを省略できるようになっています。以下の-t付きのrpn式を見てください。

  >rpn -t _ } . } + / <data.txt


この式は、次のように-tを省略することができます。

  >rpn _ } . } + / <data.txt


rpnは-tがなくてもrpn式だと判別できた時点で、-tオプションとして解釈するように設計されています。

もっと簡単な数式に変更

 さて、-tオプションが省略できることが分かったのですが、肝心のrpn式の「_ } . } + /」は何だか難しいですよね。スタックのイメージが頭にないとなかなか理解できません。

これはデータを削除することと、勝率を計算することが一緒になっているから余計にそう感じるからです。また、レジスタを使わずにスタックだけで計算しようとしているのも分かりにくさの原因になっています。

そこで、rpn式を①と②に分けて書き直してみましょう。

①先に不要な引き分け数を削除
②勝ち数と負け数をそれぞれレジスタにして計算

①番目のrpn式は「_」だけです。②番目は引き分け数が既に削除されているとすると、「#l #w」でレジスタのlに負け数が、wに勝ち数が格納されます。その後、レジスタを参照することで「@w @w @l + /」で勝率計算できます。

この①と②のrpnを繋ぐと答えが出そうです。2つのrpn式を繋ぐにはパイプという仕組みを利用します。

情報パイプについては、rpn基礎データを転がして計算しようdos入門パイプに詳しい説明があります。

  >rpn _ <data.txt | rpn #l #w @w @w @l + /
  0.632653
  0.62
  0.58
  0.489796
  0.46
  0.372549
  0.333333


計算結果が出てきました。「_ } . } + /」と同じです。しかも、こちらのrpn式のほうがはるかに分かりやすいと思いませんか。

パイプ接続したときのスタックの動き

 rpn式の動作をスタックの内容と共に追いかけてみましょう。

  rpn式    スタックの内容  説明
  ======== ==============  ==========================================
           31 18 11        最初に「31 18 11」がスタック
  _        31 18           _で11が削除(引き分け数が削除)

      |
      v         ---+
 (パイプ結合)      | 31 18をデータとして次のrpnに渡す
      |         <--+
      v 

  rpn式    スタックの内容  説明
  ======== ==============  ==========================================
           31 18           最初に「31 18」がスタック
  #l       31              18をlレジスタに移動
  #w                       31をwレジスタに移動
  @w       31              wレジスタから31をコピー
  @w       31 31           wレジスタから31をコピー
  @l       31 31 18        lレジスタから18をコピー
  +        31 49           31と18を足して49をスタック
  /        0.632653        31を49で割って勝率計算


パイプを使ったときのデータの流れ

 次にrpnの動きを別の視点から説明します。今回のrpn式は、data.txtのデータがリダイレクトでrpnに渡されて、引き分け数の削除が行われます。勝ち数と負け数だけになったデータが再度、パイプで繋がったrpnに引き渡されます。rpnは勝ち数と負け数から勝率を計算して、計算結果のデータをそのまま画面に表示するという仕組みでしたね。

この動きを下の図のようにデータの流れとして表してみます。

  (data.txtから取り出して…)  (勝率を計算して…)
       +-----+                +---------------> (画面へ表示)
       |     |                |
       v     |                |
  >rpn _ <data.txt | rpn #l #w @w @w @l + /
       |                      ^
       |                      |
       +----------------------+
  (引き分け数を削除して…)


2つのrpnがパイプによって、繋がれていることが分かります。計算結果は画面に流れていきますが、当然リダイレクトしてファイルに残しておくこともできます。以下がそのrpn式です。

  >rpn _ <data.txt | rpn #l #w @w @w @l + / >tmp


tmpファイルに計算した勝率が格納されています。データの流れを図で示すと以下のようになります。

  (data.txtから取り出して…)  (勝率を計算して…)
       +-----+                +---------------+
       |     |                |               |
       v     |                |               v (tmpファイルに格納)
  >rpn _ <data.txt | rpn #l #w @w @w @l + / >tmp
       |                      ^
       |                      |
       +----------------------+
  (引き分け数を削除して…)


確認のためにtmpファイルをtypeコマンドで表示してみましょう。

  >type tmp
  0.632653
  0.62
  0.58
  0.489796
  0.46
  0.372549
  0.333333


リダイレクトに続き、パイプを使った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標準版は、すべてのプログラムが動作します。