/****************************/ /* 最小二乗法(多項式近似) */ /* coded by Y.Suganuma */ /****************************/ import java.io.*; import java.util.StringTokenizer; public class Test { public static void main(String args[]) throws IOException { double x[], y[], z[]; int i1, m, n, sw; StringTokenizer str; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); // 多項式の次数とデータの数 str = new StringTokenizer(in.readLine(), " "); m = Integer.parseInt(str.nextToken()); n = Integer.parseInt(str.nextToken()); x = new double [n]; y = new double [n]; z = new double [m+1]; // データ for (i1 = 0; i1 < n; i1++) { str = new StringTokenizer(in.readLine(), " "); x[i1] = Double.parseDouble(str.nextToken()); y[i1] = Double.parseDouble(str.nextToken()); } sw = least(m, n, x, y, z); if (sw == 0) { System.out.println("結果"); for (i1 = 0; i1 < m+1; i1++) System.out.println(" " + (m-i1) + " 次の係数 " + z[i1]); } else System.out.println("***error 逆行列を求めることができませんでした"); } /*************************************/ /* 最初2乗法 */ /* m : 多項式の次数 */ /* n : データの数 */ /* x,y : データ */ /* z : 多項式の係数(高次から) */ /* return : =0 : 正常 */ /* =1 : エラー */ /*************************************/ static int least(int m, int n, double x[], double y[], double z[]) { double A[][], w[][], x1, x2; int i1, i2, i3, sw = 0; m++; w = new double [m][m+1]; A = new double [n][m]; for (i1 = 0; i1 < n; i1++) { 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 sw = 1; return sw; } /*******************************************************/ /* 線形連立方程式を解く(逆行列を求める) */ /* w : 方程式の左辺及び右辺 */ /* n : 方程式の数 */ /* m : 方程式の右辺の列の数 */ /* eps : 逆行列の存在を判定する規準 */ /* return : =0 : 正常 */ /* =1 : 逆行列が存在しない */ /*******************************************************/ static 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 = Math.abs(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