/* * example6.c --- DE 公式 * * 1 2 (1/2) * I1 = ∫ (1-x ) dx = π/2 * -1 * * 1 2 (-1/2) * I2 = ∫ (1-x ) dx = π * -1 * * いずれも端点に特異性があって、古典的な数値積分公式はうまく行かない。 * double exponential formula (DE公式) ならばうまく計算できる。 * * コンパイル: cc -o example6 example6.c * */ #include <stdio.h> #include <math.h> #include <string.h> typedef double ddfunction(double); double pi, halfpi; /* φ */ double phi1(double t) { return tanh(halfpi * sinh(t)); } /* 2乗 */ double sqr(double x) { return x * x; } /* φ' */ double dphi1(double t) { return halfpi * cosh(t) / sqr(cosh(halfpi * sinh(t))); } /* DE 公式による (-1,1) における定積分の計算 */ double de(ddfunction f, double h, double N) { int n; double t, S, dS; S = f(phi1(0.0)) * dphi1(0.0); for (n = 1; n <= N; n++) { t = n * h; dS = f(phi1(t)) * dphi1(t) + f(phi1(-t)) * dphi1(- t); S += dS; } return h * S; } /* テスト用の被積分関数 その1 */ double f1(double x) { return sqrt(1 - x * x); } /* テスト用の被積分関数 その2 */ double f2(double x) { if (x >= 1.0 || x <= -1.0) // φ(t)の計算で情報落ちで1になる場合の安全網 return 0; else return 1 / sqrt(1 - x * x); } void test(ddfunction f, double I) { int m, N; double h, IhN; /* |t|≦3 まで計算することにする */ h = 1.0; N = 3; /* h を半分, N を倍にして double exponential formula で計算してゆく */ for (m = 1; m <= 10; m++) { IhN = de(f, h, N); printf("h=%f, N=%4d, I_hN=%25.16f, I_hN-I=%e\n", h, N, IhN, IhN - I); h /= 2; N *= 2; } } int main(void) { pi = 4.0 * atan(1.0); halfpi = pi / 2; printf("DE公式による数値積分\n"); printf("test1 (sqrt(1-x^2) の積分)\n"); test(f1, halfpi); printf("test2 (1/sqrt(1-x^2) の積分)\n"); test(f2, pi); return 0; }