プログラミング演習1
― 課題4 数値解析 ―
3. 数値積分
3.1 台形公式
台形公式の1区間分の近似式は
I = ∫ab f (x ) dx ≒ (b -a )[f (a ) + f (b )] / 2
積分範囲を n 分割したときの複合公式は
この式からPADを素直に描くと以下のようになる。
![]()
ここで、f (a +ih)のカッコ内の乗算をなくすために xi = a +ih とおき、
x 0 = a, xi +1 = xi +h
というように帰納的に計算すると、以下のようになる。
しかし、このアルゴリズムでは加算による丸め誤差の累積が発生しやすい。 実際、台形公式による積分計算を単精度(float)で行うプログラムを用いて、 上記2つのアルゴリズムを比較してみる。1: #include <stdio.h> 2: #include <math.h> 3: 4: float f(float x) 5: { 6: return 4.0 / (1 + x * x); // f(x) = 4/(1+x2) 7: } 8: 9: float Trapez(float a, float b, float (*f)(float), int n) 10: /* 11: * 累積誤差がない単精度の数値積分ルーチン(台形公式) 12: */ 13: { 14: int i; 15: float h, s; 16: 17: h = (b - a) / n; 18: s = ((*f)(a) + (*f)(b)) / 2; 19: for (i = 1; i < n; i++) { 20: s += (*f)(a + i * h); // 累積誤差はない 21: } 22: return h * s; 23: } 24: 25: float Trapez2(float a, float b, float (*f)(float), int n) 26: /* 27: * 累積誤差がある単精度の数値積分ルーチン(台形公式) 28: */ 29: { 30: int i; 31: float h, x, s; 32: 33: h = (b - a) / n; 34: x = a; 35: s = ((*f)(a) + (*f)(b)) / 2; 36: for (i = 1; i < n; i++) { 37: x += h; // 累積誤差発生要因 38: s += (*f)(x); 39: } 40: return h * s; 41: } 42: 43: main() 44: { 45: int n; 46: float a, b計算結果を示すと以下のようになる。, s; 47: 48: a = 0; b = 1; 49: printf("# 分割数, 累積誤差なし, 累積誤差あり\n"); 50: for (n = 40; n <= 10000; n += 20) 51: printf("%5d, % .15e, % .15e\n", n, Trapez(a, b, f, n), Trapez2(a, b, f, n)); 52: return 0; 53: }![]()
練習問題
(1) 上記の結果を確認せよ。
(2) 倍精度(double)で計算し、単精度の結果と比較してみよ。
【目次】 | 【1.】 | 【2.】 | 【3.のつづき】 | 【付録1】 | 【付録2】