<?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;
}
?>