1 // DK3.C -- DKA 法で代数方程式の根を求める
2 //
3 // 数学科 6701 号室のワークステーション環境でのコンパイル
4 // (グラフィックス・ライブラリィ GLSC を使っているので
5 // 情報科学センターではコンパイルできない。悪しからず。)
6 // g++ -o DK3 DK3.C -I/usr/local/include -lglscd -lX11 -lsocket
7 // あるいは
8 // ccmg+ DK3.C
9 //
10 // Win32 環境下の glscwin でも (若干の修正の下に) 動作させられることが
11 // 分かったので、画面に表示するメッセージを変更しました (2000/10/18)。
12
13 #include <iostream.h>
14 #include <iomanip.h> // setprecision() のため
15 #include <math.h>
16 #include <complex.h> // complex<double> のため
17
18 // GLSC のヘッダーファイルをインクルード
19 extern "C" {
20 #define G_DOUBLE
21 #include <glsc.h>
22 }
23
24 // プロトタイプ宣言
25 complex<double> polynomial(int, complex<double> *, complex<double>);
26 complex<double> bunbo(int, complex<double> *, int);
27
28 // 解きたい代数方程式の次数の最高値
29 #define MAXN 100
30
31 int main()
32 {
33 int i, k, n;
34 complex<double> a[MAXN+1], x[MAXN], newx[MAXN], dx[MAXN];
35 complex<double> g, I(0,1);
36 double r0, R, max, pi;
37
38 // 数学定数 (円周率) の準備
39 pi = 4 * atan(1.0);
40
41 // 表\示の桁数を 16 桁にする
42 cout << setprecision(16);
43
44 // 方程式の入力
45 cout << "次数 n を入力してください (1≦n≦" << MAXN << "): ";
46 cin >> n;
47 if (n > MAXN || n <= 0) {
48 cerr << "次数は" << MAXN << "以下の自然数として下さい。" << endl;
49 exit(0);
50 }
51 for (i = 0; i <= n; i++) {
52 cout << (n-i) << "次の係数を入力してください: ";
53 cin >> a[i];
54 }
55
56 // 多項式を最高次の係数で割って monic にする
57 cout << "monic にします。" << endl;
58 for (i = 1; i <= n; i++)
59 a[i] /= a[0];
60 a[0] = 1;
61 cout << "修正した係数" << endl;
62 for (i = 0; i <= n; i++)
63 cout << "a[" << i << "]=" << a[i] << endl;
64
65 // Aberth の初期値を配置する円の決定
66 g = - a[1] / n;
67 cout << "根の重心" << g << endl;
68 max = 0;
69 for (i = 1; i <= n; i++)
70 if (abs(a[i]) > max)
71 max = abs(a[i]);
72 cout << "max|a_i|=" << max << endl;
73 r0 = abs(g) + 1 + max;
74 cout << "根は重心中心で、半径 r0=" << r0 << "の円盤内にある" << endl;
75
76 cout << "円の半径 (分からなければ上の値を指定してください): ";
77 R = r0;
78 cin >> r0;
79 if (r0 > R)
80 R = r0;
81 cout << "図は根の重心を中心として半径 " << R
82 #ifdef __CYGWIN__
83 << "の円が表\示できるようにします。" << endl;
84 #else
85 << "の円が表示できるようにします。" << endl;
86 #endif
87
88 // Aberth の初期値
89 cout << "初期値" << endl;
90 for (i = 0; i < n; i++) {
91 double theta;
92 theta = 2 * i * pi / n + pi / (2 * n);
93 x[i] = g + r0 * exp(I * theta);
94 cout << x[i] << endl;
95 }
96
97 // グラフィックス・ライブラリィ GLSC の初期化
98 g_init("DKGRAPH", 120.0, 120.0);
99 g_device(G_BOTH);
100 // 座標系の指定
101 g_def_scale(0,
102 real(g) - 1.1 * R, real(g) + 1.1 * R,
103 imag(g) - 1.1 * R, imag(g) + 1.1 * R,
104 10.0, 10.0, 100.0, 100.0);
105 g_sel_scale(0);
106 // 線種、マーカーの指定
107 g_def_line(0, G_BLACK, 0, G_LINE_SOLID);
108 g_sel_line(0);
109 g_def_marker(0, G_RED, 2, G_MARKER_CIRC);
110 g_sel_marker(0);
111
112 // 初期値と初期値を置く円を描く
113 g_circle(real(g), imag(g), r0, G_YES, G_NO);
114 for (i = 0; i < n; i++)
115 g_marker(real(x[i]), imag(x[i]));
116
117 // 反復
118 for (k = 1; k <= 1000; k++) {
119 double error;
120 cout << "第" << k << "反復" << endl;
121 for (i = 0; i < n; i++) {
122 dx[i] = polynomial(n, a, x[i]) / bunbo(n, x, i);
123 newx[i] = x[i] - dx[i];
124 // 図示する
125 g_move(real(x[i]), imag(x[i]));
126 g_plot(real(newx[i]), imag(newx[i]));
127 g_marker(real(newx[i]), imag(newx[i]));
128 }
129 // 更新
130 for (i = 0; i < n; i++) {
131 x[i] = newx[i];
132 cout << x[i] << endl;
133 }
134 // 変化量を計算する (ここは非常に素朴)
135 error = 0.0;
136 for (i = 0; i < n; i++)
137 error += abs(dx[i]);
138 cout << "変化量=" << error << endl;
139 // 変化量が小さければ収束したと判断して反復を終了する。
140 if (error < 1e-12)
141 break;
142 }
143
144 // GLSC 終了の処理
145 cout << "終了には" << endl;
146 cout << " グラフィックスのウィンドウをクリック (X の場合)。" << endl;
147 cout << " グラフィックスのウィンドウをクローズ (Windows の場合)。" << endl;
148 g_sleep(-1.0);
149 g_term();
150
151 return 0;
152 }
153
154 // 多項式の値の計算 (Horner 法)
155 complex<double> polynomial(int n,
156 complex<double> *a,
157 complex<double> z)
158 {
159 int i;
160 complex<double> w;
161 w = a[0];
162 for (i = 1; i <= n; i++)
163 w = (w * z + a[i]);
164 return w;
165 }
166
167 // Π (zi-zj) の計算
168 // j≠i
169 complex<double> bunbo(int n,
170 complex<double> *z,
171 int i)
172 {
173 int j;
174 complex<double> w(1,0);
175 for (j = 0; j < n; j++)
176 if (j != i)
177 w *= (z[i] - z[j]);
178 return w;
179 }