<?php /************************************/ /* 代数方程式の解(ベアストウ法) */ /* 例:(x+1)(x-2)(x-3)(x2+x+1) */ /* =x5-3x4-2x3+3x2+7x+6=0 */ /* coded by Y.Suganuma */ /************************************/ // データの設定 $ct = 1000; $eps = 1.0e-10; $p0 = 0.0; $q0 = 0.0; $n = 5; $a = array($n+1); $b = array($n+1); $c = array($n+1); $rl = array($n); $im = array($n); $a[0] = 1.0; $a[1] = -3.0; $a[2] = -2.0; $a[3] = 3.0; $a[4] = 7.0; $a[5] = 6.0; // 計算 $ind = Bairstow($n, $ct, $eps, $p0, $q0, $a, $b, $c, $rl, $im, 0); // 出力 if ($ind > 0) printf("収束しませんでした!\n"); else { for ($i1 = 0; $i1 < $n; $i1++) printf(" %f i %f\n", $rl[$i1], $im[$i1]); } /*************************************************/ /* 実係数代数方程式の解(ベアストウ法) */ /* n : 次数 */ /* ct : 最大繰り返し回数 */ /* eps : 収束判定条件 */ /* p0, q0 : x2+px+qにおけるp,qの初期値 */ /* a : 係数(最高次から与え,値は変化する) */ /* b,c : 作業域((n+1)次の配列) */ /* rl, im : 結果の実部と虚部 */ /* k : 結果を設定する配列の位置 */ /* return : =0 : 正常 */ /* =1 : 収束せず */ /* coded by Y.Suganuma */ /*************************************************/ function Bairstow($n, $ct, $eps, $p0, $q0, $a, $b, $c, &$rl, &$im, $k) { $p1 = $p0; $p2 = 0.0; $q1 = $q0; $q2 = 0.0; $ind = 0; $count = 0; /* 1次の場合 */ if ($n == 1) { if (abs($a[0]) < $eps) $ind = 1; else { $rl[$k] = -$a[1] / $a[0]; $im[$k] = 0.0; } } /* 2次の場合 */ else if ($n == 2) { // 1次式 if (abs($a[0]) < $eps) { if (abs($a[1]) < $eps) $ind = 1; else { $rl[$k] = -$a[2] / $a[1]; $im[$k] = 0.0; } } // 2次式 else { $D = $a[1] * $a[1] - 4.0 * $a[0] * $a[2]; if ($D < 0.0) { // 虚数 $D = sqrt(-$D); $a[0] *= 2.0; $rl[$k] = -$a[1] / $a[0]; $rl[$k+1] = -$a[1] / $a[0]; $im[$k] = $D / $a[0]; $im[$k+1] = -$im[$k]; } else { // 実数 $D = sqrt($D); $a[0] = 1.0 / (2.0 * $a[0]); $rl[$k] = $a[0] * (-$a[1] + $D); $rl[$k+1] = $a[0] * (-$a[1] - $D); $im[$k] = 0.0; $im[$k+1] = 0.0; } } } // 3次以上の場合 else { // 因数分解 $ind = 1; while ($ind > 0 && $count <= $ct) { for ($i1 = 0; $i1 <= $n; $i1++) { if ($i1 == 0) $b[$i1] = $a[$i1]; else if ($i1 == 1) $b[$i1] = $a[$i1] - $p1 * $b[$i1-1]; else $b[$i1] = $a[$i1] - $p1 * $b[$i1-1] - $q1 * $b[$i1-2]; } for ($i1 = 0; $i1 <= $n; $i1++) { if ($i1 == 0) $c[$i1] = $b[$i1]; else if ($i1 == 1) $c[$i1] = $b[$i1] - $p1 * $c[$i1-1]; else $c[$i1] = $b[$i1] - $p1 * $c[$i1-1] - $q1 * $c[$i1-2]; } $D = $c[$n-2] * $c[$n-2] - $c[$n-3] * ($c[$n-1] - $b[$n-1]); if (abs($D) < $eps) return $ind; else { $dp = ($b[$n-1] * $c[$n-2] - $b[$n] * $c[$n-3]) / $D; $dq = ($b[$n] * $c[$n-2] - $b[$n-1] * ($c[$n-1] - $b[$n-1])) / $D; $p2 = $p1 + $dp; $q2 = $q1 + $dq; if (abs($dp) < $eps && abs($dq) < $eps) $ind = 0; else { $count++; $p1 = $p2; $q1 = $q2; } } } if ($ind == 0) { // 2次方程式を解く $D = $p2 * $p2 - 4.0 * $q2; if ($D < 0.0) { // 虚数 $D = sqrt(-$D); $rl[$k] = -0.5 * $p2; $rl[$k+1] = -0.5 * $p2; $im[$k] = 0.5 * $D; $im[$k+1] = -$im[$k]; } else { // 実数 $D = sqrt($D); $rl[$k] = 0.5 * (-$p2 + $D); $rl[$k+1] = 0.5 * (-$p2 - $D); $im[$k] = 0.0; $im[$k+1] = 0.0; } // 残りの方程式を解く $n -= 2; for ($i1 = 0; $i1 <= $n; $i1++) $a[$i1] = $b[$i1]; $ind = Bairstow($n, $ct, $eps, $p0, $q0, $a, $b, $c, $rl, $im, $k+2); } } return $ind; } ?>