[PR] この広告は3ヶ月以上更新がないため表示されています。
ホームページを更新後24時間以内に表示されなくなります。
関数f(x)のあるx=aでのf'(a),f"(a)を数値的に近似計算をする。 微分の定義は f'(a) = lim[h→0] (f(a+h) - f(a))/h これを近似するのに lim[h→0] h = ⊿x を代用すればよい、と考えるのが数値微分の基本的な発想である。 次のように前方差分、後方微分、中心微分を定義する。前方差分(forward difference) ⊿y/⊿x = (f(x+⊿x) - f(x))/⊿x 後方差分または後退差分(backward difference) ∇y/∇x = (f(x) - f(x-⊿x))/⊿x 中心差分(central difference) δy/δx = (f(x+⊿x) - f(x-⊿x))/2⊿x これは、⊿y/⊿xと∇y/∇xの平均となる。 テイラー展開をしてみる f(x+⊿x) = f(x)+f'(x)⊿x/1!+f"(x)(⊿x)2/2!+ … +f(n)(⊿x)n/n!+ … これから {f(x+⊿x)-f(x)}/⊿x = f'(x)/1!+f"(x)(⊿x)1/2!+ … +f(n)(⊿x)n-1/n!+ … ∴⊿x/⊿y = f'(x)+f"(x)(⊿x)1/2!+ … +f(n)(⊿x)n-1/n!+ … 同様に f(x-⊿x) = f(x)-f'(x)⊿x/1!+f"(x)(⊿x)2/2!+ … -f(n)(⊿x)n/n!+ … これから {f(x)-f(x-⊿x)}/⊿x = f'(x)/1!-f"(x)(⊿x)1/2!+ … +f(n)(⊿x)n-1/n!+ … ∴∇x/∇y = f'(x)-f"(x)(⊿x)1/2!+ … +f(n)(⊿x)n-1/n!+ … n階微係数の近似 上のテイラー展開した式を用いる。 読み飛ばした者は結果(太文字)だけでも見るように。 ⊿y/⊿x-∇y/∇x = f"(x)⊿x+f""(x)(⊿x)2/2・4!+ … これを⊿xで割れば (⊿y/⊿x-∇y/∇x)/⊿x = f"(x)+f""(x)⊿x+ … f""(x)⊿x以上の項は小さいので無視すれば (⊿y/⊿x-∇y/∇x)/⊿xはf"(x)の近似とできる。 また、これを δ2y/δx2と表し、2階の中心差分という。
#include <stdio.h> #include <math.h> #define dx (0.1) //⊿x /** * xの関数f(x)について * f"(a)の近似値を求める。 * ---- * ここでは * f(x)=x^3 * f"(x)=6xのハズだが… */ float f(float x){ return pow(x,3); //f(x)=x^3 } main(){ float x,fpp; for(x=0;x<10;x++){ fpp=(f(x+dx)-2*f(x)+f(x-dx))/dx/dx; printf("f\"(%1.0f) = %f\n",x,fpp); } }
f(x)=x3という式について f"(x)を求めている。 式は単純なのでプログラムに任せるまでもなく、 f"(x)=6xとわかる。 実際にプログラムで、 f"(0)、f"(1)、f"(2) … f"(9) の計算結果を表示している。 0,6,12,18,,,54 と、出力されれば完全だが… 誤差は⊿x(プログラムではdx)の二乗に比例する。 即ち、小さければ小さい程(理論上)精密になるが、それは桁数を いくらでも取れる場合だけで、f(x+⊿x)-f(x)の結果が0や無意味な 数値になってしまう。 一般の場合 δny/δxnについては(n∈N) nが偶数の時 δny/δxn = {(δn-2y/δ(x+⊿x)n-2) - 2(δn-2y/δxn-2) + (δn-2y/δ(x-⊿x)n-2)}/⊿x2 nが奇数の時 δny/δxn = {(δn-1y/δ(x+⊿x)n-1) - (δn-1y/δ(x-⊿x)n-1)}/2⊿x これをスターリング(Stirling)の方式という。 数値積分 定積分は次のように表せる ∫[a~b] f(x)・dx = lim[n→∞](b-a)/nΣ[k=1~n]f(a+k(b-a)/n) と書けてlim[n→∞]nの代わりに「十分大きなn」を使うことで近似する。 定積分は下の図の青色の斜線の面積を求めることになる。xのa~bをn等分し、端からx0(=a)、x1、x2、…xn-1、xn(=b)とする。 xkはa+k(b-a)/nである。 また、分割したxの幅を⊿xとする。 ⊿x = (b-a)/n = xn-xn-1 よって、 I = Σ⊿x*{f(xn)+f(xn+1)}/2 ●f(x)=4/(1+x2)のxの定義域[0~1]でdxで積分する。 x=tanθとする。 1/(1+x2)=cos2θ dx=1/cos2θ であるから、 ∫f(x)・dx = ∫1・dθ = π
#include <stdio.h> /** * f(x) = 4/(1+x^2)の積分 */ float f(float x){ return 4/(1+x*x); } main(){ float k,n,a,b; float sum=0.0,dx; printf("分割数 n=");scanf("%f",&n); a=0;b=1; dx=(b-a)/n; for(k=0;k<n;k++){ sum += dx * (f(a+(b-a)*k/n)+f(a+(b-a)*(k+1)/n))/2; } printf("∫4/(1+x^2)・dx = %f",sum); }
初めにnを指定する。 256とすると3.141590と表示され、大体πとなる。 ちなみに、k,n,a,bはint型でもいいような気がするが dx=(b-a)/n や(a+(b-a)*k/n) が、勝手にintに縛られ、いちいち変数の前に(float)をつけるのは 面倒なので、初めにfloat型で宣言した。