我有这个'简化'的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技术可以让我安全,轻松地转换这些代码。
你有什么建议吗?
答案 0 :(得分:4)
你确定你的FORTRAN家伙做得对吗?
您最初发布的代码段已经按行主要顺序访问数组(对于FORTRAN来说“低效”,对于C来说是“高效”)。
如代码片段所示,并且正如您的问题所述,获得“正确”代码可能容易出错。担心首先将FORTRAN代码移植到C而不必担心这样的细节。当端口工作时 - 那么您可以担心更改对行顺序访问的列顺序访问(如果在端口工作后它甚至真的很重要)。
答案 1 :(得分:4)
在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]
会比我上面建议的更好。
答案 2 :(得分:2)
我从大学毕业的第一个编程工作之一是修复一个从FORTRAN移植的长期运行的C应用程序。阵列比你的大得多,并且每次运行大约需要27个小时。修好之后,他们跑了大约2.5个小时......非常可爱!
(好吧,它确实没有被分配,但我很好奇并发现他们的代码存在很大问题。尽管有这样的修复,但有些旧计时器并不喜欢我。) < / 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时在列中迭代。