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 をつける。こうしておかないと、手続きの中で値を書き換え てもそれが呼出元には伝わらない。
procedure rect(x1, y1, x2, y2: integer);をつくる。これを使って、大きさ、位置を変えながらたくさんの長方形を画面 に書くプログラムを作ってみる。
1998 SI-1 840001 J. Makinoというような形でサインを書く手続きを作る。なお、画面に字を書くには、手 続き outtextxyを使う。