• 検索結果がありません。

手続きと関数の例

ドキュメント内 note.dvi (ページ 41-44)

5.14 関数と手続き

5.14.3 手続きと関数の例

Example 5.14.1 以下の手続きと,それを呼び出しているプログラムは,与えられた2つのinteger型の 変数のうち小さくない方を表示するものである.

program print_max (output) ; var

x,y : integer ;

procedure print_max(x,y : integer) ; var

z : integer ; begin

if (x < y) then writeln(y) else

writeln(x) ; end ;

begin x := 1 ; y := 2 ; print_max(x,y) end.

Example 5.14.2 この例では,2つのinteger型の変数の和を返す関数を記述している.

program print_sum (output) ; var

x,y : integer ;

function return_max(x,y : integer) : integer ; begin

return_max := x + y ; end ;

begin x := 1 ; y := 2 ;

writeln(return_max(x,y)) end.

Example 5.14.3 この例は,配列をベクトルと思い,それの長さを返し, さらに,それに直交するベクトル を一つ求めている11 .

11本当はちょっと問題のある計算である.

Id: P6.tex,v 1.5 2001-03-15 15:43:57+09 naito Exp

program vector (output) ; type

vector = array [1..2] of real ; var

x,y : vector ; r : real ;

function get_norm_and_normal (a : vector ; var b : vector) : real ; begin

b[1] := a[2] ; b[2] := (-1)*a[1] ;

get_norm_and_normal := sqrt(a[1]*a[1] + a[2]*a[2]) ; end ;

begin

x[1] := 1.0 ; x[2] := 0.0 ;

r := get_norm_and_normal(x,y) ;

writeln(’length of (’,x[1],’,’,x[2],’) = ’,r) ;

writeln(’normal of (’,x[1],’,’,x[2],’) = (’,y[1],’,’,y[2],’)’) ; end.

このように,関数の結果型とはなり得ないものを求めるには,関数もしくは手続きの副作用を利用するこ とができる.

Example 5.14.4 この例は,異なった関数に対して,f(x) +g(y/2)の値を求める関数である.

program sum_of_function_values (output) ; var

x,y : real ;

function sin_ft(a : real) : real ; begin

sin_ft := sin(a) ; end ;

function cos_ft(a : real) : real ; begin

cos_ft := cos(a) ; end ;

procedure ch(var a : real) ; begin

a := a/2.0 ; end;

function sum_of_function_values ( a,b : real;

procedure ch (var a : real) ; function f(a : real) : real ;

function g(a : real) : real ) : real ; begin

ch(b) ;

sum_of_function_values := (f(a) + g(b)) ; end ;

begin

x := 0.0 ; y := 1.0 ;

writeln(x,y,sum_of_function_values(x,y,ch,sin_ft,cos_ft)) ; end.

Example 5.14.5 この例は,上の例と同じ結果をもたらすが,forwardを利用している.

Id: P6.tex,v 1.5 2001-03-15 15:43:57+09 naito Exp

program sum_of_function_values (output) ; var

x,y : real ;

procedure ch(var a : real) ; forward ; function sin_ft(a : real) : real ; begin

sin_ft := sin(a) ; end ;

function cos_ft(a : real) : real ; begin

cos_ft := cos(a) ; end ;

function sum_of_function_values ( a,b : real;

function f(a : real) : real ;

function g(a : real) : real ) : real ; begin

ch(b) ;

sum_of_function_values := (f(a) + g(b)) ; end ;

procedure ch ; begin

a := a/2.0 ; end;

begin

x := 0.0 ; y := 1.0 ;

writeln(x,y,sum_of_function_values(x,y,sin_ft,cos_ft)) ; end.

5.14.4 再帰的関数呼びだし

前のsectionで解説した関数,手続きは,それ自身をその内部で呼び出すことができる. これを再帰的関

数呼び出し(recursive function call)と呼ぶ.

再帰的関数呼び出しを利用すると, 帰納的に定義されたものを計算することが容易になる. 数学的には, 再帰で計算できるものは必ず再帰を利用しなくても計算できることが証明されているが,再帰で計算する とプログラムが簡潔になるという利点がある. 一方, 関数,手続き等を呼び出す際には, 多くの処理系にお いて呼び出しの手順として時間がかかることが多い. したがって,再帰には時間がかかることが多い.

Example 5.14.6 次は,帰納的に定義された数列an+1=an+ 2,a1= 1のan を求める関数である.

function recursive_function(n : integer) : integer ; begin

if (n = 1) then

recursive_function := 1 else

recursive_function := recursive_function(n-1) + 2 ; end ;

再帰を用いたアルゴリズムは,必ず再帰を用いなくても実現できる. 再帰を用いると,メモリ内のスタック

(stack)領域を大量に消費する. したがって,あらかじめどのくらいの回数の再帰が行われるかを見積もり,

余りに回数が多い場合には,再帰以外の方法を考えた方が良い場合もある.

Id: P6.tex,v 1.5 2001-03-15 15:43:57+09 naito Exp

ドキュメント内 note.dvi (ページ 41-44)