質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

3910閲覧

C言語 Linux

uv-

総合スコア26

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2017/01/17 04:54

編集2017/01/17 07:16

以前にも同じ質問をさせていただいたのですが、解決できなかったので再送します。

Gnome端末を使っています。

x1+2x2+3x3=6
3x1+10x2-4x3=-29
-2x1-4x2+x3=9
という連立方程式をGauss-seidel法で求める問題です。

下記のようにプログラミングすると、

ILL CONDITION i=0
Iteration x1 x2 x3
1 1.0000 1.1034 1.7126
2 -0.2241 0.7406 1.2793
3 0.1135 0.8353 1.3964
4 0.0233 0.8098 1.3651
5 0.0475 0.8166 1.3735
6 0.0410 0.8148 1.3713
7 0.0428 0.8153 1.3719
8 0.0423 0.8152 1.3717
9 0.0424 0.8152 1.3717
10 0.0424 0.8152 1.3717
11 0.0424 0.8152 1.3717

となり、x1=1、x=ー2、x3=3が得られません。

また、

3x1+x2+x3=10
x1+5x2+2x3=21
x1+2x2+5x3=30

を同じプログラミングで解こうとすると、

Iteration x1 x2 x3
1 1.0000 0.9524 0.9032
2 0.8144 0.8752 0.9145
3 0.8210 0.8738 0.9144
4 0.8212 0.8738 0.9144
5 0.8212 0.8738 0.9144

のようになり、x1=1、x=2、x3=5が得られません。

“♯include<stdio.h>
♯include<math.h>
♯define eps 1.e-5
int main(void)
{

double a[3][3],b[3],x[3];
double s,w,anorm,xnorm;
int i,j,k,n;
scanf("%d",&n);
for(i=0;i<n;i++){
for(j=0;j<n;j++){
scanf("%lf",&a[i][j]);
}
scanf("%lf",&b[i]);}

for(i=0;i<n;i++){
s=0.0;
for(j=0;j<n;j++){
if(i==j) continue;
s+=fabs(a[i][j]);
}

if(fabs(a[i][i])<=s){
printf("ILL CONDITION i=%d\n",i);
break;
}
}

for(i=0;i<n;i++){
x[i]=0.0;
}

printf("Iteration x1 x2 x3\n");
for(k=1;;k++){
anorm=0.0;
xnorm=0.0;
for(i=0;i<n;i++){
w=b[i];
for(j=0;j<n;j++){
if(j==i) continue;
w -=a[i][j]*x[j];
}

w /=b[i];
anorm+=fabs(x[i]-w);
xnorm+=fabs(w);
x[i]=w;
}

printf("%6d",k);
for(i=0;i<n;i++){
printf(" %.4f",x[i]);
}
printf("\n");
if(anorm/xnorm<eps)
break;
}
return 0;
}

御指摘いただきたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2017/01/17 07:13

コードを載せるときは```で囲み字下げしましょう。
guest

回答3

0

ベストアンサー

なんとなく質問者さんが理解されていないように感じるため、修正したコードの全文を掲載します。

C

1#include<stdio.h> 2#include<stdlib.h> 3#include<math.h> 4#define eps 1.e-5 5int main(void) 6{ 7 double a[3][3],b[3],x[3]; 8 double s,w,anorm,xnorm; 9 int i,j,k,n; 10 scanf("%d", &n); 11 for(i=0; i<n; i++){ 12 for(j=0; j<n; j++){ 13 scanf("%lf", &a[i][j]); 14 } 15 scanf("%lf", &b[i]); 16 } 17 18 for(i=0;i<n;i++){ 19 s=0.0; 20 for(j=0;j<n;j++){ 21 if(i==j) continue; 22 s+=fabs(a[i][j]); 23 } 24 25 if(fabs(a[i][i])<=s){ 26 printf("ILL CONDITION i=%d\n",i); 27 exit(1); 28 } 29 } 30 31 for (i = 0; i < n; i++) { 32 for (j = 0; j < n; j++) { 33 printf("%lfx%d ", a[i][j], j+1); 34 } 35 printf("= %lf\n", b[i]); 36 } 37 38 for(i=0; i < n; i++){ 39 x[i] = 0.0; 40 } 41 42 printf("Iteration x1 x2 x3\n"); 43 for(k=1; ; k++){ 44 anorm = 0.0; 45 xnorm = 0.0; 46 for(i = 0; i < n; i++){ 47 w=b[i]; 48 for(j=0; j<n; j++){ 49 if(j==i) continue; 50 w -= a[i][j]*x[j]; 51 } 52 53// w /= b[i]; // ←ここが間違っている 54 w /= a[i][i]; 55 anorm += fabs(x[i]-w); 56 xnorm += fabs(w); 57 x[i] = w; 58 } 59 60 printf("%6d", k); 61 for(i = 0; i < n; i++){ 62 printf(" %.4f", x[i]); 63 } 64 printf("\n"); 65 if(anorm/xnorm < eps) break; 66 } 67 return 0; 68}

ガウス=ザイデル法の更新式をよく見なおしてください。

なお、ひとつ目の例は、
ILL CONDITION i=0
と出力されているように、ガウス=ザイデル法の収束条件(対角優位)を満たしていないため収束しません。

以上のように修正すれば、2つ目の例は収束します。

sh

1% ./a.out 23 33 1 1 10 41 5 2 21 51 2 5 30 6Iteration x1 x2 x3 7 1 3.3333 3.5333 3.9200 8 2 0.8489 2.4622 4.8453 9 3 0.8975 2.0824 4.9876 10 4 0.9767 2.0096 5.0008 11 5 0.9965 2.0004 5.0005 12 6 0.9997 1.9998 5.0001 13 7 1.0000 1.9999 5.0000 14 8 1.0000 2.0000 5.0000 15

投稿2017/01/17 06:38

編集2017/01/17 07:15
MasashiKimura

総合スコア1150

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

uv-

2017/01/17 06:51

お返事ありがとうございます。 二つ目の例の場合でも、収束はしていますが、得たい解答(x1=1、x=2、x3=5)が得られていないです。どのようにすれば、正答が得られるか教えていただけると嬉しいです。
MasashiKimura

2017/01/17 06:53

修正後 Iteration x1 x2 x3 .... 8 1.0000 2.0000 5.0000 となっていますよ。あっていると思うのですが。
uv-

2017/01/17 07:20

申し訳ございません。 あっていました。 おこがましいですが、再び質問させていただきます。 一つ目の例で収束しないということは、ガウス=ザイデル法では一つ目の例は解けないということなのでしょうか。
MasashiKimura

2017/01/17 07:24

そのままでは解けません。 これを解くために、 Ax=b ではなく、A^T Ax =A^T b を解くテクニックがあるようです。
guest

0

ちょこっとwikiでGauss-seidel法をみただけですがGauss-seidel法のアルゴリズムとコードを見比べておかしいと思える点をコメントします。

  1. 前回の質問で正しいコードを間違ったものに直してます。

w /= a[i][i]が正しいですが、これをw /= b[i]に修正してしまってます。コメントした方は「Gauss-seidel法については知らないがコードをみた感じ間違いではないか?」とおっしゃっているだけですので、その指摘が正しいかどうかは質問者さんご自身で判断すべきだったと思います。

  1. 収束条件

Gauss-seidelで解が収束する充分条件は(必要条件かはわかりません)「係数行列の各行で非対角要素の絶対値の和が対角要素の絶対値よりも小さい場合」とwikiにあります。プログラムコードでもそれをチェックしてはいますが単にメッセージを表示するだけで実行は継続していますね?最初の方程式は1行目がこの条件を満たしていませんので"IL CONDITION"とメッセージが出ます。実行を継続してみるとおっしゃるとおり収束しないように見えます。エラーメッセージを出すだけでプログラムを中断しない論理となっているのはどういう意図でしょう?「充分条件は満たしていなくてもとにかくやってみる」ということならわかりますが・・・当然ながら本当に収束できないケースでは無限ループに陥ってしまいます。収束条件を満たさないケースで処理をあきらめたいなら「収束条件を満たさないことが判明した時点で」returnなりexitで実行を中断すべきでしょう。
なお、収束条件を満たすように式を変形するような配慮をプログラム上でしてやれば解が求まるとは思いますが、そのような論理を入れると最早Gauss-seidel法ではなくGaussの消去法になってしまうのかも知れません。

投稿2017/01/17 07:44

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

インデントを整えたり、コメントを入れて、プログラムをわかりやすくしましょう。
バグが発見しやすくなります。

2番目の連立方程式は、解x1=1、x=2、x3=5が得られました。
1番目の連立方程式は、解がGauss-Seidel 法では発散するようです。

C

1#include<stdio.h> 2#include<math.h> 3 4 5/* 計算誤差の許容値 */ 6#define eps (1.e-5) 7 8 9int main(void) 10{ 11 12 double a[3][3], b[3], x[3]; 13 double s, anorm, xnorm, sum; 14 int i, j, k; 15 int n; /* 連立方程式の大きさ */ 16 double new_x; /* 新しい近似解 */ 17 18 19 /* データ入力 */ 20 21 scanf("%d", &n); 22 23 for (i = 0; i < n; i++) { 24 for (j = 0; j < n; j++) { 25 scanf("%lf", &a[i][j]); 26 } 27 scanf("%lf", &b[i]); 28 } 29 30 31 for (i = 0; i < n; i++) { 32 s = 0.0; 33 34 for (j = 0; j < n; j++) { 35 if (i == j) 36 continue; 37 38 s += fabs(a[i][j]); 39 } 40 41 if (fabs(a[i][i]) <= s) { 42 printf("ILL CONDITION i=%d\n", i); 43 /* この条件のとき、近似解は発散? */ 44 break; 45 } 46 } 47 48 /* 近似解の初期値代入 */ 49 for (i = 0; i < n; i++) { 50 x[i] = 0.0; 51 } 52 53 54 printf("Iteration x1 x2 x3\n"); 55 56 for (k = 1; ; k++) { 57 anorm = 0.0; 58 xnorm = 0.0; 59 60 for (i = 0; i < n; i++) { 61 sum = 0.0; 62 63 for (j = 0; j < n; j++) { 64 if (j == i) 65 continue; 66 67 sum += a[i][j] * x[j]; 68 } 69 70 /* 反復計算後の近似解 */ 71 new_x = 1.0 / a[i][i] * (b[i] - sum); 72 /* 近似解の変化量を加算 */ 73 anorm += fabs(x[i] - new_x); 74 /* 近似解の総和計算 */ 75 xnorm += fabs(new_x); 76 /* 新しい近似解を代入 */ 77 x[i] = new_x; 78 } 79 80 printf("%6d", k); 81 82 for (i = 0; i < n; i++) { 83 printf(" %.4f", x[i]); 84 } 85 86 printf("\n"); 87 88 /* 計算終了条件 */ 89 if (anorm / xnorm < eps) 90 break; 91 } 92 return 0; 93}

投稿2017/01/17 07:40

naomi3

総合スコア1105

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問