fork(1) download
  1. #include <stdio.h>
  2. #include <math.h>
  3.  
  4. #define N 4
  5. #define EPS 1e-6
  6. #define MAX_ITER 100
  7.  
  8. // 行列2の定義
  9. double A[N][N] = {
  10. {2.0, 1.0, 2.0, 5.0},
  11. {3.0, -3.0, 1.0, 6.0},
  12. {0.0, 1.0, 2.0, 7.0},
  13. {1.0, 1.0, 3.0, 1.0}
  14. };
  15.  
  16. // LU分解を行う関数: (A - lambda_hat * I) = L * U
  17. void lu_decomposition(double B[N][N], double L[N][N], double U[N][N]) {
  18. for (int i = 0; i < N; i++) {
  19. for (int j = 0; j < N; j++) {
  20. L[i][j] = (i == j) ? 1.0 : 0.0;
  21. U[i][j] = 0.0;
  22. }
  23. }
  24.  
  25. for (int i = 0; i < N; i++) {
  26. for (int j = i; j < N; j++) {
  27. double sum = 0.0;
  28. for (int k = 0; k < i; k++) sum += L[i][k] * U[k][j];
  29. U[i][j] = B[i][j] - sum;
  30. }
  31. for (int j = i + 1; j < N; j++) {
  32. double sum = 0.0;
  33. for (int k = 0; k < i; k++) sum += L[j][k] * U[k][i];
  34. L[j][i] = (B[j][i] - sum) / U[i][i];
  35. }
  36. }
  37. }
  38.  
  39. // 前進代入: L * y = x
  40. void forward_substitution(double L[N][N], double x[N], double y[N]) {
  41. for (int i = 0; i < N; i++) {
  42. double sum = 0.0;
  43. for (int j = 0; j < i; j++) sum += L[i][j] * y[j];
  44. y[i] = x[i] - sum;
  45. }
  46. }
  47.  
  48. // 後退代入: U * x_next = y
  49. void backward_substitution(double U[N][N], double y[N], double x[N]) {
  50. for (int i = N - 1; i >= 0; i--) {
  51. double sum = 0.0;
  52. for (int j = i + 1; j < N; j++) sum += U[i][j] * x[j];
  53. x[i] = (y[i] - sum) / U[i][i];
  54. }
  55. }
  56.  
  57. // 逆反復法の実行
  58. void find_remaining_eigen(double lambda_hat) {
  59. double B[N][N], L[N][N], U[N][N];
  60. double y[N], x_next[N];
  61.  
  62. // 初期ベクトル x0 = [1, 1, 1, 1]^T
  63. double x[N] = {1.0, 1.0, 1.0, 1.0};
  64.  
  65. // シフトした行列 B = A - lambda_hat * I の構成
  66. for (int i = 0; i < N; i++) {
  67. for (int j = 0; j < N; j++) {
  68. B[i][j] = A[i][j] - (i == j ? lambda_hat : 0.0);
  69. }
  70. }
  71.  
  72. // LU分解(ループの外で1回のみ実行)
  73. lu_decomposition(B, L, U);
  74.  
  75. printf("\n==================================================================\n");
  76. printf(" 行列2 に対する逆反復法を実行中 (近似固有値 lambda_hat = %.3f)\n", lambda_hat);
  77. printf("==================================================================\n");
  78.  
  79. int iter = 0;
  80. double diff;
  81. double lambda = 0.0;
  82.  
  83. do {
  84. // 1. 前進代入により L * y = x^(k) を解く
  85. forward_substitution(L, x, y);
  86.  
  87. // 2. 後退代入により U * x^(k+1) = y を解く
  88. backward_substitution(U, y, x_next);
  89.  
  90. // 規格化因子の探索 (絶対値が最大の要素)
  91. double max_val = 0.0;
  92. for (int i = 0; i < N; i++) {
  93. if (fabs(x_next[i]) > fabs(max_val)) {
  94. max_val = x_next[i];
  95. }
  96. }
  97.  
  98. // ベクトル要素の規格化
  99. for (int i = 0; i < N; i++) {
  100. x_next[i] /= max_val;
  101. }
  102.  
  103. // 収束判定のためのベクトル要素の絶対変化量の計算
  104. diff = 0.0;
  105. for (int i = 0; i < N; i++) {
  106. diff += fabs(x_next[i] - x[i]);
  107. }
  108.  
  109. // 既存の作業ベクトル x の更新
  110. for (int i = 0; i < N; i++) {
  111. x[i] = x_next[i];
  112. }
  113.  
  114. // 現在のステップにおける固有値の計算: lambda = lambda_hat + 1 / max_val
  115. lambda = lambda_hat + (1.0 / max_val);
  116.  
  117. // 収束状況の出力レイアウト
  118. printf("反復 %2d: x = [%.4f, %.4f, %.4f, %.4f], 固有値 = %.6f\n",
  119. iter + 1, x[0], x[1], x[2], x[3], lambda);
  120.  
  121. iter++;
  122. } while (diff > EPS && iter < MAX_ITER);
  123.  
  124. // 最終結果出力ブロック
  125. printf("\n 計算結果:\n");
  126. printf(" 収束固有値 (lambda) = %10.6f\n", lambda);
  127. printf(" 収束固有ベクトル (x) = [%.4f, %.4f, %.4f, %.4f]\n", x[0], x[1], x[2], x[3]);
  128. printf("==================================================================\n");
  129.  
  130. // 固有値・固有ベクトルであることの確認(残差チェック)
  131. printf("\n 固有対の検証チェック (A*x - lambda*x):\n");
  132. for (int i = 0; i < N; i++) {
  133. double ax_i = 0.0;
  134. for (int j = 0; j < N; j++) {
  135. ax_i += A[i][j] * x[j];
  136. }
  137. double lx_i = lambda * x[i];
  138. printf(" 第%d行: A*x = %10.6f, lambda*x = %10.6f, 残差絶対値 = %e\n",
  139. i + 1, ax_i, lx_i, fabs(ax_i - lx_i));
  140. }
  141. printf("==================================================================\n");
  142. }
  143.  
  144. int main() {
  145. printf("=== 行列2: 実数シフトによる残りの固有値スペックトルの探索 ===\n");
  146.  
  147. // 近似固有値の設定(課題9で求めた主固有値 7.817 を避ける初期推測値)
  148. find_remaining_eigen(-5.0); // 負の大きな固有値領域
  149. find_remaining_eigen(-2.0); // 負の中間固有値領域
  150. find_remaining_eigen(1.5); // 正の内部固有値領域
  151.  
  152. return 0;
  153. }
Success #stdin #stdout 0s 5320KB
stdin
Standard input is empty
stdout
=== 行列2: 実数シフトによる残りの固有値スペックトルの探索 ===

==================================================================
 行列2 に対する逆反復法を実行中 (近似固有値 lambda_hat = -5.000)
==================================================================
反復  1: x = [0.1304, -0.6957, -0.2174, 1.0000], 固有値 = -0.217391
反復  2: x = [0.0335, 1.0000, 0.2098, -0.3408], 固有値 = -5.381829
反復  3: x = [0.0130, 1.0000, 0.1468, -0.2732], 固有値 = -4.453684
反復  4: x = [0.0066, 1.0000, 0.1288, -0.2592], 固有値 = -4.406512
反復  5: x = [0.0049, 1.0000, 0.1238, -0.2555], 固有値 = -4.394737
反復  6: x = [0.0044, 1.0000, 0.1224, -0.2545], 固有値 = -4.391544
反復  7: x = [0.0043, 1.0000, 0.1220, -0.2542], 固有値 = -4.390666
反復  8: x = [0.0042, 1.0000, 0.1219, -0.2542], 固有値 = -4.390424
反復  9: x = [0.0042, 1.0000, 0.1219, -0.2542], 固有値 = -4.390358
反復 10: x = [0.0042, 1.0000, 0.1219, -0.2541], 固有値 = -4.390339
反復 11: x = [0.0042, 1.0000, 0.1219, -0.2541], 固有値 = -4.390334
反復 12: x = [0.0042, 1.0000, 0.1219, -0.2541], 固有値 = -4.390333
反復 13: x = [0.0042, 1.0000, 0.1219, -0.2541], 固有値 = -4.390333

 計算結果:
 収束固有値 (lambda)   =  -4.390333
 収束固有ベクトル (x)  = [0.0042, 1.0000, 0.1219, -0.2541]
==================================================================

 固有対の検証チェック (A*x - lambda*x):
 第1行: A*x =  -0.018493, lambda*x =  -0.018493, 残差絶対値 = 3.370022e-08
 第2行: A*x =  -4.390333, lambda*x =  -4.390333, 残差絶対値 = 0.000000e+00
 第3行: A*x =  -0.535209, lambda*x =  -0.535209, 残差絶対値 = 1.000340e-07
 第4行: A*x =   1.115785, lambda*x =   1.115785, 残差絶対値 = 7.247127e-08
==================================================================

==================================================================
 行列2 に対する逆反復法を実行中 (近似固有値 lambda_hat = -2.000)
==================================================================
反復  1: x = [0.4286, -0.7857, 1.0000, -0.1429], 固有値 = 0.214286
反復  2: x = [-0.2471, 1.0000, -0.5765, 0.2908], 固有値 = -1.270588
反復  3: x = [-0.2272, 1.0000, -0.5825, 0.2519], 固有値 = -2.752458
反復  4: x = [-0.2300, 1.0000, -0.5689, 0.2469], 固有値 = -2.777532
反復  5: x = [-0.2272, 1.0000, -0.5663, 0.2443], 固有値 = -2.782267
反復  6: x = [-0.2273, 1.0000, -0.5651, 0.2436], 固有値 = -2.785448
反復  7: x = [-0.2271, 1.0000, -0.5648, 0.2433], 固有値 = -2.786043
反復  8: x = [-0.2271, 1.0000, -0.5647, 0.2433], 固有値 = -2.786349
反復  9: x = [-0.2271, 1.0000, -0.5647, 0.2432], 固有値 = -2.786424
反復 10: x = [-0.2271, 1.0000, -0.5646, 0.2432], 固有値 = -2.786454
反復 11: x = [-0.2271, 1.0000, -0.5646, 0.2432], 固有値 = -2.786463
反復 12: x = [-0.2271, 1.0000, -0.5646, 0.2432], 固有値 = -2.786466
反復 13: x = [-0.2271, 1.0000, -0.5646, 0.2432], 固有値 = -2.786467

 計算結果:
 収束固有値 (lambda)   =  -2.786467
 収束固有ベクトル (x)  = [-0.2271, 1.0000, -0.5646, 0.2432]
==================================================================

 固有対の検証チェック (A*x - lambda*x):
 第1行: A*x =   0.632735, lambda*x =   0.632735, 残差絶対値 = 1.267989e-07
 第2行: A*x =  -2.786467, lambda*x =  -2.786467, 残差絶対値 = 0.000000e+00
 第3行: A*x =   1.573349, lambda*x =   1.573349, 残差絶対値 = 3.343676e-07
 第4行: A*x =  -0.677760, lambda*x =  -0.677759, 残差絶対値 = 2.459525e-07
==================================================================

==================================================================
 行列2 に対する逆反復法を実行中 (近似固有値 lambda_hat = 1.500)
==================================================================
反復  1: x = [1.0000, 0.5127, -0.2800, 0.0400], 固有値 = 2.152727
反復  2: x = [1.0000, 0.5281, -0.5169, -0.0319], 固有値 = 1.334764
反復  3: x = [1.0000, 0.5306, -0.5135, -0.0288], 固有値 = 1.359754
反復  4: x = [1.0000, 0.5307, -0.5137, -0.0288], 固有値 = 1.359320
反復  5: x = [1.0000, 0.5307, -0.5137, -0.0288], 固有値 = 1.359333
反復  6: x = [1.0000, 0.5307, -0.5137, -0.0288], 固有値 = 1.359333

 計算結果:
 収束固有値 (lambda)   =   1.359333
 収束固有ベクトル (x)  = [1.0000, 0.5307, -0.5137, -0.0288]
==================================================================

 固有対の検証チェック (A*x - lambda*x):
 第1行: A*x =   1.359333, lambda*x =   1.359333, 残差絶対値 = 0.000000e+00
 第2行: A*x =   0.721403, lambda*x =   0.721403, 残差絶対値 = 1.044082e-08
 第3行: A*x =  -0.698268, lambda*x =  -0.698268, 残差絶対値 = 1.577842e-08
 第4行: A*x =  -0.039149, lambda*x =  -0.039149, 残差絶対値 = 6.677112e-10
==================================================================