C言語関係掲示板

過去ログ

No.88.複素行列の行列式を求めるプログラム


はじめまして
独学でC言語について勉強しています。
いま複素行列 det(sI-A0-A1*exp(-s*h))
の行列式を求めるプログラムをかんがえているのですが、
うまくプログラムすることができません
なにかアドバイスをしてもらえたらうれしいのですが
おねがいします。

一般の行列式を求めるプログラムだけでも知りたいです
誰か親切な方お願いします


ゆみさん今晩は。

>いま複素行列 det(sI-A0-A1*exp(-s*h))
>の行列式を求めるプログラムをかんがえているのですが、
>うまくプログラムすることができません

実は複素行列が何だかわかりません。すみません。
単なる複素数の和差積商を求めるプログラムはここにあります。
http://www.ma.nma.ne.jp/~daisuki/program/c/rei9.c

>一般の行列式を求めるプログラムだけでも知りたいです

一般の行列式で、2行3列の行列×3行2列の行列を求めるプログラムは
下記のようになります。

#include <stdio.h>
int main(void)
{
        int i,j,k;
        int x[2][3] = { {1,2,3},{4,5,6} };
        int y[3][2] = { {1,2},{3,4},{5,6} };
        int z[2][2] = {0};
        
        /* 2行3列の行列×3行2列の行列 */
        for (i=0; i<2; i++)
                for (j=0; j<2; j++)
                        for (k=0; k<3; k++)
                                z[i][j] += x[i][k] * y[k][j];
        
        /* 行列の表示 */
        for (i=0; i<2; i++) {
                for (j=0; j<2; j++)
                        printf("%3d",z[i][j]);
                printf("\n");
        }
        
        return(0);
}


今晩わ!!
お返事ありがとう
ごめんね
行列式についてもっと詳しくかけばよかったみたいです
でも本当にありがとう
C言語って本当に難しいです


おはようございます。
どうも見当違いの返信をしたようですね。すみません。

>C言語って本当に難しいです

数学の方がずっと難しいです。(^_^;)

kikkさん、サポート感謝しています。


ども。


>一般の行列式を求めるプログラムだけでも知りたいです

とりあえず以下のような感じかと。とりあえず、です。。

typedef float real; /*doubleにしたければどーぞ*/
real Determinant(real mat[][], int n) {
 real det=0;
 if(n>2) {
  for() {
   余因子行列d[][]を求める。
   det+=sign*Determinant(d,n-1); /* signは展開の仕方次第 */
  }
 }
 else
  det=mat[0][0]*mat[1][1]-mat[1][0]*mat[0][1];
 retrun det;
}

メモリ関係がポイントですね。ちょっと工夫しないと容量もCPUもいっぱい必要
になります。

実数のは最近作ったような気が。。と思って探しましたが勘違いだったようで、
逆行列とか固有値はでてきましたが、行列式はありませんでした。残念。


ちなみに。
もし使用している処理系がC/C++コンパイラなら、複素数はC++の複素数クラス
を利用するといいと思います。実数で書いたコードがほとんどそのまま使える
ので(変数宣言周りを変えるだけでいいはず)。
# そういえばたしか複素数はC99で導入されましたね


では。


kikkさんありがとうございます
がんばってみます!!
またわからないことあったら教えて下さい
ホントにありがとう


ども。


>メモリ関係がポイントですね。ちょっと工夫しないと容量もCPUもいっぱい必要
>になります。

とかいいながら、かんじんの、どう工夫するのかを書き忘れた(というかめんど
かった)ので、書いときます。

まず、おさえておくことは以下の2点です。

1. 行列式を求めるだけならば、任意の余因子行列を求める必要はない
2. Cではひとつの行はメモリ上で連続している(a[0][0], a[0][1], ..)
# ちなみにFORTRANでは行と列の配置方法が逆です

1.は具体的には1列目のみで考えます。そうすることによって行が分断される
ことを避けます(なのでN列目でも可)。分断されないということと、2.より
ポインタによってそのままデータを引き渡せる、つまり全要素のコピーが
不要になります。したがってコピー時間とメモリの削減が両方実現できます。
# ポインタでコスト削減に関しては、一般的に使えることですが

コードにすると以下のような感じ。

/* 配列は1オリジンとする */
/* つまりmat[1+N][1+N]とかなっている */
--略--
/* i行1列について余因子行列を求める */
real *d[1+N];
int row,index;
index=1;
for(row=1;row<=n;row++) {
 if (row==i)
  continue;
 d[index++]=mat[row]+1+1; /* 0列目は未使用で、1列目で展開 */
}


あと、簡単なことですが、展開時に注目している要素が0の時は、その要素の
余因子の行列式は求める必要がないので、そのコードを追加すると計算量が
減ります。
# 0が多いと助かるのは計算機でも同じです。。


では。


ども。


いろいろかきましたが、もっと単純な方法がありました。すみません。

ガウスの消去法の前進消去過程を使い上三角行列にしてから、対角成分を
かけるだけでOKです。

以前書いた方法でも求まるには求まりますがコストがぜんぜん違います。
しつれいしました。


では。


丁寧に教えていただいてありがとうございました
なんとかがんばってみます
またわからないことあったら相談に乗ってください!!!
ヾ(@^▽^@)ノ

戻る


「初心者のためのポイント学習C言語」 Last modified:2002.01.11
Copyright(c) 2000-2002 TOMOJI All Rights Reserved