2015年2月21日土曜日

HP-16Cのプログラム技法

1980年代にHewlett Packardが出荷していたHP-16Cという電卓の名器があった. 下のような面構えである.



私は30有余年愛用していて, 今も毎日持ち歩いているが, 十進法の計算はiPhoneを使うことが多くなった. HP-16Cの最大の特徴はRPN, すなわちReverse Polish Notationで, (1+2)*(3+4)を1,2+3,4+*の順に入力する. これは大変理にかなっていて, 私が以前実装したHappy Hacking Calculatorも勿論そうなっている. ただHP-16Cはスタックが4段で, 手前から(HPのマニュアルでは下から)x,y,z,tしかない. つまり上の例ではまず1がxに入り, カンマで示したENTERキーでその1がyへ移動. 2がxに入り, +で和の3がxに出来る. 3を入力すると, 和の3がyへ移動. xが新入力の3になり, ENTERでyの3がzに移動, xの3がyに移動, 4の入力でxに4が入り, +でxが7. yが3になり, *でxに21が出来る.

もう1つの特徴が, 数値の表示が二進, 八進, 十進, 十六進に切り替わることだ. 内部表現はいうまでもなく二進である.

iPhoneで真似が出来ないのがHP-16Cのプログラム機能だ. 現今の標準から見れば計算速度も相当遲いし記憶容量も小さいので大したことは出来ないが, こういうプログラムもあるということは, ソフトウェア歴史上無視できない.

今回のブログでは, HP-16Cのプログラムのスタイルを話したい.

HP-16Cには203バイトのメモリーが塔載されている. 0番地の方からデータの記憶場所, 反対側からプログラムの記憶場所として使う. プログラムの方は1ステップが1バイトだが, データの方は1ビットから64ビットまで長さが任意で, プログラムに取られた場所以外を様々なサイズでデータ用の番地を取っていく. これをレジスタという. 私には計算に使うx, yなどがレジスタという気分なのだが, そちらはスタックというのだろう. この可変長のレジスタがどういう実装なのか私には分らない.

HP-16CのプログラミングはKeystroke Programmingといって, 通常手で計算するキーの押し方の順を記憶するもでのある. この他にラベルを置くこと, ラベルへジャンプすること, 条件判断で1ステップ飛ばすことなどが出来る.

またIで表記するインデックスレジスタが1個ある. (I)と表記するとIの内容という意味である.

以下で扱うHP-16Cのプログラムは, 素因数分解のプログラムで使う予定の疑似素数発生噐である. つまり2,3,5,7,11,13,...を次々を作るのだが, 素数だけを作るには大量に記憶するか, 毎回素数性を検査するとか, 実用にならないので, 途中から先は, たまに合成数があっても苦しうないというものだ.

2,3,5で割れない数は30個で循環して現れる. 0から29までの数を書き, 2,3,5で割れるものは1, 割れないものは0として, 縦に0が揃うものを*で表わし, その間隔を 調べると以下のようになる.
2 101010101010101010101010101010
3 100100100100100100100100100100
5 100001000010000100001000010000
&  *     *   * *   * *   *     *
   2     6   4 2   4 2   4     6
また, 始めの方の素数の間隔は
2,3,5,7,11,13,17,19,23,29,31,37,41,43,
 1 2 2 4  2  4  2  4  6  2  6  4  2
だから, 2に1,2,2と足して3,5,7が得られた後は, 上の循環数列の最初の4からを順に足す. こうするとそのうち49が現れるが驚かない.

ではプログラムに移ろう. 循環の最後を調べるのを容易にするには, インデックスレジスタIを使う. 1足したり引いたりした結果が0になると, 次のステップを 飛ばす機能があるから, レジスタには次のように逆順に差分を入れておく. インデックスは最初11に設定し, DSZ(decrement skip if zero)で1ずつ減らし, 0になったら8に再設定する.

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
   6, 2, 6, 4, 2, 4, 2, 4, 2,  2,  1
プログラムは不思議なことに001番地から始まる.
001 43.22.00 LBL 0
002 43.34    PSE
003 54.31    RCL (I)
004 40       +
005 43.23    DSZ
006 22.00    GTO 0
007 34       x<>y
008 44.32    STO I
009 34       x<>y
010 22.00    GTO 0
001行目はLBL 0(ラベル 0)だ. つまりここに0のラベルをつける. 002行目はPSE(pause)で一旦小休止してxの内容をしめす. すぐに走りだすから, 目を凝らす必要がある. 003行目 RCL(I) インデックスレジスタの内容をxにもってくる, xにあった疑似素数はyに送られている. 004行目 +. これで前の疑似素数に差分を足す. 結果はxに出来ている. 005行目 DSZ. インデックスレジスタから1を引き, 結果が0なら007行目へ飛ぶ. 006行目GTO 0. ラベル0へジャンプ. 007行目. xに出来ている疑似素数とyにある数を交換する. 008行目 STO I. xの値をインデックスレジスタへ入れる. 009行目. x<->y. 010行目GTO 0. 0へ飛ぶ. という風に走る.

従って,
11をインデックスレジスタに入れる.
8をxに入れる. ENTERしてyに送る.
最初の疑似素数2をxにいれる.
GTO 0でスタートへ.
R/Sで起動する.

HP-16Cが手元に無ければシミュレータが使える. 例えばここにある.

これらのキーにポインタを合せてクリックすると入力できる. たとえば最初の例. 1,2+3,4+*だが, 1を押し, 中央のENTERを押し, 2を押し, +を押し, 3を押し, ENTERを押し, +, *を押す.

HEXを押せば15に, OCTを押せば25に, BINを押せば10101に表示が変る. その時の基数を窓の右端にh,d,o,bで表示する.

各キーには上にオレンジ色, 下に青色で機能が示されている. その方を使うには, その前に左下のfかgを押しておく.

というわけで疑似素数発生プログラムをやってみよう.

まず差分を入れる. レジスタの長さは8ビットでよさそうだからDECとしてから8を押しfを押し, オレンジ色のWSIZEを押す.

HP-16Cではキーの位置を2桁(行と列)の十進数で表わす. 行番号は上から1,2,3,4. 列番号は左から1,2,3,...,9,0である. fの位置は42, WSIZEの位置は44だ. (2行にわたるENTERは36)

レジスタ1に6を入れるには6を押してxに置き, STO 1と押す. こうしてレジスタ9に2まで入れたら, 次に2と1を10と11に入れるためにHEXにする. 2 STO A 1 STO Bで差分の入力は終わる

プログラムを入力するには, gと31のキー, P/Rを押す. そうすると窓に000が表示される. いかにも000に入りそうだが, 表示の次の位置の入るので要注意だ. プログラム入力モードになっているので, 窓にPRGMの表示がある.

LBL 0をいれる. 窓には 001 43.22.00 と出る. 001番地にキー位置43 (つまりg), 22 (つまりLBL), 00 (これはキー位置ではなく0)が格納されたことが分かる.

このようにして上のプログラムリストの右端の部分を次々と入力する. それが済んだら, 入力モードのままで, GTO . 001と入力すると001番地の命令をみることができる. 以下続く番地の内容を見るにはSSTを押す. こうしてプログラムを確認できる.

プログラムを走らせるには, P/Rを押して入力モードから抜ける. つまり計算モードにする. DECであるのを確認し, 11 STO I としてインデックスレジスタを11に初期設定する. 次に8をENTERし, 2をxに入れて, GTO 0としR/Sを押すとプログラムが走りだす.

各々方はうまく走らせることが出来たであろうか. 私の場合, HP-16Cの実機ではうまく行くが, 件のシミュレータでは, R/Sで停止しない. ONを押して電源を切ると止まってくれた.

HP-16Cのプログラムはかようなものである.

0 件のコメント: