忙しい現代人の腰&肩のお悩み対策!

C言語で反復法の「ヤコビ法」と「ガウス・ザイデル法」、消去法を用いて連立方程式を解くプログラムを作りたい。
また、プログラムは任意の元数に対応できるように作りたい。
分かる方がいましたら、回答よろしくお願いします。

「連立方程式」の質問画像

このQ&Aに関連する最新のQ&A

A 回答 (4件)

#2ですが、反復法(ガウスザイデル・ヤコビ・CG法など)で解く場合、解が1つでもあれば、そこに収束します。

つまり、解けます。
どういうことかというと、連立1次方程式を解く場合、数学的に解が1つしかない場合と、解が無数にある場合があり、そのような方程式であれば解くことができるということです。
解が1つしかない場合とは、中学や高校で学習するような1次方程式のことです。
解が無数にある場合とは、不定方程式となる場合、つまり係数マトリックスのランクが次元数より少なくなる場合です。
もちろん、その中でも解がない場合は反復法でも解けません。
画像の方程式は、解いていないのでわからないですが、多分解が1つしかない場合だと思います。
その場合だと、反復法でも直接法(ガウスの消去・LU分解法など)でもとけます。ただし、反復法で行う場合は、その解の初期値が必ず問題になります。この与え方が悪いと、解が見つからない場合があります。だいたい零ベクトルとして与える場合が多いのではないでしょうか。

また、直接法では解が1つしかない場合についてしか解けません。だから、解が無数にある場合の方程式は解くことができません。
それに対して、反復法ではそのような方程式でも解くことができます。その解に近づいていくはずです。もちろん、直接法で求められる値に対して、少々誤差がででくるとは思います。

その点、反復法のほうが強い方法であるといえます。
    • good
    • 0

プログラムができたとしても、この画像中の連立方程式は反復法では解けないのではないでしょうか。

    • good
    • 0

下のようなフォーマットで



3  //次元数

3 12 27   //係数マトリクス
5 80 405
7 448 5103

27 243 2187   //右辺のベクトル

とか入力ファイルを作って、ファイル入力して解くというのはどうでしょうか?

次元数から、Cであればmallocを、c++であればnewを使って動的にメモリを確保すれば、係数マトリックスや、解ベクトル、右辺のベクトルに入力できて、まず、解く前段階の処理を行うことができます。
(”任意の次元数に対応できる”をこれで満たせると思います)

あとは、ソルバ(解法)ですが、ヤコビ・ガウスザイデル・ガウスの消去などで行うのであれば、全て、同じ入力形式にしてしまうといいと思います。つまり、ソルバを呼び出して、連立方程式を解かせるときに、それぞれの関数(またはクラスの関数)の入力形式が同じであると、文字を少し変えるだけで違うソルバを用いることができるからです。
[そのようにすると、C++でクラスを使うとき、クラス名を変えてしまうだけで、違うソルバで解いたりすることができます]

で、キモのソルバですが、アルゴリズムはもちろん、プログラムはインターネット上に落ちていると思います。しかも、図書館などで数値計算に関する本は、とても数え切れないくらいあります。初心者向けに書かれた本から、上級者向けまでさまざまです。正直、ネットよりも本の方がしっかり書いてると思います。

たとえば、ガウスザイデル法のプログラムでしたら、下のURLにありました。もちろん、動作確認は行っていないので、自分で使えるような形にして、プログラムを作成してください。

参考URL:http://akita-nct.jp/yamamoto/lecture/2007/5E_com …
    • good
    • 0

ちょっと検索すれば、良いサイトが見つかるよ~!



http://homepage3.nifty.com/gakuyu/suti/renritu/h …

後は自分で…。
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qガウス・ザイデル法

次ぎの連立方程式をガウス・ザイデル法に従って解け。

2x1+x2=1
x1+2x2=-1

(1)上式をガウス・ザイデル法で解く場合のX1(K)、x2(K)とx1(K-1)、x2(K-2)の間を関係づける反復の式を書け。
(2)初期値をx1(0)=0、x2(0)=0とし、反復回数K=3までのx1(K)、x2(K)を求めよ。

という問題なんですが、今夏休みという関係などで先生との連絡がつかないので質問できません。
教科書を見ながら似たような例題を参考にしながら自力でやってみてるんですが、やり方がわからないところなどがあるので教えて欲しいんです。お願いします。また他のもっと効率のよい解き方などがあったら教えてください。

まず、つまずいているところなんですが、教科書の例題にならってやってみると、上の式を係数行列
A= 2 1
   1 2

という形にし

行列K1とK2および行列Qを書くとなってるんですが、その行列の変換の方法がわからないので実際の問題に置き換えやることができません。

ちなみに教科書の例題は

10x1+3x2+x3=14
-2x1+5x2+x3=4
2x1+5x2+5x3=8

という方程式が

A= 10 3 1
   -2 5 1
    2 1 5

という行列に直され

K1=   0   0 0
   -0.4   0 0
    0.4 0.2 0

K2=0 0.3 0.1
   0   0 0.2
   0   0   0

Q=1.4
  0.8
  1.6

というようになっているんですが、どのようにこのような形にもっていくのかわからないのです。

質問などでわかりにくい部分など多々あると思いますが、よろしくお願いします。

次ぎの連立方程式をガウス・ザイデル法に従って解け。

2x1+x2=1
x1+2x2=-1

(1)上式をガウス・ザイデル法で解く場合のX1(K)、x2(K)とx1(K-1)、x2(K-2)の間を関係づける反復の式を書け。
(2)初期値をx1(0)=0、x2(0)=0とし、反復回数K=3までのx1(K)、x2(K)を求めよ。

という問題なんですが、今夏休みという関係などで先生との連絡がつかないので質問できません。
教科書を見ながら似たような例題を参考にしながら自力でやっ...続きを読む

Aベストアンサー

ガウスザイデル法は反復して解を求める手法ですね。
行列式に書き直さなくても良いのではと思います。
連立方程式の一つを用いてある変数について解き、その解を別の方程式を解いていきます。
この時、まだ値が求まっていない変数については初期値を代入します。
ご質問の方程式をもう少し一般的に書くと、
a*x1+b*x2=A   (1)
c*x1+d*x2=B   (2)
となります。
(2)式について、まずx2について解くと、
x2(1)=(B-c*x1(0))/d
となります。x2(1)の(1)は1回目という意味です。
x1(0)は適当な初期値を入れます。
あなたの場合は0が指定されているとすれば0を入れます。
x2(1)を(1)式に代入してx1について解くと、
x1(1)=(A-b*x2(1))/a
となります。これを式(2)に入れてx2について解くということを延々と繰り返していき、収束すれば終了します。
実際にやってみると、x2→-1, x1→1となると思います。
5回くらいやってみると良く分かると思いますよ。
行列式を使いたい場合は、逆行列を掛けて一気に解くガウスの消去法の法が良いのではという気がしますが。
参考になれば。

ガウスザイデル法は反復して解を求める手法ですね。
行列式に書き直さなくても良いのではと思います。
連立方程式の一つを用いてある変数について解き、その解を別の方程式を解いていきます。
この時、まだ値が求まっていない変数については初期値を代入します。
ご質問の方程式をもう少し一般的に書くと、
a*x1+b*x2=A   (1)
c*x1+d*x2=B   (2)
となります。
(2)式について、まずx2について解くと、
x2(1)=(B-c*x1(0))/d
となります。x2(1)の(1)は1回目という意味です。
x1(0)は適当な初期値を...続きを読む

Q連立一次方程式を解くプログラム

すこし煩雑な(21×11です)の連立一次方程式を解くプログラムを作りたいのですが
何か良い文献、HPなどは無いでしょうか?
いろいろなものを見ましたが大体縦横が同じ(n次元?)の
計算のヒントみたいなのしか見つけれませんでした。

プログラムはほとんどやったことが無いので、
ソースなどが公表されていてそれをちょっと書き換えれば
目的のものがつくれるというのが理想ですが・・・。

解法はガウスジョルダンとかガウスサイデル
あるいは他にもっとよいものがあればそちらで構いません。

また、連立一次方程式のちゃんとした答え(言い方悪いですね)が求まらない場合、
近似解を算出することになると思うのですが
これはどういった基準で「解」とされるのでしょうか?
計算の反復回数とかでしょうか?

まとまりのない質問ですがよろしくお願いします。
何かあれば補足をお願いします。

Aベストアンサー

連立方程式の解き方にはいろいろ有って、それぞれ長所短所あります。
手元の書籍では
Numerical recipes in C (技術評論社)
に結構詳しく載っています。(別冊で、プログラムの入ったディスクも販売されていたと思います)

ガウスジョルダンももちろん掲載されていますし、変数と式の数が一致しない場合の扱いなども記述されています。
一読の価値はあるかと。

ご質問の式では、係数に0の多い、疎な方程式に思えます。疎な式の場合には、計算量を下げることも可能です
(詳細は、上記書籍に記載されています)

ご参考になれば。

Q数字の入った配列をファイルへ出力。

今、hist[256]というint型の配列に数字が入っているとします。
これを、テキストファイルに出力して、

0
242
5654
232
3123
756



こんな感じで、ファイルに出力したいです。

文字としての出力になるのでhist[256]配列を、int型からchar型に変換しないとダメでしょうか?
また、変換するとしたら、char型だと unsigned char にしても 0~256の値までしか1つの配列に保存できませんよね?
もっと大きい数字も入っているので何とかする方法も教えて下さい。

初歩的な質問で申し訳ありませんが、よろしくお願いします。

Aベストアンサー

fprintf()関数を使えば簡単です。
簡単に言えば、printf()関数のファイル出力版です。
画面ではなく、ファイルに文字列を出力します。

サンプル
------------------------
FILE *fp;
int i;
if((fp = fopen("data.txt", "w")) != NULL){
 for(i = 0; i < 256; i++){
  if(fprintf(fp, "%d\n", hist[i]) < 0){
   //書き込みエラー
   break;
  }
 }
 fclose(fp);
}else{
 //ファイルオープンエラー
}
------------------------

%d で int型の整数を文字として表示、
\n で改行です。printf()関数と同じですね。

#サンプルはインデントに全角スペースを使っています。

-----------------------------------------------------------
>int型からchar型に変換しないとダメでしょうか?
>また、変換するとしたら、char型だと unsigned char にしても 0~256の値までしか1つの配列に保存できませんよね?

ちょっと勘違いしているようなので、説明しますが・・・

C言語の文字列は、文字の配列です。
char型は1文字を表わします。
文字列は、char型の配列になります。

例えば、整数の 123 を文字列で表現する場合、
文字数は3文字で、終端にヌル文字('\0')が入りますので、
4文字の配列になります。

unsigned char c[] = {'1','2','3','\0'};

一つ一つは文字コード(0~255)ですので、char型で問題ありません。

fprintf()関数を使えば簡単です。
簡単に言えば、printf()関数のファイル出力版です。
画面ではなく、ファイルに文字列を出力します。

サンプル
------------------------
FILE *fp;
int i;
if((fp = fopen("data.txt", "w")) != NULL){
 for(i = 0; i < 256; i++){
  if(fprintf(fp, "%d\n", hist[i]) < 0){
   //書き込みエラー
   break;
  }
 }
 fclose(fp);
}else{
 //ファイルオープンエラー
}
------------------------

%d で int型の整数を文字として表示、
\n で...続きを読む

Qガウスの掃き出し法によるC++プログラム

大学で、ガウスーヨルダンの掃き出し法により連立方程式を解き、係数マトリクスの逆行列と解を表示するプログラムを作れ、という課題が出ました。

4s+t+3u+2v=23
s+4t+3u+3v=30
5s+5t+10u+5v=65
4s+4t+2u+6v=42

という問題です。
まったく素人の状態から4時間ほどやったくらいでこの問題が出たので、解き方が全くわからなかったのですが、いろいろなサイトを巡ってこのようなプログラムを作りました。

#include <stdio.h>
#include <float.h>

#define N 4 /* 行列の行数および列数 */

double A[N][N] = { { 4.0,1.0,3.0,2.0}, /* 係数行列 A の定義 */
{1.0,4.0,3.0,3.0},
{5.0,5.0,10.0,5.0},
{4.0,4.0,2.0,6.0}};
double b[N] = {23.0,30.0,65.0,42.0}; /* 定数ベクトル b の定義 */

void Gauss_J( int, double*, double* );

void main( void )
{
int i; /* カウンタ */

printf( "%d元連立一次方程式\n", N );
for( i = 0; i < N ; i++ )
{
printf( "%g s + %g t + %g u + %g v = %g \n",
A[i][0], A[i][1], A[i][2],A[i][3], b[i] );
}
printf("の解は,\n" );
Gauss_J( N, (double *)A, (double *)b ); /* ガウス・ジョルダン法で解く */
printf( "s = %g \n", b[0] );
printf( "t = %g \n", b[1] );
printf( "u = %g \n", b[2] );
printf( "v = %g \n", b[3] );
}

void Gauss_J( int n, double *a, double *b )
{
int p, i, j, l ; /* カウンタ */
double pivot, c ; /* ピボット値 */

for ( p = 0 ; p < n ; p++ ) /* 1行目から n行目まで繰り返す */
{
pivot = a[ p*n + p ]; /* ピボットを取得する */
for ( i = p ; i < n ; i++ ) /* p行目の p列目から n列目まで */
{
a[ p*n + i ] /= pivot; /* 係数行列の p行を pivotで割る */
}
b[ p ] /= pivot; /* 定数ベクトルの p行を pivotで割る */

for ( l = 0 ; l < n ; l++ ) /* 1行目から n行目まで */
{
if ( l != p ) /* p行を除いて */
{
c = a[ l*n + p ]; /* 掃き出す */
for ( j = p ; j < n ; j++ )
{
a[ l*n + j ] -= c * a[ p*n + j ];
}
b[ l ] -= c * b[ p ];
}
}
}
return ;
}

これで行列の解は出るようになったのですが、逆行列が表示されてません。
どうすれば表示されるようになるのでしょうか?

大学で、ガウスーヨルダンの掃き出し法により連立方程式を解き、係数マトリクスの逆行列と解を表示するプログラムを作れ、という課題が出ました。

4s+t+3u+2v=23
s+4t+3u+3v=30
5s+5t+10u+5v=65
4s+4t+2u+6v=42

という問題です。
まったく素人の状態から4時間ほどやったくらいでこの問題が出たので、解き方が全くわからなかったのですが、いろいろなサイトを巡ってこのようなプログラムを作りました。

#include <stdio.h>
#include <float.h>

#define N 4 /* 行列の行数および列数 */

double A[N][N] = { { 4...続きを読む

Aベストアンサー

ガウスの掃き出し方は、与えられた連立方程式を行列を、
[A][x]=[B]
の形にしておいて、A行列からピボットを取り出して割ったり引いたりして、最終的に[a]行列を単位行列(対角要素が1、それ以外が0の行列)に変形していくのですが、同時に同じ操作を[B]ベクトルにも施すと、最後には[B]が答えになっているというものです。

逆行列を求めるときは、[B]ベクトルの代わりに[A]と同じ大きさの単位行列[E]を置いて、[A]を単位行列に変形したのと同じ操作を[E]にも施すと、最後には[E]が逆行列になっています。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング