dポイントプレゼントキャンペーン実施中!

以下の文はある本から抜粋してきたガウス・ジョルダン法のサブルーチンです。Cに翻訳してくださいって言ったら怒りますか?(笑

c Gauss-Jordan method
subroutine gj(a,n1,nn,m,epsl,isw)
double precision a,epsl,p,w
dimension a(n1,*)
nplsm=nn+m
do 100 n=1,nn
p=0.0
do 10 i=n,nn
if(p.lt.abs(a(i,n))) then
p=abs(a(i,n))
ip=i
end if
10 continue
if(p.le.epsl) then
isw=1
write(6,*) 'error'
return
end if
do 20 j=n,nplsm
w=a(n,j)
a(n,j)=a(ip,j)
20 a(ip,j)=w
do 30 j=n+1,nplsm
30 a(n,j)=a(n,j)/a(n,n)
do 40 i=1,nn
if(i.ne.n) then
do 45 j=n+1,nplsm
45 a(i,j)=a(i,j)-a(i,n)*a(n,j)
end if
40 continue
100 continue
isw=0
return
end

だいたい自分でもCに書き換えることはできたんですが、次のところがどのように書き換えたらよいのか分かりません。

subroutine gj(a,n1,nn,m,epsl,isw),

dimension a(n1,*),

do 20 j=n,nplsm
w=a(n,j)
a(n,j)=a(ip,j)
20 a(ip,j)=w

どうかよろしくお願いします。

A 回答 (4件)

No.1です。



よく見たら、配列以外はすべてコピー渡しで十分ですね。だから、

void gj(double *a[][], int *n1, int *nn, ...)

void gj(double *a[][], int n1, int nn, ...)
でも問題ありません。(当然、関数内部は少し書き換える)

でも、Gauss-Jordan法のソースなら、たぶん検索エンジンで英語のページとか探せば見つかるんじゃないかな…
と思って探したら、見つかりました。No.2の方がお勧めの本のオンライン版です。ただし英語ですが。

ソースの中にivector(1,n)といった関数がありますが、これは可変長配列(必要な分だけ勝手に長さが変わる配列)を作る関数だと思います(たぶん本のどこかにソースが載っているはず)。

参考URL:http://www.ulib.org/webRoot/Books/Numerical_Reci …
    • good
    • 0

FORTRANの2次元配列と違いCでは可変長の2次元配列をFORTRANのように作ることが出来ません。


つまり、
FOTRANでは、
dimension a(n1,n2)
というサイズを変数n1,n2で指定した変数を宣言できます。しかし、Cではこのような宣言は許されていません。
つまり、
double a[n1][n2];
はエラーになります。

この部分を同等にするには、工夫が必要です。
やり方は2とおりあります。
a[i][j] = xxxx.....;
のように、FORTRANと同じように取り扱いたい場合は、サイズをn1,n2として、

double **a;
int i;

a = (double **) malloc( n1 * sizeof(double *) );
for (i = 0; I < n1; i++)
  a[i] = (double *) malloc( n2 * sizeof(double) );

とします。これによりa[n1][n2]の配列が出来上がります。
これはサブルーチンを呼ぶ側で作り、そして、 (double **) の型で n1, n2とともに渡せばよいわけです。

別の方法は、FORTRANと同様な2次元配列を扱う関数群を作ることです。
しかし、これだと直接a[i][j]のようなアクセスは出来ません。( SetValue(a, i, j, value) みたいに関数呼び出しで値をセットする )

C++であれば、FORTRANと全く同じ扱いになる配列は作れるんですけどね。

では。
    • good
    • 0

「Numerical Recipes in C」という本があります。

参考になると思います。

参考URL:http://www.nr.com/
    • good
    • 0

fortranですか、懐かしい…私もあまり詳しくないので、間違いがあるかもしれません。



>subroutine gj(a,n1,nn,m,epsl,isw),
fortranのsubroutineはなかなかCには直しづらいですね。普通の関数のように記述してありますが、これはすべてポインタ渡しを行うのと等価です。つまり、Cの関数のコピー渡しでは渡された値をいじっても元の値は変化しないのに対して、fortranのsubroutineに渡された変数は、すべてサブルーチンの中から操作可能です。これをC言語では次のように定義します。

void gj(double *a[][], int *n1, int *nn, ...)

として、関数内では

a(i,j)=a(i,j)*2

のようにしていたものを、

*a[i][j] = *a[i][j] * 2;

のようにするはずです(自信なし)。


>dimension a(n1,*)
これは関数を定義する際に記述した(double *a[][]の部分)ので不要。

>do 20 j=n,nplsm
>w=a(n,j)
>a(n,j)=a(ip,j)
>20 a(ip,j)=w
これは以下のようにする。

double w;
int n_ = *n;
int ip_ = *ip;
for(int j=n_; n_<=nplsm; j++){
 w = *a[n_][j];
 *a[n_][j] = *a[*ip_][j];
 *a[ip_][j] = w;
}

でも、これはあまりきれいな方法ではありません。実際には構造体を用いて、
typedef struct {
 double a[NUM_X][NUM_Y]; //適当な数を#defineしておくか、double **a;として後でmallocする
 int n1;
 int nn;
...
}GaussJordan; //もっとマシな名前を付けて

としたものを

void gj(GaussJordan *ga){
 int nn_ = ga->nn;
 for(int n=1; n<=nn_; n++){
  ...
 }
}

のようにします。関数の内部は、上の例で*(アスタリスク)をつけていた変数に、ga->をつけるようにします(アロー演算子)。

もしあなたがC言語の初心者だったら、これは理解できないと思います。最低限ポインタの概念を理解していないと…
    • good
    • 0

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