名簿番号 得点 名簿番号 得点
1 45 6 53
2 56 7 85
3 54 8 49
4 20 9 45
5 82 10 99
この得点を配列に代入し、最高点、最低点、平均点、標準偏差を求めるプログラムを作成 しようとして、途中まで作成したら、次のようになった。
dimension a(10) n = 10
a(1) = 45 a(2) = 56 a(3) = 54 続きを完成させなさい。
sum = 0 do i = 1,n
sum = sum + a(i) end do
ave = sum / n
write(6,*) ’average of japanese ’,ave sum = 0
do i = 1,n
sum = sum + b(i) end do
ave = sum / n
write(6,*) ’average of mathematics ’,ave end
ここで、プログラムの中に似た部分があります。これを、1つにまとめることが出来た なら、プログラムが簡潔になることが予想されます。その方法として、サブルーチンとい う方法があります。まず、最も簡単な例を見てみましょう。
write(6,*) ’aaa’
call sample <---- 「sample という名前のサブルーチン
write(6,*) ’ccc’ へジャンプする 」
end
subroutine sample <---- sample という名前のサブルーチン write(6,*) ’bbb’
return <---- call で呼ばれた文の次の行へ戻る
end <---- サブルーチンの終りを表す
実行してみて下さい。call sampleはsampleという名前のサブルーチンに飛びなさい という意味を持ちます。subroutine sampleはこの行から sampleという名前のサブルー チンを記述することを表しています。return文はサブルーチンを呼んだcall文の次の行 から実行を再開しなさいという意味を持ちます。また、サブルーチンの終わりにはend文 をつけて下さい。
では、次のプログラムはどうなるでしょうか。
a = 1
write(6,*) ’in main a = ’,a
call sample2(a) <--- 「a を引数としてサブルーチ write(6,*) ’in main a = ’,a ンsample2 をコールする 」 end
subroutine sample2(b) <--- 引数をうけとり b と呼ぶ write(6,*) ’in sub b = ’,b
return end
call sample2(a) のように call 文の後に書いたサブルーチン名の後に括弧で変数が 入っています。これを引数 と呼び、サブルーチンsample2に対して引数を渡すことを意 味しています。また、サブルーチン側にもsubroutine sample2(b)のようにサブルーチ ン名の後に括弧で変数が入っています。これも 引数と呼び、引数を受けとり bと呼ぶこ とを意味しています。
実行してみると分かりますが、メインルーチンにおける変数aが、サブルーチンからみ るとbとなって認識されることがわかります。return文の前にb = 2という行を加えて みて下さい。メインプログラムに戻ってみるとaの値が2に変わっていることが分かりま す。このように、メインルーチンの変数aとサブルーチンの変数 bは結合され、サブルー チンで変数の値を変更すると、メインルーチンにも影響が及びます。
ここで大切なのは メインルーチン側とサブルーチン側とで引数の型を合わせる という ことです。この場合はメインルーチンから実数型引数aを渡し、サブルーチン側で実数型 引数b を受けとっています。もし、
subroutine sample2(i) write(6,*) ’in sub i = ’,i return
end
とやると、iには間違った値が入ってしまいます。
次に、キーボードから入力した数の階乗を計算するプログラムをサブルーチンを用いて 作ってみましょう。
read(5,*) n
call fact(n,n2) <--- n! を求め n2 に入れるサブルーチンを呼ぶ
write(6,*) ’n = ’,n,’ n! = ’,n2 end
subroutine fact(k,k2) <---- k! を計算し k2 に入れる i = 1
do j = 1,k i = i * j end do
k2 = i return end
ここでは引数が2つあります。このように引数が複数個ある場合は順番に結合されます。
すなわち、nとkが結合され、n2と k2が結合されます。サブルーチンfactは引数nを 受けとってn!を計算し、その値をn2に返すという機能を持っています。
いちばんはじめの例題のプログラムをサブルーチンを使って書き直します。つまり、配 列と配列の要素数の2つを引数として与えると、その平均値を求めるサブルーチンを作り ます。
call cal_average(a,n, ave)
write(6,*) ’average of japanese ’,ave call cal_average(b,n, ave)
write(6,*) ’average of japanese ’,ave end
subroutine cal_average(a,n, ave) <--「配列を受けとって
dimension a(n) その平均を求める」
sum = 0 do i = 1, n
sum = sum + a(i) end do
ave = sum / n return
end
ここでは、引数が3つ使われています。引数が複数個ある場合は、順番に結合されます。
ここでは、引数として配列を指定しました。call文において引数として配列を指定すると きは、このように配列名から括弧の部分を取り除いたものを指定します。サブルーチン側
でも同様の指定を行います。但し、サブルーチン側でも dimension宣言をし、引数が配 列であることを宣言しなくてはなりません。サブルーチン側で行うdimension宣言では、
要素数のところに何を書いても構いません。その理由は、引数として渡されるのは配列a が格納されている領域の先頭アドレスだからです。ここでは、分かりやすくするためa(n) と書きましたが、a(*)あるいは a(1)などと書いてもプログラムの動作は同じです。
このようにサブルーチンを使うことによりプログラムを簡潔に分かりやすく書くことが できます。また、プログラムの再利用が容易になります。例えば、あなたが別のプログラム を作っているときに、配列データの平均を求める必要があったとします。その時は、今回 作成したサブルーチンをそのままコピーして使えばよいのです。こうすることにより、素 早くプログラムを作成することができ、間違いも少なくなります。
大規模なプログラム開発では、まずプログラムの設計という作業をします。そこでは、
プログラムが果たすべき機能をうまく分割し、それぞれの機能をサブルーチンで実現しま す。皆さんも、将来、卒業研究などで大きなプログラムを組むときは、プログラムの設計 にも注意を払って下さい。
練習問題 11
二項係数は次のような式で表されます。
mCn = m!
n!·(m−n)! (23)
m,nを入力すると二項係数 keisuuを返すサブルーチン subroutine nikou(m,n, keisuu)
を作成しなさい。