指数関数の計算プログラム(補足)
このページでは、テイラー展開 $$ e^x = \sum_{n=0}^{\infty} \frac{x^n}{n!} $$ を使って指数関数の値を計算するプログラムを、いくつかのステップを踏みながら構成してみたい。 もちろん、$n$を無限大まで加えることはコンピュータには無理なので、以下では$n=9$までで打ち切ることにする。
ステップ1:階乗の計算プログラム (ex7-1.c)
いきなり指数関数を計算するのは複雑なので、まずは、0から9までの数の階乗を計算して表示するプログラムを作ってみる。0!は1であることを考慮すると、以下のように書けるだろう。
#include <stdio.h> main() { int n ; float fact ; fact=1 ; for (n=0; n<10; n=n+1) { if (n>0) { fact = fact * n ; } printf("%dの階乗 = %f\n",n,fact) ; } }
ステップ2:xのべき乗の計算プログラム(ex7-2.c)
つぎは、xの値を入れると、xのn乗($x^n$)をn=0から順に$n=9$まで順に計算するプログラムの例。xの0乗は1であることに注意。
#include <stdio.h> main() { int n ; float x, p ; printf("xの値:") ; scanf("%f",&x) ; p=1 ; for (n=0; n<10; n=n+1) { if (n>0) { p = p * x ; } printf("%fの%d乗 = %f \n",x,n,p) ; } }
ステップ3:テイラー展開の各項を計算するプログラム(ex7-3.c)
すると、テイラー展開の各項は、階乗とべき乗の組み合わせ($\frac{1}{n!} x^n$)なのだから、上の2つの計算を組み合わせて:
#include <stdio.h> main() { int n ; float x, p, fact ; printf("xの値:") ; scanf("%f",&x) ; p=1 ; fact=1 ; for (n=0; n<10; n=n+1) { if (n>0) { fact = fact * n ; p = p * x ; } printf("第%d項 = %f \n",n,1/fact*p) ; } }
ステップ4:級数和を使って指数関数を求めるプログラム(ex7.c)
例題7のプログラムは、上記のプログラムを組み合わせた格好をしていることがわかるだろうか。
#include <stdio.h> main() { int n ; float sum, x, p, fact ; printf("xの値:") ; scanf("%f",&x) ; p=1 ; fact=1 ; sum = 0 ; for (n=0; n<10; n=n+1) { if (n>0) { fact = fact * n ; p = p * x ; } sum = sum + 1/fact * p ; } printf("EXP( %f ) = %f \n",x,sum) ; }
ここではその動作をさらに少し詳しく見てみよう。
プログラムの開始からの変数の値の変化を表にまとめたので、追いかけてみるとよい。プログラムを書くときは、このような表を頭に思い浮かべ、プログラムの動作を「シミュレーション」しながら考えることが大切(特に慣れないうちは)。
実行される箇所 | 動作 | nの値 | sumの値 | xの値 | pの値 | factの値 |
int n ; | 整数型のメモリーを確保 | 領域確保 | 未定義 | 未定義 | 未定義 | 未定義 |
float sum, x,p,fact | 実数型のメモリーを確保 | 領域確保 | 領域確保 | 領域確保 | 領域確保 | |
setbuf(stdout,NULL) ; printf("Xの値:") ; |
画面に「Xの値:」と表示 | |||||
scanf("%f",&x) ; | キーボードにタイプした数値を 変数xにセット。 ここではxに2をセットしたと仮定。 |
2 | ||||
p=1 ; | 2 | 1 | ||||
fact=1 ; | 2 | 1 | 1 | |||
sum=0 ; | 0 | 2 | 1 | 1 | ||
for (n=0 ; ... ; ...) { | nを0にセットしてから反復開始 | 0 | 0 | 2 | 1 | 1 |
for ( ...; n<10 ; ...) { | n<10かどうかチェック。 nは0なので反復1回目を開始。 |
0 | 0 | 2 | 1 | 1 |
if (n>0) { ... } | n>0かどうかチェック nは0だからこの条件は満足されない。よって、{ ... }の中はスキップ。 |
0 | 0 | 2 | 1 | 1 |
sum = sum + 1/fact * p ; | 0 + 1/1*1 をsumにセット | 0 | 0→1 | 2 | 1 | 1 |
for ( ... ; ... ; n=n+1) | forの中の3番目の文が反復の度に実行される。 nを1だけ更新 |
0→1 | 1 | 2 | 1 | 1 |
for ( ...; n<10 ; ...) { | n<10かどうかチェック。 nは1なので反復2回目を開始。 |
1 | 1 | 2 | 1 | 1 |
if (n>0) { | n>0かどうかチェック。 nは1なので条件を満足 |
1 | 1 | 2 | 1 | 1 |
fact=fact*n ; | 1*1(=1の階乗) をfactにセット |
1 | 1 | 2 | 1 | 1→1 |
p=p*x ; } |
1*2 (=xの1乗) をpにセット | 1 | 1 | 2 | 1→2 | 1 |
sum = sum + 1/fact * p ; | 1 + 1/1*2 をsumにセット | 1 | 1→3 | 2 | 2 | 1 |
for ( ... ; ... ; n=n+1) | nを更新 | 1→2 | 3 | 2 | 2 | 1 |
for ( ...; n<10 ; ...) { | nは2なので反復3回目を開始。 | 2 | 3 | 2 | 2 | 1 |
if (n>0) { | nは2なので条件を満足 | 2 | 3 | 2 | 2 | 1 |
fact=fact*n ; | 1*2 (=2の階乗) をfactにセット | 2 | 3 | 2 | 2 | 1→2 |
p=p*x ; } |
2*2 (=2の2乗)をpにセット | 2 | 3 | 2 | 2→4 | 2 |
sum=sum+1/fact*p ; | 3 + 1/2*4 をsumにセット | 2 | 3→5 | 2 | 4 | 2 |
for ( ... ; ... ; n=n+1) | nを更新 | 2→3 | 5 | 2 | 4 | 2 |
for ( ...; n<10 ; ...) { | nは3なので反復4回目を開始。 | 3 | 5 | 2 | 4 | 2 |
途 中 略 | ||||||
for ( ...; n<10 ; ...) { | nが10なので、条件を満足せず、反復を終了。 | 10 | 7.39... | 2 | 512 | 362880 |
printf("EXP( %f ) = %f \n",x,sum) ; | 結果を表示。 |
1回目のループ(nは0)で sum = 1/0! * 20
2回目のループ(nは1)で sum = 1/0! * 20 + 1/1! * 21
3回目のループ(nは2)で sum = 1/0! * 20 + 1/1! * 21 + 1/2! * 22
4回目のループ(nは3)で sum = 1/0! * 20 + 1/1! * 21 + 1/2! * 22 + 1/3! * 23
という順に、nが10になったところで、計算を打ち切って、 $$ e^x = \sum_{n=0}^{9} \frac{x^n}{n!} $$ が計算されている様子が分かるだろうか。