- ベストアンサー
C言語への翻訳お願いします
以下の文はある本から抜粋してきたガウス・ジョルダン法のサブルーチンです。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 どうかよろしくお願いします。
- みんなの回答 (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)といった関数がありますが、これは可変長配列(必要な分だけ勝手に長さが変わる配列)を作る関数だと思います(たぶん本のどこかにソースが載っているはず)。
その他の回答 (3)
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と全く同じ扱いになる配列は作れるんですけどね。 では。
- nikorin
- ベストアンサー率24% (47/191)
「Numerical Recipes in C」という本があります。参考になると思います。
- 参考URL:
- http://www.nr.com/
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言語の初心者だったら、これは理解できないと思います。最低限ポインタの概念を理解していないと…