starwish’s diary

おじさんの自由研究(2)

 その昔大学で研究室に配属となって卒研にいそしんでいた時、実験装置の調整でちょっとした計算が必要になった。電卓を持っていなかったので指導教官に電卓を借りたのだが、そのキー配列をみた私は一瞬目が点になった。そこにはおなじみの「=」キーがなかった。代わりに"ENTER"という横長の謎のキーが場所をとって配置されている。加えて表示部は見慣れた液晶とは大きく異なり、怪しく光るアンバーレッド。クリック感もカチカチと使い慣れた電卓のフニャフニャした感じとは格が違うぞ。ううむ、何だこのマシンは。
commons.wikimedia.org
 しばらくその電卓らしき物体と格闘し、どうやら数を先に入れ、最後に演算子を押せば答えが出るらしいと理解した私は、何とか答えを出して教官に電卓を返却した。そのときの教官の意味深な微笑は今も忘れられない。後年それがかの有名なHPのRPN型電卓だと知り、早速コピー版のHP35sを購入した。これがそうだ。

HP35s

 RPNというのは逆ポーランド記法 (RPN: Reverse Polish Notation)と呼ばれる記法で、数値とENTERキーで計算対象の数値を指定したあとで、演算子を指定して計算するところに特徴がある。例えば1+2を計算するとき、普通の電卓だと1+2=と入れるところを、RPNだと1ENTER2+となる。計算対象の数字をあらかじめ入れておく場所をスタックといい、X,Y,Z,Tの4つがある。これらのうち基本X,Yの2つのスタックの内容が表示される(写真参照)。1+2の計算を例にとると、キー操作によってスタックは下図のように変化する。

入力 1 ENTER 2 +
説明 Xに1が入り、スタック全体が上昇、Tは破棄 XがYにコピーされ、スタック全体が上昇、Tは破棄 スタックはそのままでXに2が入る※ XとYに+を適用し、X,Yを破棄して答えをXに入れ、Tを新しいTにコピー、スタック全体が下降

※数値を入力する直前のキーがENTERだとスタック全体は変化しない
 このような仕組みによって、普通の電卓だと"M"を多用しなければならない()つきの計算が手早く行えるのが特徴だ。例えば(1+2)*(3+4)=は、1ENTER2+3ENTER4+*となる。これに対して普通の電卓の記法はALG(Algeblatic)と呼ばれる。
 ここでRPNによる計算の応用例としてプログラムを使わない(もちろん\sqrt{x}も、x^{0.5}も使わない)、基本キー操作だけを使った開平算に取り組んでみたい。開平算にもいろいろあるが、簡単なものから取り組むことにする。下図のように面積a、縦1、横aの長方形を、縦と横が同じになるように平均をとりながら、一辺が\sqrt{a}の正方形に変形していく過程をイメージして計算手順に落とし込もう。
この長方形を正方形に変形していく過程を考えると、ある時点での縦の長さをx_nに対し、横の長さは\frac{a}{x_n}になる。正方形は縦と横の長さが等しいのだから、新しいx_nの長さであるx_{n+1}は、x_n\frac{a}{x_n}の平均値になるはずだ。このような関係は次の漸化式
x_{n+1}=\frac{x_n+\frac{a}{x_n}}{2}
で表される。この式を希望する精度が出るまで繰り返せば\sqrt{a}が求まるだろう。補足しておくと、この手順はy=x^2-aの解をニュートン法を用いて求める手順と等価になっており、収束も保証されているので安心だ。
 せっかくHP35sを使うのだから、その特徴であるスタックを上手に使ってキー入力を減らしたい。手順の核となるのは漸化式の計算だが、分子にある\frac{a}{x_n}の計算が終わった段階でx_nの値は消えてしまい、x_nとの加算を行うことができない。HP35sにはスタックの値を変えずに上下シフトさせる機能もあるので、これを使ってx_nの値を割り算を行う前に保存して後から参照させる手もあるが、キー入力が増えてしまう。
 どうするかと思いながらHP35sのキートップを眺めると、LASTxという気になるキーがある。マニュアルを読むと
LAST Xレジスタはスタックの付随レジスタであり、最後の数値機能の実行前にXレジスタに記録されていた数値を保持します。
とあり、目的にばっちり適合するではないか。これを使って\frac{a}{x_n}を計算した後にx_nを最下段に入れ、加算したのち、2を手入力して割れば漸化式は完成する。あとは平方根を求めたい数ax_nの初期値である1を与え、適当な回数ループを回せば答えが求まるはずだ。
 ところがこの手順を実行すると2回目のループを回そうとしたところで最下段が0になってしまった。なぜだろうと少し考えた。ループ内部には先述のとおり演算が3回あるのに対し、数値の入力は2つしかない。これはループを一回回すごとにスタックが一つ減ることを意味する。ループ先頭の÷はax_nで割る処理なので、1回目の処理の結果スタックが1段下がり、2回目にはここでaの値にスタックの初期値である0が入ってしまったのが原因だ。なので手順を成功させるためには、ここでaの値を永久にループに供給させる仕組みが必要となる。
 幸いなことに、演算の結果スタックが下がるときには、最上段の値がコピーされるという特徴がある(スタックの動きを説明する図中、+を入力したときの処理を参照)。なので最初からスタックの最上段を平方根を求めたい数aで満たしておけば、あとはこれがコピーされるのでループにaを永久に供給することが可能になる。
 a=3として実行すると、5回ループを回ったところで最大表示桁である12桁目まで真値と一致した。ALG電卓だとメモリ機能を用いる必要があるので、もう少し煩雑な手順になるのではないかと思う。
 LASTxの入力にはシフトキーを押す必要があるので、ループを構成するキー数が6つになり、求根の過程はちょうどワルツを奏でる感じになる。調子に乗ったおじさんはBlue Danubeのリズムに乗せて計算を始めてみたはいいものの、過程は10秒程度であっけなく終わってしまった。なんとなく物足りない感じはするが、そもそも欲しかったのは簡単な手順なので、これでいいのだ。