<?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
*/
?>