| 2.3 二元連立非線形方程式(ニュートン法) |
n 元連立非線形方程式は一般に
f1(x1, x2, ..., xn) = 0,
f2(x1, x2, ..., xn) = 0,
... ... ... ... ...
fn(x1, x2, ..., xn) = 0
と書くことができる。これをベクトル表記すると
f (x)
= 0
となる。
このとき、ニュートン法の計算式は
xk+1
= xk
+ u (xk)
= xk
- J (xk)-1
f (xk)
となる。ここに、
J (xk)
はヤコビ行列と呼ばれ、
であり、また、
u (x)
= - J (x)-1
f (x)
である。
2変数の場合は、逆行列が簡単に求められるので

ここに
1: /*
2: newton2.c: 2変数のニュートン法
3: x2+y2=1, y=x3 -> (x,y)=(0.826,0.5636),(-0.826,-0.5636)
4: */
5: #include <stdio.h> // printf, fprintf, fgets, sscanf
6: #include <math.h> // hypot(hypotenuse): 直角三角形の斜辺を求める関数
7:
8: double f1(double x, double y)
9: {
10: return x * x + y * y - 1; // f1(x,y) = x2 + y2 - 1
11: }
12: double f2(double x, double y)
13: {
14: return x * x * x - y; // f2(x,y) = x3 - y
15: }
16:
17: double J11(double x, double y)
18: {
19: return 2 * x; // df1(x,y)/dx = 2x
20: }
21: double J12(double x, double y)
22: {
23: return 2 * y; // df1(x,y)/dy = 2y
24: }
25: double J21(double x, double y)
26: {
27: return 3 * x * x; // df2(x,y)/dx = 3x2
28: }
29: double J22(double x, double y)
30: {
31: return -1; // df2(x,y)/dy = -1
32: }
33:
34: int ucalc(double x, double y, double *ux, double *uy)
35: /*
36: u = -J-1(x)*f(x)
37: */
38: {
39: double det;
40:
41: det = J11(x, y) * J22(x, y) - J12(x, y) * J21(x, y);
42: *ux = -1 / det * (J22(x, y) * f1(x, y) - J12(x, y) * f2(x, y));
43: *uy = 1 / det * (J21(x, y) * f1(x, y) - J11(x, y) * f2(x, y));
44: return 0;
45: }
46:
47: int newton2(double *x, double *y, double eps)
48: {
49: int n=0;
50: double x0, y0, ux, uy, err;
51:
52: printf("# n, x, y, err\n");
53: printf("%4d, % .15e, % .15e\n", n, *x, *y);
54: do {
55: n++;
56: x0 = *x; y0 = *y;
57: ucalc(*x, *y, &ux, &uy);
58: *x += ux; *y += uy; // xk+1 = xk + u(xk)
59: err = hypot(*x - x0, *y - y0);
60: printf("%4d, % .15e, % .15e, % .15e\n", n, *x, *y, err);
61: } while (err >= eps);
62: return 0;
63: }
64: // ------------ Main ------------
65: int main(void)
66: {
67: double x=1, y=0.5, eps = 1e-10;
68: char s[128];
69:
70: fprintf(stderr, "# x0 y0 = "); fgets(s, 128, stdin); sscanf(s, "%lf%lf", &x, &y);
71: newton2(&x, &y, eps);
72: printf("\n# (x y) = (% .15e % .15e)\n", x, y);
74: return 0;
75: }
"# x0 y0 = 1 0.5" と入力したときの実行結果とグラフは