Taro-再帰関数Ⅰ(公開版).jtd

Similar documents
Taro-再帰関数Ⅱ(公開版).jtd

Taro-プログラミングの基礎Ⅱ(公

Taro-再帰関数Ⅲ(公開版).jtd

Taro-最大値探索法の開発(公開版

Taro-リストⅠ(公開版).jtd

Microsoft PowerPoint - lec4.ppt

Microsoft PowerPoint - ca ppt [互換モード]

Taro-スタック(公開版).jtd

Microsoft PowerPoint - IntroAlgDs-05-4.ppt

main

Microsoft Word - Cプログラミング演習(12)

gengo1-11

Microsoft Word - 03

PowerPoint Presentation

Taro-2分探索木Ⅱ(公開版).jtd

kiso2-06.key

Microsoft PowerPoint - C4(反復for).ppt

Taro-2分探索木Ⅰ(公開版).jtd

Microsoft PowerPoint - CproNt02.ppt [互換モード]

Microsoft PowerPoint - C言語の復習(配布用).ppt [互換モード]

Microsoft PowerPoint - 説明3_if文switch文(C_guide3)【2015新教材対応確認済み】.pptx

演習課題No12

Microsoft PowerPoint - C_Programming(3).pptx

講習No.12

Microsoft Word - Cプログラミング演習(3)

Taro-数値計算の基礎Ⅱ(公開版)

Microsoft PowerPoint - 11th.ppt [互換モード]

Microsoft PowerPoint - 4.pptx

<4D F736F F D20438CBE8CEA8D758DC F0939A82C282AB2E646F63>

Microsoft PowerPoint - 10.ppt [互換モード]

DVIOUT

Taro-ポインタ変数Ⅰ(公開版).j

kiso2-09.key

Taro-ビット処理(公開版).jtd

Taro-数値計算の誤差(公開版)

プログラミング入門1

char int float double の変数型はそれぞれ 文字あるいは小さな整数 整数 実数 より精度の高い ( 数値のより大きい より小さい ) 実数 を扱う時に用いる 備考 : 基本型の説明に示した 浮動小数点 とは数値を指数表現で表す方法である 例えば は指数表現で 3 書く

< F2D837C E95CF CF68A4A94C5816A2E6A>

関数の動作 / printhw(); 7 printf(" n"); printhw(); printf("############ n"); 4 printhw(); 5 関数の作り方 ( 関数名 ) 戻り値 ( 後述 ) void である. 関数名 (

Microsoft Word - 3new.doc

2. 整数の値を 3 つ 引数として受け取ってそのうち最大の値を返す関数 int max(int a,int b,int c) 3 つの中からの最大値, と値が少ないので, 配列を使わずにごり押しで最大値を求めてみ ました. 配列を使う方法については今までの解答を見ればわかるはずです. その場合受け

関数の中で宣言された変数の有効範囲はその関数の中だけです さっきの rectangle _s で宣言されている変数 s は他の関数では使用できません ( 別の関数で同じ名前の変数を宣言することはできますが 全く別の変数として扱われます このように ある関数の中で宣言されている変数のことをその関数の

cp-7. 配列


スライド 1

関数 C 言語は関数の言語 関数とは 関数の定義 : f(x) = x * x ; 使うときは : y = f(x) 戻り値 引数


Microsoft Word - no11.docx

C言語入門

/*Source.cpp*/ #include<stdio.h> //printf はここでインクルードして初めて使えるようになる // ここで関数 average を定義 3 つの整数の平均値を返す double 型の関数です double average(int a,int b,int c){

本サンプル問題の著作権は日本商工会議所に帰属します また 本サンプル問題の無断転載 無断営利利用を厳禁します 本サンプル問題の内容や解答等に関するお問 い合わせは 受け付けておりませんので ご了承ください 日商プログラミング検定 STANDARD(C 言語 ) サンプル問題 知識科目 第 1 問 (


C による数値計算法入門 ( 第 2 版 ) 新装版 サンプルページ この本の定価 判型などは, 以下の URL からご覧いただけます. このサンプルページの内容は, 新装版 1 刷発行時のものです.

Taro-Basicの基礎・条件分岐(公

Taro-リストⅢ(公開版).jtd

C のコード例 (Z80 と同機能 ) int main(void) { int i,sum=0; for (i=1; i<=10; i++) sum=sum + i; printf ("sum=%d n",sum); 2

DVIOUT

Microsoft PowerPoint - prog07.ppt

Microsoft Word - no13.docx

x, y x 3 y xy 3 x 2 y + xy 2 x 3 + y 3 = x 3 y xy 3 x 2 y + xy 2 x 3 + y 3 = 15 xy (x y) (x + y) xy (x y) (x y) ( x 2 + xy + y 2) = 15 (x y)

[1] #include<stdio.h> main() { printf("hello, world."); return 0; } (G1) int long int float ± ±

C言語入門

PowerPoint プレゼンテーション

PowerPoint Presentation


6 関数 6-1 関数とは少し長いプログラムを作るようになると 同じ処理を何度も行う場面が出てくる そのたびに処 理を書いていたのでは明らかに無駄であるし プログラム全体の見通しも悪くなる そこで登場す るのが 関数 である 関数を使うことを 関数を呼び出す ともいう どのように使うのか 実際に見て

C¥×¥í¥°¥é¥ß¥ó¥° ÆþÌç

18 C ( ) hello world.c 1 #include <stdio.h> 2 3 main() 4 { 5 printf("hello World\n"); 6 } [ ] [ ] #include <stdio.h> % cc hello_world.c %./a.o

alg2015-4r2.ppt

PC Windows 95, Windows 98, Windows NT, Windows 2000, MS-DOS, UNIX CPU

Microsoft PowerPoint - 説明2_演算と型(C_guide2)【2015新教材対応確認済み】.pptx

プログラミング実習I

æœ•å¤§å–¬ç´—æŁ°,æœ•å°‘å–¬å•“æŁ°,ã…¦ã…¼ã‡¯ã…ªã……ã…›ã†®äº™éŽ¤æ³Ł


memo

() / (front end) (back end) (phase) (pass) 1 2

gengo1-8

PowerPoint プレゼンテーション

gengo1-10

memo

1990 IMO 1990/1/15 1:00-4:00 1 N N N 1, N 1 N 2, N 2 N 3 N 3 2 x x + 52 = 3 x x , A, B, C 3,, A B, C 2,,,, 7, A, B, C

C#の基本2 ~プログラムの制御構造~

Microsoft PowerPoint - prog08.ppt

memo

論理と計算(2)

PowerPoint プレゼンテーション

C 2 / 21 1 y = x 1.1 lagrange.c 1 / Laglange / 2 #include <stdio.h> 3 #include <math.h> 4 int main() 5 { 6 float x[10], y[10]; 7 float xx, pn, p; 8 in

Microsoft Word - 09

Microsoft PowerPoint - CproNt05.ppt [互換モード]

Microsoft PowerPoint - 計算機言語 第7回.ppt

Taro-C言語の基礎Ⅰ(公開版).j

alg2015-2r4.ppt

‚æ4›ñ

C 言語の式と文 C 言語の文 ( 関数の呼び出し ) printf("hello, n"); 式 a a+4 a++ a = 7 関数名関数の引数セミコロン 3 < a "hello" printf("hello") 関数の引数は () で囲み, 中に式を書く. 文 ( 式文 ) は

Microsoft PowerPoint - program.ppt [互換モード]

PowerPoint プレゼンテーション

情報処理演習 B8クラス

0 (18) /12/13 (19) n Z (n Z ) 5 30 (5 30 ) (mod 5) (20) ( ) (12, 8) = 4

スライド 1

Transcription:

再帰関数 Ⅰ 0. 目次 1. 階乗関数 2. 基本演算 2. 1 乗算 2. 2 除算 2. 3 剰余 3. 最大公約数. フィボナッチ関数 5. べき乗関数 5. 1 解法 1 5. 2 解法 2-1 -

1. 階乗関数 再帰関数は 関数の中で自分自身を呼び出す関数をいう 関数を簡潔に定義することができる 階乗関数 f(n) (n 0) を明示的に書くとつぎのようになる 再帰的定義 f(n) = n*(n-1)*(n-2) 2*1 (n 1) = 1 (n=0 ) 階乗 f(n)(n 0) は つぎのように再帰的に定義される f(n) = n * f(n-1) (n 1) = 1 (n=0 ) 階乗関数 f(n) の計算 n= の場合 f() = *f(3) = *3*f(2) = *3*2*f(1) = *3*2*1 = 2 階乗関数 f(n) は 定義通りに書ける プログラム (rf111.c) 1 /* << rf111.c >> */ 3 int f(int n); 5 int main() { 6 int n; /* 正整数 n */ 7 8 /* 正整数 n の読み込み */ 9 scanf("%d",&n); 10 11 /* 階乗関数 f(n) の計算 */ 12 printf("%d! = %d \n",n,f(n)); 13 } 1 15 /* 階乗関数 */ 16 int f(int n) { 17 int z; 18 if( n == 0 ) { 19 z = 1; 20 } else { 21 z = n*f(n-1); 22 } 23 return z; 2 } - 2 -

実行結果 % cc rf111.c %./a.out! = 2 n= の場合 プログラム rf111.c の動作は 1 から 9 のようになる 9 f() は値 2を返す f() 1 f() は f(3) を呼び出す 8 f(3) は値 6を f() に返す f(3) 2 f(3) は f(2) を呼び出す 7 f(2) は値 2を f(3) に返す f(2) 3 f(2) は f(1) を呼び出す 6 f(1) は値 1を f(2) に返す f(1) f(1) は f(0) を呼び出す 5 f(0) は値 1を f(1) に返す f(0) プログラム (rf111.c) において 関数 f が呼び出される回数 n 呼び出される回数 5 5 6 6 7 7 8 階乗関数 f(n) の動作解析 プログラム (rf112.c) 1 /* << rf112.c >> */ 実行結果 3 int f(int n); 1 % cc rf112.c 2 % a.out 5 int main() { 3 --> n= 6 int n; --> n=3 7 n = ; 5 --> n=2 8 printf("%d! = %d \n",n,f(n)); 6 --> n=1 9 } 7 --> n=0 10 int f(int n) { 8 <-- n=0 z=1 11 int z; 9 <-- n=1 z=1 12 printf("--> n=%d \n",n); 10 <-- n=2 z=2 13 if( n == 0 ) { 11 <-- n=3 z=6 1 z = 1; 12 <-- n= z=2 15 } else { 13! = 2 16 z = n * f(n-1); 17 } 18 printf("<-- n=%d z=%d \n",n,z); 19 return z; 20 } - 3 -

2. 基本演算 2. 1 乗算 再帰的定義 m,n を正整数とする mul(n,m) = 0 (m=0) = n + mul(n,m-1) (m 1) 乗算関数 mul(n,m) の計算 n=5,m=3 の場合 mul(5,3) = 5 + mul(5,2) = 5 + 5 + mul(5,1) = 5 + 5 + 5 + mul(5,0) = 5 + 5 + 5 + 0 = 15 乗算関数 mul(n,m) は 定義通りに書ける プログラム (rf211.c) 1 /* << rf211.c >> */ 3 int mul(int n, int m); 5 int main() { 6 int m,n; 7 8 while( 1 ) { 9 /* 正整数 n,m の読み込み */ 10 scanf("%d%d",&n,&m); 11 if( (n <= 0) (m <= 0) ) { break; } 12 13 printf("%d * %d = %d \n",n,m,mul(n,m)); 1 } 15 } 16 17 /* 乗算関数 */ 18 int mul(int n, int m) { 19 if( m == 0 ) { 20 return 0; 21 } else { 22 return n+mul(n,m-1); 23 } 2 } - -

実行結果 % cc rf211.c %./a.out 2 3 2 * 3 = 6-1 -1 プログラム rf211.c の動作 n=5,m=3 の場合 1 から 7 のようになる 7 mul(5,3) が 15を返す mul(5,3) 1 mul(5,3) が mul(5,2) を呼び出す 6 mul(5,2) が 10を返す mul(5,2) 2 mul(5,2) が mul(5,1) を呼び出す 5 mul(5,1) が 5を返す mul(5,1) 3 mul(5,1) が mul(5,0) を呼び出す mul(5,0) が 0を返す mul(5,0) プログラム (rf211.c) において n,m が与えられたとき 関数 mul が呼び出される回数 n m 呼び出される回数 123 5 6 5 123 12 268 1357 1358 198 1007 1008 2. 2 除算 再帰的定義 m,n を正整数とする n を m で割る div(n,m) = 0 (n<m) = 1 + div(n-m,m) (n m) 除算関数 div(n,m) の計算 n=15,m= の場合 div(15,) = 1 + div(11,) = 1 + 1 + div(7,) = 1 + 1 + 1 + div(3,) = 3-5 -

除算関数 div(n,m) を求めるプログラムはつぎのようになる プログラム (rf221.c) 1 /* << rf221.c >> */ 3 int div(int n, int m); 5 int main() { 6 int m,n; 7 8 while( 1 ) { 9 /* 正整数 n,m の読み込み */ 10 scanf("%d%d",&n,&m); 11 if( (n <= 0) (m <= 0) ) { break; } 12 13 printf("%d / %d = %d \n",n,m,div(n,m)); 1 } 15 } 16 17 /* 除算関数 */ 18 int div(int n, int m) { 19 if( n < m ) { 20 return 0; 21 } else { 22 return 1+div(n-m,m); 23 } 2 } 実行結果 % cc rf221.c %./a.out 12 3 12 / 3 = 12 12 / = 3 12 5 12 / 5 = 2-1 -1 プログラム rf221.c の動作 n=15,m= の場合 1 から 7 のようになる 7 div(15,) が 3を返す div(15,) 1 div(15,) が div(11,) を呼び出す 6 div(11,) が 2を返す div(11,) 2 div(11,) が div(7,) を呼び出す 5 div(7,) が 1を返す div(7,) 3 div(7,) が div(3,) を呼び出す div(3,) が 0を返す div(3,) - 6 -

プログラム (rf221.c) において n,m が与えられたとき 関数 div が呼び出される回数 n m 呼び出される回数 123 5 3 5 123 1 268 13 190 198 10 195 2. 3 剰余 m,n を正整数とする n を m で割ったとき得られる剰余 mod(n,m) の再帰的定義はつぎのようになる mod(n,m) = n (n<m) = mod(n-m,m) (n m) 剰余関数 mod(n,m) を求めるプログラムはつぎのようになる プログラム (rf231.c) 1 /* << rf231.c >> */ 3 int mod(int n, int m); 5 int main() { 6 int m,n; 7 8 while( 1 ) { 9 /* 正整数 n,m の読み込み */ 10 scanf("%d%d",&n,&m); 11 if( (n<=0) (m<=0) ) { break; } 12 13 printf("mod(%d,%d) = %d \n",n,m, mod(n,m)); 1 } 15 } 16 17 /* 剰余関数 */ 18 int mod(int n, int m) { 19 if( n < m ) { 20 return n; 21 } else { 22 return mod(n-m,m); 23 } 2 } - 7 -

実行結果 % cc rf231.c %./a.out 15 3 mod(15,3) = 0 15 mod(15,) = 3-1 -1 プログラム (rf231.c) において n,m が与えられたとき 関数 mod が呼び出される回数 n m 呼び出される回数 123 5 3 5 123 1 268 13 190 198 10 195-8 -

3. 最大公約数 正整数 a,b の最大公約数をユークリッド互除法で求める a = bq + r ( 0< r< b) のとき a と b の最大公約数 gcd(a,b) と b と r の最大公約数 gcd(b,r) が一致することに基づく すなわち gcd(a,b)=gcd(b,r) a=155, b=0 の場合, となる 155 = 0 * 3 + 35 gcd(155,0)=gcd(0,35) 0 = 35 * 1 + 5 gcd(0,35)=gcd(35,5) 35 = 5 * 7 gcd(35,5)=5 ( 考察 ) gcd(a,b)=gcd(b,r) の証明 a = bq + r (0<r<b) のとき a,b の公約数の集合を G(a,b) とおくと G(a,b) = G(b,r) が成り立つ これは a,b の最大公約数と b,r の最大公約数が一致することを意味する G(a,b) G(b,r) を示す a=a'k, b=b'k とすると a'k=b'kq+r となり 変形して r=(a'-b'q)k となる これは b,r が約数 k を持つことを意味する すなわち G(a,b) G(b,r) が示された G(a,b) G(b,r) を示す b=b'm, r=r'm とすると a=b'mq+r'm となり 変形して a=(b'q+r')m となる これは a,b が約数 m を持つことを意味する すなわち G(a,b) G(b,r) が示された 以上より G(a,b) = G(b,r) が証明された 再帰的定義 gcd(a,b) = gcd(b,r) (a=bq+r,r>0) = b (a=bq+r,r=0) - 9 -

関数 gcd(a,b) は 定義通りに書ける プログラム (rf311.c) 1 /* << rf311.c >> */ 3 int gcd(int a, int b); 5 int main() { 6 int a,b; 7 8 while( 1 ) { 9 /* 正整数 a,b の読み込み */ 10 scanf("%d%d",&a,&b); 11 if( (a <= 0) (b <= 0) ) { break; } 12 13 printf("gcd(%d,%d) = %d \n",a,b, gcd(a,b)); 1 } 15 } 16 17 /* 最大公約数 */ 18 int gcd(int a, int b) { 19 int r,z; 20 r = a % b; 21 if( r == 0 ) { 22 z = b; 23 } else { 2 z = gcd(b,r); 25 } 26 return z; 27 } 実行結果 % cc rf311.c %./a.out 123 567 gcd(123,567) = 1 120 6 gcd(120,6) = 8 0 0-10 -

a=155,b=0 の場合 プログラム rf311.c の動作は 1 から 5 のようになる 5 gcd(155,0) は値 5を返す gcd(155,0) 1 gcd(155,0) は gcd(0,35) を呼び出す gcd(0,35) は値 5を gcd(155,0) に返す gcd(0,35) 2 gcd(0,35) は gcd(35,5) を呼び出す 3 gcd(35,5) は値 5を gcd(0,35) に返す gcd(35,5) プログラム (rf311.c) において a,b が与えられたとき 関数 gcd が呼び出される回数 a b 呼び出される回数 123 5 5 5 123 6 120 6 2 89 55 9-11 -

関数 gcd(a,b) の動作解析 プログラム (rf312.c) 1 /* << rf312.c >> */ 3 int gcd(int a, int b); 5 int main() { 6 int a,b; 7 a = 123; b = 5; 8 printf("gcd(%d,%d) = %d \n",a,b,gcd(a,b)); 9 } 10 int gcd(int a, int b) { 11 int r,z; 12 printf("--> a=%d b=%d \n",a,b); 13 r = a % b; 1 if( r == 0 ) { 15 z = b; 16 } else { 17 z = gcd(b,r); 18 } 19 printf("<-- a=%d b=%d z=%d \n",a,b,z); 20 return z; 21 } 実行結果 1 % cc rf312.c 2 %./a.out 3 --> a=123 b=5 --> a=5 b=33 5 --> a=33 b=12 6 --> a=12 b=9 7 --> a=9 b=3 8 <-- a=9 b=3 z=3 9 <-- a=12 b=9 z=3 10 <-- a=33 b=12 z=3 11 <-- a=5 b=33 z=3 12 <-- a=123 b=5 z=3 13 gcd(123,5) = 3-12 -

. フィボナッチ関数 再帰的定義 フィボナッチ関数はつぎのように定義される f(n) = f(n-1) + f(n-2) (n 2) = 1 (n=1 ) = 1 (n=0 ) フィボナッチ関数 f(n) の計算 n=5 の場合 f(5) = f() + f(3) = f(3) + f(2) + f(2) + f(1) = f(3) + 2*f(2) + f(1) = f(2) + f(1) + 2*(f(1) + f(0)) + f(1) = f(2) + *f(1) + 2*f(0) = f(1) + f(0) + *f(1) + 2*f(0) = 5*f(1) + 3*f(0) = 8 フィボナッチ関数 f(n) の計算状況 n=5 の場合 f(5) f() f(3) ( 注意 ) 同じ値 f(k) が何度も計算され f(3) f(2) f(2) f(1) 効率が悪くなる f(2) f(1) f(1) f(0) f(1) f(0) f(5) 1 回 f() 1 回 f(1) f(0) f(3) 2 回 f(2) 3 回 f(1) 5 回 f(0) 3 回 - 13 -

フィボナッチ関数 f(n) は 定義通りに書ける プログラム (rf11.c) 1 /* << rf11.c >> */ 3 int f(int n); 5 int main() { 6 int n; 7 8 /* 正整数 n の読み込み */ 9 scanf("%d",&n); 10 printf("f(%d) = %d \n",n,f(n)); 11 } 12 13 /* フィボナッチ関数 */ 1 int f(int n) { 15 int z; 16 if( (n==0) (n==1) ) { 17 z = 1; 18 } else { 19 z = f(n-1) + f(n-2); 20 } 21 return z; 22 } 実行結果 % cc rf11.c %./a.out 9 f(9) = 55 プログラム (rf11.c) において 関数 f が呼び出される回数 n 呼び出される回数 3 5 9 5 15 6 25-1 -

フィボナッチ関数 f(n) の動作解析 プログラム (rf12.c) 実行結果 1 /* << rf12.c >> */ % cc rf12.c % a.out 3 int f(int n); 1 --> n= 2 --> n=2 5 int main() { 3 --> n=0 6 int n; <-- n=0 z=1 7 n = ; 5 --> n=1 8 printf("f(%d) = %d \n",n,f(n)); 6 <-- n=1 z=1 9 } 7 <-- n=2 z=2 10 int f(int n) { 8 --> n=3 11 int z; 9 --> n=1 12 printf("--> n=%d \n",n); 10 <-- n=1 z=1 13 if( (n==0) (n==1) ) { 11 --> n=2 1 z = 1; 12 --> n=0 15 } else { 13 <-- n=0 z=1 16 z = f(n-1) + f(n-2); 1 --> n=1 17 } 15 <-- n=1 z=1 18 printf("<-- n=%d z=%d \n",n,z); 16 <-- n=2 z=2 19 return z; 17 <-- n=3 z=3 20 } 18 <-- n= z=5 f() = 5 関数 f(n) が呼び出される順序 1 18 f() 8 17 2 7 f(3) f(2) 11 16 9 10 5 6 3 f(2) f(1) f(1) f(0) 1 15 12 13 f(1) f(0) 1 2 ~ 17 18 は呼ばれる順序 大きい n の値について実行時間を測定する プログラム (rf13.c) 1 /* << rf13.c >> */ 3 double f(int n); 5 int main() { 6 int n; 7 8 /* 正整数 n の読み込み */ 9 scanf("%d",&n); 10 printf("f(%d) = %16.0f\n",n,f(n)); 11 } - 15 -

12 13 /* フィボナッチ関数 */ 1 double f(int n) { 15 double z; 16 if( (n==0) (n==1) ) { 17 z = 1.0; 18 } else { 19 z = f(n-1) + f(n-2); 20 } 21 return z; 22 } 実行時間 % cc rf13.c % time./a.out 5 f(5) = 1836311903 16.927u 0.007s 0:18.23 92.8% 0+0k 0+0io 0pf+0w % time./a.out 6 f(6) = 2971215073 27.398u 0.008s 0:29.36 93.2% 0+0k 0+8io 0pf+0w % time./a.out 7 f(7) = 807526976.325u 0.029s 0:9.87 88.9% 0+0k 0+0io 0pf+0w 指定した範囲の f(n)(0 n 10) について 計算結果を配列に保存し 2 度目以降計算をしないようにして プログラム ( rf13.c) を改良する プログラム (rf13a.c) 1 /* << rf13a.c >> */ 3 #define N 10 /* 事前に計算しておく最大値 */ double g[n+1]; /* 保存用の配列 */ 5 double f(int n); 6 7 int main() { 8 int i,n; 9 10 /* 正整数 n の読み込み */ 11 scanf("%d",&n); 12 13 /* 初期設定 */ 1 g[0] = 1; g[1] = 1; 15 for( i=2; i<=n; i++ ) { 16 g[i] = g[i-1] + g[i-2]; 17 } - 16 -

18 19 printf("f(%d) = %16.0f\n",n,f(n)); 20 } 21 22 /* フィボナッチ関数 */ 23 double f(int n) { 2 double z; 25 if( n <= N ) { 26 z = g[n]; 27 } else { 28 z = f(n-1) + f(n-2); 29 } 30 return z; 31 } 実行時間 % cc rf13a.c % time./a.out 5 f(5) = 1836311903 0.255u 0.000s 0:01.9 16.7% 0+0k 0+0io 0pf+0w % time./a.out 6 f(6) = 2971215073 0.17u 0.000s 0:01.62 25.3% 0+0k 0+0io 0pf+0w % time./a.out 7 f(7) = 807526976 0.666u 0.000s 0:02.7 2.0% 0+0k 0+0io 0pf+0w - 17 -

5. べき乗関数 べき乗 ( a n a: 実数 n: 正整数 ) の計算法を考察する 5. 1 解法 1 再帰的定義 1 a n = a n-1 * a (n 1) = 1 (n=0 ) 再帰的定義 1 で べき乗関数 g1(a,n) を求める プログラム (rf511.c) 1 /* << rf511.c >> */ 3 float g1(float a, int n); 5 int main() { 6 int n; 7 float a; 8 9 while( 1 ) { 10 /* 実数 a と正整数 n の読み込み */ 11 scanf("%f%d",&a,&n); 12 if( n < 0 ) { break; } 13 1 printf("%f ** %d = %f \n",a,n,g1(a,n)); 15 } 16 } 17 18 /* べき乗の計算 */ 19 float g1(float a, int n) { 20 if( n == 0 ) { 21 return 1.0; 22 } else { 23 return a*g1(a,n-1); 2 } 25 } - 18 -

実行結果 % cc rf511.c %./a.out 2.0 2 2.000000 ** 2 =.000000 2.0 20 2.000000 ** 20 = 108576.000000 0.0-1 プログラム (rf511.c) において a,n が与えられたとき 関数 g1 が呼び出される回数 a n 呼び出される回数 2 5 6 2 8 9 2 12 13 2 15 16 5. 2 解法 2 再帰的定義 2 計算例 a n = a n/2 * a n/2 nが偶数の場合 = a n-1 * a nが奇数の場合 = 1 n=0の場合 a 20 = a 10 a 10 a 10 = a 5 a 5 a 5 = a a a = a 2 a 2 a 2 = a a 再帰的定義 2 で べき乗関数 g2(a,n) を求める プログラム (rf521.c) 1 /* << rf521.c >> */ 3 float g2(float a, int n); 5 int main() { 6 int n; 7 float a; 8 9 while( 1 ) { 10 /* 実数 a と正整数 n の読み込み */ - 19 -

11 scanf("%f%d",&a,&n); 12 if( n < 0 ) { break; } 13 1 printf("%f ** %d = %f \n",a,n,g2(a,n)); 15 } 16 } 17 18 /* べき乗の計算 */ 19 float g2(float a, int n) { 20 float b; 21 if( n == 0 ) { return 1.0; } 22 if( n%2 == 0 ) { 23 b = g2(a,n/2); return b*b; 2 } else { 25 b = g2(a,n-1); return b*a; 26 } 27 } 実行結果 % cc rf521.c %./a.out 2.0 2 2.000000 ** 2 =.000000 2.0 20 2.000000 ** 20 = 108576.000000 0.0-1 プログラム (rf521.c) において a,n が与えられたとき 関数 g2 が呼び出される回数 a n 呼び出される回数 2 5 5 2 8 5 2 12 6 2 15 8-20 -