<?php /****************************/ /* 最小二乗法(多項式近似) */ /* coded by Y.Suganuma */ /****************************/ fscanf(STDIN, "%d %d", $m, $n); // 多項式の次数とデータの数 $x = array($n); $y = array($n); for ($i1 = 0; $i1 < $n; $i1++) // データ fscanf(STDIN, "%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]); } else printf("***error 逆行列を求めることができませんでした\n"); /******************************************/ /* 最初2乗法 */ /* m : 多項式の次数 */ /* n : データの数 */ /* x,y : データ */ /* return : 多項式の係数(高次から) */ /* エラーの場合はNULLを返す */ /******************************************/ function least($m, $n, $x, $y) { $m++; $z = array($m); $w = array($m); for ($i1 = 0; $i1 < $m; $i1++) $w[$i1] = array($m+1); $A = array($n); for ($i1 = 0; $i1 < $n; $i1++) { $A[$i1] = array($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; return $z; } /*******************************************************/ /* 線形連立方程式を解く(逆行列を求める) */ /* w : 方程式の左辺及び右辺 */ /* n : 方程式の数 */ /* m : 方程式の右辺の列の数 */ /* eps : 正則性を判定する規準 */ /* return : =0 : 正常 */ /* =1 : 逆行列が存在しない */ /*******************************************************/ function gauss(&$w, $n, $m, $eps) { $ind = 0; $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 = 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 */ ?>