program procedure_sample(input, output);
const pi = 3.14159265358979;
var x : real;
procedure print_volume(radius :real);
begin
write('Radius = ', radius:15:7);
writeln(' Volume = ', radius*radius*radius*pi*4.0/3.0:15:7);
end;
begin
write('Enter radius : ');
readln(x);
print_volume(x);
end.
このプログラムは、単に適当な数字を読み込んで、その値を半径とする球の体
積を表示するプログラムである。このプログラムでは、実際に体積を計算して
答を表示するのを、 print_volume という名前の手続きが行なってい
る。手続きは、
procedure 名前([var ] 引数1 [,引数2, ...]:型[, ... 引数i [,引数i+1,...]:型]);
[変数宣言]
begin
実行部
end;
という形をとる。このような記述(手続き宣言)が、もとのプログラムの実行
部の前にあると、もとのプログラム(以下、メインプログラムという。これに
対して手続きのことをサブプログラム、あるいはサブルーチンということもあ
る)の中から手続きを「呼び出す」ことができる。よびだされると何が起こるかを上の例で考えてみる。メインプログラムで print_volume(x); というところまで来ると、次に実行されるのは procedure print_volume(radius :real) の実行部の先頭の文 write('Radius = ', radius:15:7); である。手続きの中の変数 radius の値は、メインプログラムで手続きを呼び出す時に設定した値、 すなわちメインプログラムの変数 x の値がそのままコピーされている。
手続き実行部の2行めの writeln文で、球の体積が出る。 end; までくると、手続きですることがもうないのでメインプログラムに戻る。メイ ンプログラムは戻ればもう終っているので、これですべてのプログラムがおしまいで ある。
Enter radius : 2 Radius = 2.0000000 Volume = 33.5103216
しかし、ある程度複雑なプログラムで、同じようなことをあちこちでする時に は、その処理をまとめておいて、同じようなことを繰り返してプログラムしな くてもいいようにしたい。そのような時に手続きは役に立つ。
もちろん、 for, while などを使った繰り返しでも、ある程度のことはできる が、さらに「手続き」という形でまとめることで、便利に使えるようになる。
例えば、グラフィックスで使った initgraph, line, circle といった手続き は、中では実際には非常に複雑な処理をしている。これがあらかじめ手続きと してまとめられているおかげで、我々は簡単に画面に絵を描けるわけである。
program bisection(input, output);
var x0,x1, eps : real;
function f(x:real):real;
begin
f := x*x*x - 2;
end;
procedure bisection(var xmin, xmax : real; eps:real);
var x, f_min, f_max : real;
begin
f_min := f(xmin);
f_max := f(xmax);
if f_min * f_max > 0.0 then begin
writeln('cannot find solution...');
end else begin
repeat
x := (xmin + xmax) *0.5;
if f(x) * f_min > 0.0 then
xmin := x
else
xmax := x;
writeln('x=', x:20:16, ', f(x)=', f(x));
until xmax - xmin < eps;
end;
end;
begin
x0 := 0.0;
x1 := 2.0;
eps := 1e-10;
bisection( x0, x1, eps);
writeln('Final x = ', x0:20:14,x1:20:14);
end.
関数は、手続きに良く似ているが、「値を返す」ことができるという違いがあ
る。書き方の違いは、
procedure 名前(引数の宣言); の代わりに function 名前(引数の宣言):型; となることと、実行部の中で、 (関数の)名前:= 式;の形の代入文で戻すべき値をセットすることである。このようにして宣言した 関数は、 PASCAL がもともと持っている sin, cos などの関数と全く同 じように使うことができる。
関数では、値を一つしか返せない。したがって、上の例のように、二分 法で方程式を解いて、区間の両端の値を戻したければ、引数の形で返すことに なる。引数で値を返すためには、引数の宣言のところで上の例のように名前の 前に var をつける。こうしておかないと、手続きの中で値を書き換え てもそれが呼出元には伝わらない。
上のプログラムは、「2分法」というやり方で、方程式の(近似的な)解を求 めるものである。方程式は、関数=0 という形になっているものとしよう。 このやりかたでは、まず最初にどの範囲に答があるかは知っているものとする。 そうすると、下図にあるように、その範囲の両端で関数の符号が違っているはず である。

その区間の中点で関数の値を計算する。図のように、中点での値と左端での値 の符号が同じなら、答えは中点と右端の間にある。この時は、中点の値で左端 の値を置き換える。逆に中点での値と左端での値の符号が違えば、もちろん答 えはその間にある。この時は右端の値を置き換える。いずれの場合でも、答が あるとわかっている区間の幅がもとの半分に狭まる。これを繰り返していって、 答をもとめる。
これは、例えば辞書で単語を探す時に、まず真ん中あたりを開いてみて、探し ている単語がそのページよりも後ろなら、後ろ半分のさらに真ん中あたりを開 く。というのを繰り返していくのと全く同じことである。人間がやるとまだるっ こしいが、計算機は速いので、こういうやり方でも結構あっというまにかなり 正確な答えにたどり着くことができる。
procedure rect(x1, y1, x2, y2: integer);
をつくる。これを使って、大きさ、位置を変えながらたくさんの長方形を画面
に書くプログラムを作ってみる。
97 SII-1 750001 J. Makino
というような形でサインを書く手続きを作る。なお、画面に字を書くには、手
続き outtextxyを使う。