4.プロシージャ
プログラム中で同じ作業を何度も繰り返す場合,その作業をプロシージャで記述しそれを参照すると,プログラムが
短く簡潔で分かりやすくなる。プロシージャにはサブプロシージャ(サブルーチンプログラムに相当)と関数プロシージャ
(関数副プログラム,ユーザー定義関数に相当)の2種類がある。
以下ではその使用方法について説明する前準備として,Quick
Basicのプログラム構造およびその他の予備知識
について述べる。
Quick Basicのプログラム構造
・大規模なプログラムは,メインモジュールと複数のサブモジュールで構成される。メインモジュールとはプログ
ラムの中で最初に制御が渡される部分をいう。ただし,講義で扱うプログラムはその大きさが小さいので,メイ
ンモジュールのみで構成され,サブモジュールはない。
・上記の各モジュールは,複数のプロシージャとモジュールレベルコード(プロシージャを除く部分でメインプログ
ラムに相当)から構成される。
メインモジュールにはモジュールレベルコードを必ず含まなければならないが,サブモジュールではその必要
はない。
なお,詳細は,Quick Basic Handbook
P297〜P308を参照のこと。
プロシージャの基本構造
サブプロシージャ,関数プロシージャのプログラムの先頭および文末のステートメントは基本的に下記の通りで,
それらの中間に仕事の内容に応じたステートメントを記述する。
(サブプロシージャ) SUB プロシージャ名 : : END SUB |
(関数プロシージャ) FUNCTION 関数名 : : END FUNCTION |
なお,詳細はQuick Basic Handbook
P41〜P94を参照のこと。
プロシージャの作成方法
プロシージャをQuick Basicで作成するには2つの方法がある。
・Edit−New SUB あるいは Edit−New FUNCTION を選択する。
上の操作をすると,自動的に先頭と末尾のステートメントのみが記述されたプロシージャ編集画面に切り替わる。
プロシージャとモジュールレベルコードの編集画面の切り替え
各プロシージャの編集画面とモジュールレベルコードの編集画面は異なる。このため,編集画面を切り替える。
・F2キーを押す
上の操作を行い,編集したいプロシージャあるいはモジュールレベルコードに白黒反転表示を合わせ,Enter
キーを押す。
プログラムを保存する場合は,モジュールレベルコードを保存すれば,それに関連するプロシージャも自動的に
いっしょに保存される。同様に一度プログラムを保存すればプログラムを読み込む際にモジュールレベルコードを
読み込むと,関連するプロシージャも自動的に読み込まれる。
(1)サブプロシージャ
多元連立一次方程式をGaussの消去法で解くプログラムを例にサブプロシージャの使用方法を説明する。
Gaussの消去法では,前進消去の計算で[a]マトリックスの対角要素より左下三角部分(対角要素は含まない)
を0とするような式の変形を行う。次いで後退代入計算を行い,Xnから順にX1までの値を求める。
次のプログラムは,モジュールレベルコードで必要なデータ[a]および{y}の値を読み込み,サブプロシージャで{x}を
求めた後,その答をモジュールレベルコードで打ち出す。
参考プログラムリスト(引数による変数の受け渡し例)
モジュールレベルコード ’ −−−−Solution by Gauss −−−− DEFINT I−N OPTION BASE 1 −−−−−−−−−−−−−−−−−−−−−−−−−− | DIM a(50,50),x(50),f(50) | | DECLARE SUB gauss (a(),x(),f(),n) | −−−−−−−−−−−−−−−−−−−−−−−−−− READ n FOR i=1 TO n F0R j=1 T0 n READ a(i,j) NEXT j NEXT i FOR i=1 TO n READ f(i) NEXT i −−−−−−−−−−−−−−−−−−− | CALL gauss(a(),x(),f(),n) | ・・・引数 −−−−−−−−−−−−−−−−−−− CLS FOR i=1 TO n PRINT USING ”x(##)=##.####”;i;x(i) NEXT i ’−−−−−−−data−−−−−−−− DATA 4 DATA 2,−1,0,0 DATA −1,2,−1,0 DATA 0,−1,2,−1 DATA 0,0,−1,1 DATA 0,0,0,1 END サブプロシージャ DEFINT I−N −−−−−−−−−−−−−−−−−−− | SUB gauss (a(),x(),f(),n) | ・・・パラメータ −−−−−−−−−−−−−−−−−−− ’ gauss elimination F0R k=1 TO n−1 FOR i=k+1 T0 n w=a(i,k)/a(k,k) FOR j=k+1 T0 n a(i,j)=a(i,j)−w*a(k,j) NEXT j f(i)=f(i)−w*f(k) NEXT i NEXT k ’backward substitution x(n)=f(n)/a(n,n) FOR i=n−1 T0 1 STEP −1 FOR j=i+1 T0 n f(i)=f(i)−a(i,j)*x(j) NEXT j x(i)=f(i)/a(i,i) NEXT i END SUB |
プログラムの解説
1) DECLARE文
DECLARE SUB サブプロシージャ名 ([引数リスト])
・Quick Basicでプログラムを作成すると,プログラムを保存する際に自動的にDECLARE文が挿入される。
この宣言は該当モジュール全体で有効。
・DECLARE文を指定すると,コンパイル時にプロシージャを呼び出すときの引数の個数とデータ型がチェック
される。
・DECLARE文はコンパイルしてオブジェクトモジュールを作成する場合には必ず必要である。しかし,インター
プリター型で使用する場合には省略可能。
・別のモジュールで定義されているプロシージャを呼び出すときにはDECLARE文が必要。
(講義では別のモジュールが必要となるような大きなプログラムは作らない。)
注意
・サブプロシージャ名は,40文字以内,ただしFNで始まってはいけない。名前は変数名の規則に従う。
・DECLARE文で,引数リストを省略する場合でも外側の( )は省略できない。
2) CALL文〜サブプロシージャの呼び出し
CALL サブプロシージャ名[(引数リスト)] |
・DECLARE文でサブプロシージャ名を宣言しているときはCALLを省略し,サブプロシージャ名から記述しても
よい。この場合は,引数を囲む外側の( )を付けてはいけない。
DECLARE文が省略されているときは必ずCALLから記述する。
結論〜DECLARE文の有無に拘わらず,CALLから記述する方が無難。
・プログラムの実行順序〜CALL文のところで実行はサブプロシージャに移行する。END SUBまで実行を終え
た後モジュールレベルコードに戻る。そしてCALL文の次のステートメントに実行が移る。
・引数〜モジュールレベルコードとサブプロシージャ間で受け渡される単純変数名,配列変数名などの内,
モジュールレベルコード側のものを引数と呼ぶ。反対にサブプロシージャ側のものをQuick Basicでは
パラメータと呼ぶ。
変数の受け渡し方法としては引数による他,
DlM SHARED文,COMMON SHARED文,REDlM SHARED文,SHARED文がある。
引数とこれらの方法を混用してもよい。詳細については,後述の参考例を参照されたい。
注意
・引数とパラメータ間の受け渡し規則
・引数とパラメータの個数は同じでなければならない。
・対応する引数とパラメータのデータ型は同じでなければならない。
・対応する引数とパラメータの名前は同じである必要はない。
・引数として定数を指定できるが,パラメータに定数を指定できない。
・CALL文で,引数の受け渡しがなされない場合
・2つのプログラム間でたとえ同じ変数名であってもそれらは互いに無関係な独立な変数,即ちロ−カル
変数として扱われる。
・CALL文で,受け渡しがされた場合
・モジュール間で共有して参照できるグローバル変数として扱われる。従来のBasicにあるGOSUB文で
特定のサブルーチンプログラムに飛び,RETURN文でメインプログラムに戻る形式のプログラムにおい
ては,グローバル変数の扱いとなっている。
3) SUB文 および DEFINT文
SUB サブプロシージャ名 [(パラメータリスト)] |
・通常はサブプロシージャの先頭はSUB文で始まる。ただし,参考プログラムではDEFINTの宣言文がSUB文
の前にきている。
理由:引数リスト中のnを整数型として使用しているためである。モジュールレベルコードでDECLARE文に先
立ちDEFINTの宣言でnを整数型と定義しているが,サブプロシージャでDEFINTの宣言を省略すると,
”データの不一致である”というエラーメッセージが表示される。このためにSUB文に先立ちDEFINTの
宣言を行う。
なお,DEFINTで宣言した変数nと変数n%は異なる変数(識別子は変数名の一部)として解釈されることに注意。
4) OPTION BASE 1
・配列変数の添字の下限値が1となるように指定している。この文が省略された場合には,下限値は0である。
5) PRINT USING文
・PRINT USING文を用いると,打ち出し書式を自由に指定することが可能となる。
6) 参考プログラム中の破線の囲み
・引数による受け渡しをしない場合に変更となるステートメントブロックで,詳細は”SHAREDによる変数の
共有”を参照のこと。
問題 SHARED文,COMMON SHARED文,DlM SHARED文,REDlM SHARED文の使用方法を
QBアドバイザーで確認しなさい。
間題 PRINT USING文についても上記同様その解説を確認しなさい。
SHAREDによる変数の共有
SHARED文〜プロシージャに記述し,そのプロシージャとモジュールレべルコードの間だけで変数は共有される。
したがって,他のプロシージャがこれらの変数を共有することはできない。
COMMON SHARED文,DlM SHARED文,REDlM SHARED文〜モジュールレベルコードに記述し,
モジュールレべルコードとそのモジュール内の全てのプロシージャとの間で変数は共有される。
なお,先の参考プログラムを”SHAREDによる変数の共有”を用いて修正する場合には,参考プログラムの
破線で囲んだ部位を次のように差し替えればよい。
(SHARED文)
−−−−−−−−−−−−−−−−−− | DIM a(50,50),x(50),f(50) | | DECLARE SUB gauss() | −−−−−−−−−−−−−−−−−− −−−−−−−−−− | CALL gauss | −−−−−−−−−− −−−−−−−−−−−−−−−− | SUB gauss | | SHARED a(),x(),f(),n | −−−−−−−−−−−−−−−− |
(COMMON SHARED文)
−−−−−−−−−−−−−−−−−−−−−−−−− | DIM a(50,50),x(50),f(50) | | COMMON SHARED /g1/ a(),x(),f(),n | | DECLARE SUB gauss () | −−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−− | CALL gauss | −−−−−−−−−− −−−−−−−−−− | SUB gauss | −−−−−−−−−− |
(DlM SHARED文)
−−−−−−−−−−−−−−−−−−−−−−− | DIM SHARED a(50,50),x(50),f(50) | | DECLARE SUB gauss (n) | −−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−− | CALL gauss (n) | −−−−−−−−−−−− −−−−−−−−−−− | SUB gauss (n) | −−−−−−−−−−− |
(2)関数プロシージャ
サブプロシージャと関数プロシージャの違いは,サブプロシージャはその呼び出しがCALL文などを用いて
1つの文として扱われるのに対して,関数プロシージャは命令の一要素として使われ,プロシージャで計算
された値を返す。
次の参考プログラムはβを0.1から0.5まで0.1刻みで次式
COS(0)+COS(β)+COS(2β)+・・・・+COS((n‐1)β)
=COS((n−1)β/2)*SIN(nβ/2)/SIN(β/2)
が成立することを確認するプログラムである。このプログラムを用いて関数プロシージャの使用方法を以下に
説明する。
参考プログラムリスト (モジュールレベルコード;引数を用いた場合) DEFINT I,N −−−−−−−−−−−−−−−−−−−−−−−− | DECLARE FUNCTION cosb (n,beta) | −−−−−−−−−−−−−−−−−−−−−−−− n=100 CLS FOR i=1 T0 5 beta=.1*i PRIN丁 ”in the case of beta=”;beta PRINT ” l.h.s.=”; cosb(n,beta) a=COS((n−1)/2!*beta)*SIN(n*beta/2!)/SIN(beta/2!) PRINT ” r.h.s.=”;a NEXT i END (関数プロシージャ) DEFINT J,N −−−−−−−−−−−−−−−−−− | FUNCTION cosb (n,beta) | −−−−−−−−−−−−−−−−−− S=0! FOR j=0 TO n−1 ang=j*beta s=s+C0S(ang) NEXT j cosb=s END FUNCTION |
プログラムの解説
1) モジュールレべルコードでFUNCTION名があると,関数プロシージャに実行が移り,計算された値が
FUNCTION名に保存され,返されてくる。従って,FUNCTION名にも整数型,実数型(単精度,倍
精度)などの型の区別がある。あたかもひとつの変数名のような記述のされ方をする。FUNCTION名
の後ろの()は引数で受け渡す場合の記述方法である。
2) FUNCTIONの後ろに続くcosbがFUNCTION名。
3) 上の関数プロシージャは,引数で受け渡す場合である。
4) 関数プロシージャにおいては,FUNCTION名は代入文の左辺に必ず出て来るが,右辺の式中には記述
できない。
なお,破線の囲みは,引数による受け渡し以外の方法の場合に変更となる部分。
SHAREDによる変数の共有
上記の参考プログラムを”SHAREDによる変数の共有”を用いて修正する場合には参考プログラムの破線の
囲みを次のように記述すればよい。
(SHARED文)
−−−−−−−−−−−−−−−−−−−− | DECLARE FUNCTION cosb() | −−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−− | FUNCTION cosb | | SHARED n,beta | −−−−−−−−−−−−−− |
(COMMON SHARED文)
−−−−−−−−−−−−−−−−−−−− | DECLARE FUNCTION cosb () | | COMMON n,beta | −−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−−−− | FUNCTION cosb | −−−−−−−−−−−−−−− |