/********************************************/
/* 行列の固有値(フレーム法+ベアストウ法) */
/* coded by Y.Suganuma */
/********************************************/
#include <stdio.h>
int Bairstow(int, int, double, double, double,
double *, double *, double *, double *, double *);
int Frame(int, int, double, double, double, double *, double *, double *,
double *, double *, double **, double **, double **);
int main()
{
double **A, **H1, **H2, *a, *b, *c, *rl, *im, p0, q0, eps;
int i1, ind, ct, n;
// データの設定
ct = 1000;
eps = 1.0e-10;
p0 = 0.0;
q0 = 0.0;
n = 3;
a = new double [n+1];
b = new double [n+1];
c = new double [n+1];
rl = new double [n];
im = new double [n];
A = new double * [n];
H1 = new double * [n];
H2 = new double * [n];
for (i1 = 0; i1 < n; i1++) {
A[i1] = new double [n];
H1[i1] = new double [n];
H2[i1] = new double [n];
}
A[0][0] = 7.0;
A[0][1] = 2.0;
A[0][2] = 1.0;
A[1][0] = 2.0;
A[1][1] = 1.0;
A[1][2] = -4.0;
A[2][0] = 1.0;
A[2][1] = -4.0;
A[2][2] = 2.0;
// 計算
ind = Frame(n, ct, eps, p0, q0, a, b, c, rl, im, A, H1, H2);
// 出力
if (ind > 0)
printf("収束しませんでした!\n");
else {
for (i1 = 0; i1 < n; i1++)
printf(" %f i %f\n", rl[i1], im[i1]);
}
delete [] a;
delete [] b;
delete [] c;
delete [] rl;
delete [] im;
for (i1 = 0; i1 < n; i1++) {
delete [] A[i1];
delete [] H1[i1];
delete [] H2[i1];
}
delete [] A;
delete [] H1;
delete [] H2;
return 0;
}
/*************************************************/
/* 行列の固有値(フレーム法+ベアストウ法) */
/* n : 次数 */
/* ct : 最大繰り返し回数 */
/* eps : 収束判定条件 */
/* p0, q0 : x2+px+qにおけるp,qの初期値 */
/* a : 係数(最高次から与え,値は変化する) */
/* b, c : 作業域((n+1)次の配列) */
/* rl, im : 結果の実部と虚部 */
/* A : 行列 */
/* H1, H2 : 作業域(nxnの行列) */
/* return : =0 : 正常 */
/* =1 : 収束せず */
/* coded by Y.Suganuma */
/*************************************************/
int Frame(int n, int ct, double eps, double p0, double q0, double *a, double *b,
double *c, double *rl, double *im, double **A, double **H1, double **H2)
{
int i1, i2, i3, i4, ind;
a[0] = 1.0;
// a1の計算
a[1] = 0.0;
for (i1 = 0; i1 < n; i1++)
a[1] -= A[i1][i1];
// a2の計算
for (i1 = 0; i1 < n; i1++) {
for (i2 = 0; i2 < n; i2++)
H1[i1][i2] = A[i1][i2];
H1[i1][i1] += a[1];
}
a[2] = 0.0;
for (i1 = 0; i1 < n; i1++) {
for (i2 = 0; i2 < n; i2++)
a[2] -= A[i1][i2] * H1[i2][i1];
}
a[2] *= 0.5;
// a3からanの計算
for (i1 = 3; i1 <= n; i1++) {
for (i2 = 0; i2 < n; i2++) {
for (i3 = 0; i3 < n; i3++) {
H2[i2][i3] = 0.0;
for (i4 = 0; i4 < n; i4++)
H2[i2][i3] += A[i2][i4] * H1[i4][i3];
}
H2[i2][i2] += a[i1-1];
}
a[i1] = 0.0;
for (i2 = 0; i2 < n; i2++) {
for (i3 = 0; i3 < n; i3++)
a[i1] -= A[i2][i3] * H2[i3][i2];
}
a[i1] /= i1;
for (i2 = 0; i2 < n; i2++) {
for (i3 = 0; i3 < n; i3++)
H1[i2][i3] = H2[i2][i3];
}
}
// ベアストウ法
ind = Bairstow(n, ct, eps, p0, q0, a, b, c, rl, im);
return ind;
}
/*************************************************/
/* 実係数代数方程式の解(ベアストウ法) */
/* n : 次数 */
/* ct : 最大繰り返し回数 */
/* eps : 収束判定条件 */
/* p0, q0 : x2+px+qにおけるp,qの初期値 */
/* a : 係数(最高次から与え,値は変化する) */
/* b, c : 作業域((n+1)次の配列) */
/* rl, im : 結果の実部と虚部 */
/* return : =0 : 正常 */
/* =1 : 収束せず */
/* coded by Y.Suganuma */
/*************************************************/
#include <math.h>
int Bairstow(int n, int ct, double eps, double p0, double q0,
double *a, double *b, double *c, double *rl, double *im)
{
double D, dp, dq, p1 = p0, p2 = 0.0, q1 = q0, q2 = 0.0;
int i1, ind = 0, count = 0;
/*
1次の場合
*/
if (n == 1) {
if (fabs(a[0]) < eps)
ind = 1;
else {
rl[0] = -a[1] / a[0];
im[0] = 0.0;
}
}
/*
2次の場合
*/
else if (n == 2) {
// 1次式
if (fabs(a[0]) < eps) {
if (fabs(a[1]) < eps)
ind = 1;
else {
rl[0] = -a[2] / a[1];
im[0] = 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[0] = -a[1] / a[0];
rl[1] = -a[1] / a[0];
im[0] = D / a[0];
im[1] = -im[0];
}
else { // 実数
D = sqrt(D);
a[0] = 1.0 / (2.0 * a[0]);
rl[0] = a[0] * (-a[1] + D);
rl[1] = a[0] * (-a[1] - D);
im[0] = 0.0;
im[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 (fabs(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 (fabs(dp) < eps && fabs(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[0] = -0.5 * p2;
rl[1] = -0.5 * p2;
im[0] = 0.5 * D;
im[1] = -im[0];
}
else { // 実数
D = sqrt(D);
rl[0] = 0.5 * (-p2 + D);
rl[1] = 0.5 * (-p2 - D);
im[0] = 0.0;
im[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[2], &im[2]);
}
}
return ind;
}