何気なく計算で使っていることをじっくり考え直すことで、 今まで知らなかったことまで浮かび上がるものです。 今回は、プログラミングコンテスト第2回のテーマ「超電卓」について、 挑戦したくても「どうしてよいのやら」と、 糸口が掴めない素人プログラマに贈り物を差し上げる目的で管理人(志)が筆を起こす気持ちになったのです。
算数で習った順番に説明してゆこう。最初に習うのは、整数同士の足し算です。 手順を分析してゆきましょう。
上の手順は小学校で習った通りの説明だが、コンピュータでのプログラミングにおいては、 説明が複雑で分かりにくい。それは繰り上がりの処理の部分だ。 上のように繰り上がりがあるとき、ないときなどと区別する必要はない。 繰り上がりがないとき、0が繰り上がると考えればすっきりした手順になってしまう。 次に、その手順を分析してみよう。
上の手順であれば、処理1,2 が準備処理に、処理3,4,5 が繰り返し処理に、処理6,7 が後始末処理に相当することになります。
では、具体的に処理をプログラムにして見よう。前回はDelphiでプログラミングを行ったが、 今回はBASICでプログラミングしてみよう。
1000 '********************************************
1001 ' 桁数の大きい整数の和を計算する
1002 ' N88BASIC版
1003 ' 2004/02/08 Ver.0.0 BY H.TAKATA
1005 '********************************************
1100 INPUT "1つ目の数値を入れてください";S1$:' 入力部分
1105 INPUT "2つ目の数値を入れてください";S2$:' S2$="4567"
1107 PRINT S1$; "+"; S2$:' 確認のため入力値を表示
1110 C=0 :' 繰り上がり分をリセット(繰り上がり数なし)
1120 P=1 :' 指定桁を1桁目にセット
1130 S$="" :' 答えの文字列を初期化
1140 IF (P > LEN(S1$)) THEN IF (P > LEN(S2$)) THEN GOTO 1200 :' 計算する桁が無くなったら終了処理へ
1150 IF P= < LEN(S1$) THEN N1$=MID$(S1$,LEN(S1$)-P+1,1) ELSE N1$="0" :' 指定桁の文字を取り出す
1155 IF P= < LEN(S2$) THEN N2$=MID$(S2$,LEN(S2$)-P+1,1) ELSE N2$="0" :' 指定桁の文字を取り出す
1157 PRINT "分解:N1$="; N1$,"N2$=";N2$,"C=";C :' プログラムチェックのためデータを表示
1170 S=INSTR("123456789",N1$)+INSTR("123456789",N2$)+C :' 指定桁の数と繰り上がり分を合計
1180 S$=MID$("0123456789",(S MOD 10)+1,1)+S$ :' 答えの指定桁の数値を埋め込む
1190 IF S= > 10 THEN C=1 ELSE C=0 :' 次の桁への繰り上がり分をセット
1185 PRINT "S=";S;" C=";C :' プログラムチェックのためデータを表示
1195 P=P+1 :' 指定桁を1桁上に移動
1196 GOTO 1140 :' 指定桁の処理を繰り返すために処理の先頭に戻る
1200 IF C=1 THEN S$="1"+S$ :' 繰り上がり分が残っておれば繰り上がりをさせる。
1300 PRINT "答え:";S1$;"+";S2$;"=";S$ :' 結果を表示してプログラムは終了
1400 END :'プログラム終了
上記のプログラムを実際に動かした結果を次に示す。入力数値は適当に入れた(10桁)になっているが、
このプログラムでは文字列の最大数まで(言語に依存するが250文字程度はどの場合もOKだから250桁)可能。
プログラムが動いているときの途中結果も表示するように、プログラムのそれぞれの部分にPRINT文を挿入しているので、
各桁分解、各桁処理、繰り上がりなどプログラム実行の様子が分かります。ご覧ください。
1つ目の数値を入れてください? 5656565656
2つめの数値を入れてください? 6789
与えられた式:5656565656+6789
1桁目の分解:N1$=6 N2$=9 C=0
S=15 C=0
2桁目の分解:N1$=5 N2$=8 C=1
S=14 C=1
3桁目の分解:N1$=6 N2$=7 C=1
S=14 C=1
4桁目の分解:N1$=5 N2$=6 C=1
S=12 C=1
5桁目の分解:N1$=6 N2$=0 C=1
S=7 C=1
6桁目の分解:N1$=5 N2$=0 C=0
S=5 C=0
7桁目の分解:N1$=6 N2$=0 C=0
S=6 C=0
8桁目の分解:N1$=5 N2$=0 C=0
S=5 C=0
9桁目の分解:N1$=6 N2$=0 C=0
S=6 C=0
10桁目の分解:N1$=5 N2$=0 C=0
S=5 C=0
答え:5656565656+6789=5656572445
以上のプログラムで足し算の計算ができたでしょう。積み算のプログラムの仕組みはこのようなものですが、
このプログラムは整数には対応しているのですが、小数には対応できていません。また、エラー処理については省いています。
完成品とはいえないレベルのプログラムですが、
どのようにして「積み残」をしているのかを示すプログラムにはなっていると思います。
後は挑戦者自身で、「積み残し」分を完成させてください。
この講座で説明したプログラムを利用しても、利用しなくてもコンテストに制約はありません。
ご自由に改造して使ってください。
また、このコンテスト「超電卓」については、言語の指定はありません。
BASIC以外の言語で作成してもかまいません。
今回のコンテスト課題は、計算速度を競うものではありませんから、
インタープリタ方式の言語の方がプログラミング作業上で有利かとおもいますが。
[追記] 筆者は当初は Active Basic で「超電卓」のプログラムを作成していました。
筆者が考えた通りにプログラムを作成し、実行したしたところ、思惑と異なる結果が出てきました。
プログラムのミスと思いプログラムの記述を確かめた(いわゆるデバッグ作業)ところ、
プログラムの実行過程に不思議な動きが起こるのを確認しました。
この処理系にバグがあるようです。
フリーソフトとはこんなことが良くあることです
(「バグがあるのが当然!」で、「作った人に責任があるのでなく、使う人が責任を持つ」これがフリーソフトの心構え)。
そこで、N88BASIC互換のBASICをインストールし、言語処理系を変えてプログラミングを行いました。
それ以降、筆者の思惑通りに動くようになりました。
本文のサンプルプログラムも筆者が使ってみた限りにおいて正常です(思ったとおり(=プログラムの通り)に動いてくれています)。
BASICを使うなら「N88BASIC互換」をお勧めします。ダウンロード等の情報は開発ツールのページをご覧ください。
※ 上記の「超電卓(整数バージョン)」 のBASICプログラムのソースリストは ダウンロード 可能です(右クリックして、ディスクに保存を選ぶ)。