/****************************/ /* 最小二乗法(多項式近似) */ /* coded by Y.Suganuma */ /****************************/ #include <stdio.h> #include <math.h> int gauss(double **, int, int, double); double *least(int, int, double *, double *); int main() { double *x, *y, *z; int i1, m, n; scanf("%d %d", &m, &n); // 多項式の次数とデータの数 x = new double [n]; y = new double [n]; for (i1 = 0; i1 < n; i1++) // データ scanf("%lf %lf", &x[i1], &y[i1]); z = least(m, n, x, y); if (z != NULL) { printf("結果\n"); for (i1 = 0; i1 < m+1; i1++) printf(" %d 次の係数 %f\n", m-i1, z[i1]); delete [] z; } else printf("***error 逆行列を求めることができませんでした\n"); delete [] x; delete [] y; return 0; } /******************************************/ /* 最初2乗法 */ /* m : 多項式の次数 */ /* n : データの数 */ /* x,y : データ */ /* return : 多項式の係数(高次から) */ /* エラーの場合はNULLを返す */ /******************************************/ double *least(int m, int n, double *x, double *y) { double **A, **w, *z, x1, x2; int i1, i2, i3, sw; m++; z = new double [m]; w = new double * [m]; for (i1 = 0; i1 < m; i1++) w[i1] = new double [m+1]; A = new double * [n]; for (i1 = 0; i1 < n; i1++) { A[i1] = new double [m]; A[i1][m-2] = x[i1]; A[i1][m-1] = 1.0; x1 = A[i1][m-2]; x2 = x1; for (i2 = m-3; i2 >= 0; i2--) { x2 *= x1; A[i1][i2] = x2; } } for (i1 = 0; i1 < m; i1++) { for (i2 = 0; i2 < m; i2++) { w[i1][i2] = 0.0; for (i3 = 0; i3 < n; i3++) w[i1][i2] += A[i3][i1] * A[i3][i2]; } } for (i1 = 0; i1 < m; i1++) { w[i1][m] = 0.0; for (i2 = 0; i2 < n; i2++) w[i1][m] += A[i2][i1] * y[i2]; } sw = gauss(w, m, 1, 1.0e-10); if (sw == 0) { for (i1 = 0; i1 < m; i1++) z[i1] = w[i1][m]; } else z = NULL; for (i1 = 0; i1 < n; i1++) delete [] A[i1]; for (i1 = 0; i1 < m; i1++) delete [] w[i1]; delete [] A; delete [] w; return z; } /*******************************************************/ /* 線形連立方程式を解く(逆行列を求める) */ /* w : 方程式の左辺及び右辺 */ /* n : 方程式の数 */ /* m : 方程式の右辺の列の数 */ /* eps : 正則性を判定する規準 */ /* return : =0 : 正常 */ /* =1 : 逆行列が存在しない */ /*******************************************************/ int gauss(double **w, int n, int m, double eps) { double y1, y2; int ind = 0, nm, m1, m2, i1, i2, i3; nm = n + m; for (i1 = 0; i1 < n && ind == 0; i1++) { y1 = .0; m1 = i1 + 1; m2 = 0; for (i2 = i1; i2 < n; i2++) { y2 = fabs(w[i2][i1]); if (y1 < y2) { y1 = y2; m2 = i2; } } if (y1 < eps) ind = 1; else { for (i2 = i1; i2 < nm; i2++) { y1 = w[i1][i2]; w[i1][i2] = w[m2][i2]; w[m2][i2] = y1; } y1 = 1.0 / w[i1][i1]; for (i2 = m1; i2 < nm; i2++) w[i1][i2] *= y1; for (i2 = 0; i2 < n; i2++) { if (i2 != i1) { for (i3 = m1; i3 < nm; i3++) w[i2][i3] -= w[i2][i1] * w[i1][i3]; } } } } return(ind); } -----------データ例1(コメント部分を除いて下さい)--------- 1 10 // 多項式の次数とデータの数 0 2.450 // 以下,(x, y) 1 2.615 2 3.276 3 3.294 4 3.778 5 4.009 6 3.920 7 4.267 8 4.805 9 5.656 -------------------------データ例2------------------------- 2 6 10 28.2 15 47.0 20 44.4 26 32.8 32 20.8 40 0.8