Fortran配列からC配列。愚かなマクロのトリックが欲しい
-
03-07-2019 - |
質問
この「簡略化された」Fortranコードを持っています
real B(100, 200)
real A(100,200)
... initialize B array code.
do I = 1, 100
do J = 1, 200
A(J,I) = B(J,I)
end do
end do
Fortranは列順で効率的にデータにアクセスし、cは行順で効率的にデータにアクセスする、とプログラミングの達人の一人が警告しました。彼は、コードをよく見て、古いプログラムの速度を維持するためにループを切り替える準備をすることを提案しました。
私が怠け者のプログラマーであり、努力の日々と間違いそうな間違いを認識して、このコードを安全かつ簡単に変換できる#defineテクニックがあるのではないかと思い始めました。
提案はありますか?
解決
Cでは、多次元配列は次のように機能します。
#define array_length(a) (sizeof(a)/sizeof((a)[0]))
float a[100][200];
a[x][y] == ((float *)a)[array_length(a[0])*x + y];
言い換えれば、それらは本当にフラットな配列であり、 [] []
は単なる構文上の砂糖です。
これを行うとします:
#define at(a, i, j) ((typeof(**(a)) *)a)[(i) + array_length((a)[0])*(j)]
float a[100][200];
float b[100][200];
for (i = 0; i < 100; i++)
for (j = 0; j < 200; j++)
at(a, j, i) = at(b, j, i);
メモリを順番に歩いており、 a
と b
が実際には列優先の順序で配置されているふりをしています。 a [x] [y]!= at(a、x、y)!= a [y] [x]
というのは恐ろしいことですが、だまされていることを覚えている限りこのように、大丈夫です。
編集
男、私は愚かな感じがします。この定義の意図は、 at(a、x、y)== at [y] [x]
にすることであり、そうします。したがって、はるかにシンプルで理解しやすい
#define at(a, i, j) (a)[j][i]
上で提案したものよりも良いでしょう。
他のヒント
あなたのFORTRANのメンバーが正しいことをしましたか?
最初に投稿したコードスニペットは、行優先順で配列にすでにアクセスしています(FORTRANでは「非効率的」、Cでは「効率的」です)。
コードスニペットで示されているように、また質問で述べられているように、この「正しい」取得はエラーを起こしやすい可能性があります。このような詳細を心配することなく、最初にFORTRANコードをCに移植することを心配します。ポートが機能している場合-(ポートが機能している後に本当に問題になる場合でも)列順アクセスを行順アクセスに変更することを心配することができます。
大学を卒業した最初のプログラミングの仕事の1つは、FORTRANから移植された長時間実行されるCアプリを修正することでした。アレイはあなたのものよりもはるかに大きく、実行ごとに約27時間かかりました。それを修正した後、彼らは約2.5時間で走りました...かなり甘い!
(p。 / p>同じ問題がここにあるようです。
real B(100, 200)
real A(100,200)
... initialize B array code.
do I = 1, 100
do J = 1, 200
A(I,J) = B(I,J)
end do
end do
あなたのループは(良いFORTRANに)次のようになります:
real B(100, 200)
real A(100,200)
... initialize B array code.
do J = 1, 200
do I = 1, 100
A(I,J) = B(I,J)
end do
end do
それ以外の場合、行優先で配列を行進しているため、非常に非効率的です。
少なくとも、それがFORTRANでどのようになるかを信じています-それは長い時間でした。
コードを更新しました...
ここで、ループ制御変数を交換して、行を反復処理し、Cに変換する場合は内部で列を反復処理するようにします。