【第14章】関数とサブルーチン
【関数】
今まで何回かこの言葉を使ってきましたが、命令との違いについて説明してきませんでした。ここまでのレベルのプログラムではこの違いがわからなくてもとくに支障はありませんでしたが、コンピュータのコンピュータらしいプログラムを作るには、知っておいた方がいいことなのでここで勉強しましょう。
図14-1.数学の関数
図14-1.は中学校でも習う一次関数のグラフです。数学でいう関数とは伴って変わる数という意味です。プログラミング言語における関数はこの意味もありますがどちらかというと「マジシャンの箱」のようなものと考えてください。
図14-2.プログラミング言語の関数
マジシャンの箱はステッキで触れると中から鳩や万国旗が出てきますが(ネタ古っ)もちろんタネも仕掛けもあるわけです。プログラミング言語の関数とは、何か材料を入れると加工されて完成品が出てくる箱だと思ってください。この箱に入れる材料のことを引数(ひきすう)、箱から出てくる完成品を戻り値(もどりち)といいます。筆者の亡父が高校(旧制中学)の時使っていた数学の教科書では関数は「函数」と書かれていましたが、プログラミング言語の関数は函数と書く方が適切なような気がします。
Tiny Basic for Windowsの関数では引数が不要なものもあります。今まで出てきたサンプルプログラム中にもすでに登場している関数もあります。
[Tiny Basic for Windowsの便利な関数](一部)
SQR(正の数) 平方根を求める
INT(数) 数の小数点以下を切り捨てて整数化する
ROUND(数) 数の小数点以下を四捨五入して整数化する
RND 0以上1未満の乱数を得る(*1)
PI 円周率 3.14159265358979324 を得る(*2)
SIN(数) 正弦を得る(*3)
COS(数) 余弦を得る(*3)
TAN(数) 正接を得る(*3)
MAX(数1,数2) 数1と数2の大きい方を得る
MIN(数1,数2) 数1と数2の小さい方を得る
図14-3弧度法(ラジアン)span>
(*1)正式な書き方はRND(数)。普通に乱数を発生させる場合、数は正の数。省略した場合は正の数が指定されたものとみなす。
(*2)関数というよりプログラミング言語が提供する定数(予約変数)。
(*3)数は弧度法(ラジアン、図14-3)で与える。
A=5
B=SQR(A)
C=INT(B)
PRINT B,C
R=10
S=PI*R^2
PRINT S
END
2.2360679774997897 2
314.159265358979324
図14-4.数値関数のサンプルプログラムと実行結果
これらは戻り値が数値の関数なので数値関数とか数学関数とよばれます。プログラミング言語の関数には戻り値がストリングのストリング関数もあります。
DATE$ 現在の日付を yyyy/mm/dd形式で得る
TIME$ 現在時刻を hh:mm:ss形式で得る
LEFT$(ストリング,自然数) ストリングの左から(自然数)分文字の文字を得る
RIGHT$(ストリング,自然数) ストリングの右から(自然数)分文字の文字を得る
LEN(ストリング) ストリングの文字数を得る(戻り値は数値)
MID$(ストリング,自然数1,自然数2) ストリングの左から(自然数1)文字目から(自然数2)文字分の文字を得る
NOW$=DATE$+" "+ TIME$
L=LEN(NOW$)
Y$=LEFT$(DATE$,4)
M$=MID$(DATE$,6,2)
D$=RIGHT$(DATE$,2)
PRINT NOW$,L
PRINT "今年は";Y$;"年です"
PRINT "今日は";M$;"月";D$;"日です"
END
2023/04/26 11:37:30 19
今年は2023年です
今日は04月26日です
図14-5.ストリング関数のサンプルプログラムと実行結果
これらの関数はプログラミング言語が提供しているものなので組込関数とよばれることもあります。
【ストリングの長さ】
※この節は昔のBASICをやったことのない方には???かもしれません。今のTiny Basicのプログラミングだけ覚えたい、という方は今は読み飛ばしていただいてかまいません。
1:STRG1$="ABCDE"
2:STRG2$="東京大阪福岡"
3:PRINT STRG1$,STRG2$
4:PRINT
5:L1=LEN(STRG1$)
6:L2=LEN(STRG2$)
7:PRINT L1,L2
8:PRINT
9:C1$=MID$(STRG1$,3,2)
10:C2$=MID$(STRG2$,3,2)
11:PRINT C1$,C2$
12:END
図14-6.Tiny Basicのストリング長を調べるプログラム
図14-7.ストリング長を調べる
図14-6のプログラムの実行結果は図14-7のようになります。Tiny Basicでは日本語(全角文字)も含めて「見える1文字」は1文字と数えます。同じプログラムを昔のBASICで実行すると図14-8のようになります。
図14-8.昔のBASICでのストリング長
昔のBASICでは半角英数字・記号・カタカナは1文字1バイト、日本語(全角文字)は1文字で2文字と数えます。昔のBASICから今のTiny Basicに乗り換える場合、注意が必要なところです。
【サブルーチン】
コンピュータの得意技のひとつがデータの保存と再利用でした。同じように処理の再利用もできます。図14-8のプログラムの10~13行目はサブルーチンとよばれ、プログラムの他の箇所から呼び出されて使われます。13行目のRETURNは呼び出し元に戻る命令です。サブルーチンは何度でも呼び出して使えます。サブルーチンを呼び出して使う側(図14-6のプログラムなら1~9行目)をサブルーチンに対しメインルーチンと呼びます。制御文ブロックが構成できるTiny Basicでこの程度のプログラムではこのような単純なサブルーチンを使う意味はほとんどありませんが、ある制御文ブロック中の処理を別のブロックで使いたい時には使います。Tiny Basicでサブルーチンをサブルーチンらしく使う場面は、関数を自作する場合です(当カテゴリーでは扱いません)。
1:RESTORE *EKIMEI
2:EKI$=""
3:WHILE EKI$<>"//"
4: READ EKI$,SHA$,SEN$
5: IF EKI$<>"//" THEN
6: GOSUB *DISP
7: END IF
8:WEND
9:END
10:*DISP
11:TXT$=EKI$+"駅は"+SHA$+SEN$+"の駅です"
12:PRINT TXT$
13:RETURN
14:*EKIMEI
15:DATA "厚岸","JR北海道","根室本線"
16:DATA "谷田川","JR東日本","水郡線"
17:DATA "合格","大井川鉄道","大井川本線"
18:DATA "教会前","JR四国","鳴門線"
19:DATA "東新庄","富山地方鉄道","宇奈月本線"
20:DATA "//","",""
厚岸駅はJR北海道根室本線の駅です
谷田川駅はJR東日本水郡線の駅です
合格駅は大井川鉄道大井川本線の駅です
教会前駅はJR四国鳴門線の駅です
東新庄駅は富山地方鉄道宇奈月本線の駅です
図14-8.サブルーチンを用いたプログラム例と実行結果
【サブルーチンのネスティングと変数の値引継ぎ】
1:A=0
2:PRINT "メインルーチンスタート"
3:GOSUB *SUB_1
4:GOSUB *SUB_2
5:PRINT "A=";A,"B=";B
6:PRINT "プログラム終了"
7:END
8:
9:*SUB_1
10:A=A+1
11:PRINT "サブルーチン1を実行しました";I
12:RETURN
13:
14:*SUB_2
15:A=A+10
16:B=5
17:GOSUB *SUB_1
18:PRINT "サブルーチン2を実行しました";I
19:RETURN
図14-9.サブルーチン間で変数を引継ぐプログラム
図14-9のプログラムでは、メインルーチンの3行目まできたところでサブルーチンへ飛びます(この例では*SUB_1以後)。サブルーチン内の12行目まできたところでRETURNなのでメインルーチンに戻ります。戻り先はこのサブルーチンを呼び出した次の行です(ここでは4行目)。4行目はまたサブルーチンへのジャンブ(今度は*sub_2以後)です。サブルーチンの17行目までくると、またサブルーチン(*sub_1以後)へジャンプします。12行目のRETURNですが、今度は戻り先が18行目になります。サブルーチンもFOR制御文、WHILE制御文のようにネスティングができます。実行結果は図14-10のようになります。
図14-10.サブルーチン間での変数引継ぎ
ところで、実行結果を見ていただければおわかりと思いますが、変数Aの値はメインルーチンからサブルーチン、また別のサブルーチンへ引き継がれていることがわかります。また変数Bは2つ目のサブルーチン内で初めて出てきたものですが、その値はメインルーチンに戻っても引き継がれます。普通のサブルーチンの使い方では変数の値はメインルーチンとすべてのサブルーチン間で引き継がれます。このようにプログラム中のすべての場所で値が引き継がれる変数をグローバル変数といいます。引き継がれるということは、たとえばサブルーチン内でメインルーチン内で使用している変数を誤って使ってしまうと、変数の値を壊してしまうことになります。これに対し特定の範囲でのみ有効な変数をローカル変数といいます。Tiny Basicや昔のBASICでは、自作の関数内で使用する変数以外はすべてグローバル変数になります。
【昔はよかったなぁ】
今のTiny Basicではあまり出番のないサブルーチンですが、(IFブロックがなかった)昔のBASICではなくてはならないものでした。図14-9のプログラムは第12章の図12-7のプログラムをサブルーチンを使うよう書き換えたものです。IFブロックが使えない昔のBASICでは、条件が成立したとき(またはしなかったとき)の処理が数十行に及んだり、その中にまた別の制御文が入ったりするときは、サブルーチンを使わなければ事実上プログラミングは不可能でした(プログラムの1行が255文字以内という制限があったため)。
図14_9サブルーチンを使ったプログラム例span>
この最初の行(行番号10)のGOTO 1000を見て「懐かしい」と思われた方、昭和プログラマ同窓会やりましょう🍺🍶🍣。
冗談はさておき、このプログラムは行番号1000~1200がメインルーチン、100~320行目がサブルーチン群です。最初の行のGOTO 1000がないと、プログラムは行番号100からメインルーチンとして開始されます。そして行番号190にきたところで「RETURN?ってどこへ帰ればいいんだ?」となり、コンピュータは止まってしまいます。これを避けるために、プログラム開始直後にサブルーチン群を飛ばしてメインルーチンの頭から実行するように、先頭にGOTO命令が置かれます。昔はなんでこんな面倒なプログラムの書き方をしたのかというと、昔のBASICではこのようにサブルーチンを最初に、メインルーチンを後ろに置いた方がメモリ節約になったからです。メモリが32Kのパソコンでまともなプログラムを書くには必須テクニックでした。GOTO命令はたしかにあまり使いたくない命令なのですが、サブルーチンが多いプログラムではなくてはならない命令だったのです。
【この章のまとめ】
材料(引数)を渡して完成品(戻り値)が出てくる箱を関数という。
プログラム中で何回も出てくる処理はサブルーチンにして呼び出して使うことができる。
サブルーチンはネスティングできる。
プログラム中のどこでも値が引き継がれる変数をグローバル変数、特定の範囲でのみ有効な変数をローカル変数という。
コメント一覧
コメント投稿