[ 簡単な説明 ] 補間法(内挿法)関連のライブラリです。 最小2乗近似法は、標本点データから近似多項式の係数を求める手法です。 ラグランジェ補間、およびスプライン補間は、補間点xにおける補間値を求めます。 これらに入力する標本点配列 xdata [ ] とそれぞれの標本点における関数値配列 ydata [ ] は、x の昇順にあらかじめ整列しておく必要があります。また、補間点xは標本点の区間内にある必要があります。 チェビシェフ近似は、関数を多項式で近似する手法です。指定区間内で極めて高精度の多項式近似を行います。 チェビシェフ近似は、チェビシェフ多項式を用いて関数近似を行いますが、チェビシェフ多項式は、-1 ≦ x ≦ 1 の範囲で定義されるので、まず区間変換を行います。(1次の変数変換) 近似多項式の係数が求まったのち、区間の逆変換を行い、与えられた関数に対する近似多項式の係数を計算します。本プログラム中では、その逆変換を行うために、パスカルの三角形による2項係数の計算を行っています。 |
関数名 | 関数の機能 | 機能説明 | 呼び出し例 |
lstsq( ) | 最小2乗近似法 | n個の要素を持つ double型配列 x[ ]、y[ ]より 次数 m の多項式係数 c[ ] を求める |
lstsq(x, y, n, m, c); |
lagra( ) | ラグランジェ補間 | n個の点 xdata[ ],ydata[ ] から 点 x における補間値を求める |
y = lagra(xdata, ydata, n, x); |
splint( ) | スプライン補間 | y = splint(xdata, ydata, n, x); | |
chebyshev( ) | チェビシェフ近似 | 多項式近似したい関数を double _f(x) で定義して、 近似範囲 min,max 、次数 n を与えると チェビシェフ近似による係数配列 a[ ] を計算する |
chebyshev(min, max, n, a); |
polynomial( ) | 多項式計算 | 係数配列 a[ ] 、値 x 、次数 n より 多項式の値を計算する |
y = polynomial(a, x, n); |
/* interp.c */ #include <stdio.h> #include <stdlib.h> #include "sslib.h" void lstsq(double x[], double y[], int n, int m, double c[]) { int i, j, k, m2, mp1, mp2; double *a, aik, pivot, *w, w1, w2, w3; if(m >= n || m < 1) { fprintf(stderr, "Error : Illegal parameter in lstsq()\n"); return; } mp1 = m + 1; mp2 = m + 2; m2 = 2 * m; a = (double *)malloc(mp1 * mp2 * sizeof(double)); if(a == NULL) { fprintf(stderr, "Error : Out of memory in lstsq()\n"); return; } w = (double *)malloc(mp1 * 2 * sizeof(double)); if(w == NULL) { fprintf(stderr, "Error : Out of memory in lstsq()\n"); free(a); return; } for(i = 0; i < m2; i++) { w1 = 0.; for(j = 0; j < n; j++) { w2 = w3 = x[j]; for(k = 0; k < i; k++) w2 *= w3; w1 += w2; } w[i] = w1; } a[0] = n; for(i = 0; i < mp1; i++) for(j = 0; j < mp1; j++) if(i || j) a[i * mp2 + j] = w[i + j - 1]; w1 = 0.; for(i = 0; i < n; i++) w1 += y[i]; a[mp1] = w1; for(i = 0; i < m; i++) { w1 = 0.; for(j = 0; j < n; j++) { w2 = w3 = x[j]; for(k = 0; k < i; k++) w2 *= w3; w1 += y[j] * w2; } a[mp2 * (i + 1) + mp1] = w1; } for(k = 0; k < mp1; k++) { pivot = a[mp2 * k + k]; a[mp2 * k + k] = 1.0; for(j = k + 1; j < mp2; j++) a[mp2 * k + j] /= pivot; for(i = 0; i < mp1; i++) { if(i != k) { aik = a[mp2 * i + k]; for(j = k; j < mp2; j++) a[mp2 * i + j] -= aik * a[mp2 * k + j]; } } } for(i = 0; i < mp1; i++) c[i] = a[mp2 * i + mp1]; free(w); free(a); return; } double lagra(double xx[], double yy[], int n, double xi) { int flag, i, j, *jun, *k; double *p, *q, *r, *s, w, w1, w2, w3, *x, *y; x = (double *)malloc(n * sizeof(double)); if(x == NULL) { fprintf(stderr, "Error : Out of memory in lagra()\n"); return 0.; } y = (double *)malloc(n * sizeof(double)); if(y == NULL) { fprintf(stderr, "Error : Out of memory in lagra()\n"); free((char *)x); return 0.; } for(i = 0, p = xx, flag = 0; i < n - 1; i++, p++) { if(*p >= *(p + 1)) { flag = 1; break; } } if(flag) { jun = (int *)malloc(n * sizeof(int)); if(jun == NULL) { fprintf(stderr, "Error : Out of memory in lagra()\n"); free((char *)x); free((char *)y); return 0.; } sortdi1(xx, n, jun); for(i = 0, p = x, q = y, k = jun; i < n; i++) { *p++ = *(xx + *k); *q++ = *(yy + *k++); } free((char *)jun); } else { for(i = 0, p = x, q = y, r = xx, s = yy; i < n; i++) { *p++ = *r++; *q++ = *s++; } } if(n < 2 || xi < *x || xi > *(x + n - 1)) { fprintf(stderr, "Error : Illegal parameter in lagra()\n"); free((char *)x); free((char *)y); return 0.; } for(i = 0, p = x; i < n; i++) { if(*p++ == xi) { free((char *)x); free((char *)y); return *(y + i); } } w = 0.; for(i = 0, p = x, q = y; i < n; i++) { w1 = 1.; w2 = *p++; for(j = 0, r = x; j < n; j++) { w3 = *r++; if(i != j) w1 *= (xi - w3) / (w2 - w3); } w += w1 * *q++; } free((char *)x); free((char *)y); return w; } double splint(double xx[], double yy[], int n, double xi) { int flag, i, *jun, *k; double dxp, dxm, *h, hi, hi2, *p, *q, *r, *s, sm, si, *sp, *x, *y, yi; x = (double *)malloc(n * sizeof(double)); if(x == NULL) { fprintf(stderr, "Error : Out of memory in splint()\n"); return 0.; } y = (double *)malloc(n * sizeof(double)); if(y == NULL) { fprintf(stderr, "Error : Out of memory in splint()\n"); free((char *)x); return 0.; } for(i = 0, p = xx, flag = 0; i < n - 1; i++, p++) { if(*p >= *(p + 1)) { flag = 1; break; } } if(flag) { jun = (int *)malloc(n * sizeof(int)); if(jun == NULL) { fprintf(stderr, "Error : Out of memory in splint()\n"); free((char *)x); free((char *)y); return 0.; } sortdi1(xx, n, jun); for(i = 0, p = x, q = y, k = jun; i < n; i++) { *p++ = *(xx + *k); *q++ = *(yy + *k++); } free((char *)jun); } else { for(i = 0, p = x, q = y, r = xx, s = yy; i < n; i++) { *p++ = *r++; *q++ = *s++; } } if(n < 2 || xi < *x || xi > *(x + n - 1)) { fprintf(stderr, "Error : Illegal parameter in splint()\n"); free((char *)x); free((char *)y); return 0.; } for(i = 0, p = x; i < n; i++) { if(*p++ == xi) { free((char *)x); free((char *)y); return *(y + i); } } h = (double *)malloc(n * sizeof(double)); if(h == NULL) { fprintf(stderr, "Error : Out of memory in splint()\n"); free((char *)x); free((char *)y); return 0.; } sp = (double *)malloc(n * sizeof(double)); if(sp == NULL) { fprintf(stderr, "Error : Out of memory in splint()\n"); free((char *)x); free((char *)y); free((char *)h); return 0.; } subspl(x, y, n - 1, h, sp); for(i = 1, p = x + 1; i <= n; i++, p++) { if(*(p - 1) <= xi && xi < *p) { sm = *(sp + i - 1); si = *(sp + i); hi = *(h + i); hi2 = hi * hi; dxp = *p - xi; dxm = xi - *(p - 1); yi = ( sm * dxp * dxp * dxp + si * dxm * dxm * dxm + (6. * *(y + i - 1) - hi2 * sm) * dxp + (6. * *(y + i) - hi2 * si) * dxm) / hi / 6.; free((char *)x); free((char *)y); free((char *)h); free((char *)sp); return yi; } } return 0; } double polynomial(double a[], double x, int n) { int i; double w; w = a[n]; for(i = n - 1; i >= 0; i--) w = w * x + a[i]; return w; } void chebyshev(double min, double max, int n, double a[]) { /* min, max : range of approximation */ double **T; double *c, *func, *x; double k1, k2, n1, w; int i, j; if(min == max || n <= 0) { fprintf(stderr, "Error : illegal parameter input in chebyshev()\n"); return; } T = (double **)malloc((n + 1) * sizeof(double *)); if(T == NULL) { fprintf(stderr, "Error : out of memory in chebyshev().\n"); return; } for(i = 0; i <= n; i++) { T[i] = (double *)calloc(i + 1, sizeof(double)); if(T[i] == NULL) { fprintf(stderr, "Error : out of memory in chebyshev().\n"); return; } } c = (double *)calloc(n + 1, sizeof(double)); func = (double *)calloc(n + 1, sizeof(double)); x = (double *)calloc(n + 1, sizeof(double)); if(c == NULL || func == NULL || x == NULL) { fprintf(stderr, "Error : out of memory in chebyshev().\n"); return; } /* Chebyshev Polynomial */ T[0][0] = 1; T[1][0] = 0; T[1][1] = 1; for(i = 2; i <= n; i++) { for(j = 1; j <= i; j++) T[i][j] = 2. * T[i - 1][j - 1]; for(j = 0; j < i - 1; j++) T[i][j] -= T[i - 2][j]; } k1 = (max - min) / 2.; k2 = (min + max) / 2.; n1 = n + 1; w = 0.5 * M_PI / n1; for(i = 0; i <= n; i++) { x[i] = cos((2 * i + 1) * w); func[i] = _f(k1 * x[i] + k2); } w = 0.; for(j = 0; j <= n; j++) w += func[j]; c[0] = w / n1; for(i = 1; i <= n; i++) { w = 0.; for(j = 0; j <= n; j++) w += func[j] * polynomial(T[i], x[j], i); c[i] = 2. * w / n1; } for(i = 0; i <= n; i++) a[i] = 0; for(i = 0; i <= n; i++) { w = c[i]; for(j = 0; j <= i; j++) a[j] += w * T[i][j]; } if(min != -1. || max != 1.) { for(i = 1; i <= n; i++) for(j = 1; j <= i; j++) a[i] /= k1; if(k2 != 0.) T[0][0] = 1; /* Pascal's Triangle */ for(i = 1; i <= n; i++) { T[i][0] = 1; T[i][i] = 1; for(j = 1; j < i; j++) T[i][j] = T[i - 1][j] + T[i - 1][j - 1]; } for(i = 0; i <= n; i++) { c[i] = a[i]; w = -k2 * a[i]; for(j = i - 1; j >= 0; j--) { c[j] += T[i][j] * w; w *= -k2; } } for(i = 0; i <= n; i++) a[i] = c[i]; } free((char *)c); free((char *)func); free((char *)x); for(i = 0; i <= n; i++) free((char *)T[i]); free((char *)T); return; } |