Fortran Array到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]
,但只要你记得它被骗了像这样,你会没事的。
修改
男人,我感到愚蠢。这个定义的目的是在(a,x,y)==在[y] [x] 处设置,它确实如此。所以更简单易懂
#define at(a, i, j) (a)[j][i]
会比我上面建议的更好。
其他提示
你确定你的FORTRAN家伙做得对吗?
您最初发布的代码段已经按行主要顺序访问数组(对于FORTRAN来说“低效”,对于C来说是“高效”)。
如代码片段所示,并且正如您的问题所述,获得“正确”代码可能容易出错。担心首先将FORTRAN代码移植到C而不必担心这样的细节。当端口工作时 - 那么您可以担心更改对行顺序访问的列顺序访问(如果在端口工作后它甚至真的很重要)。
我从大学毕业的第一个编程工作之一是修复一个从FORTRAN移植的长期运行的C应用程序。阵列比你的大得多,并且每次运行大约需要27个小时。修好之后,他们跑了大约2.5个小时......非常可爱!
(好吧,它确实没有被分配,但我很好奇并发现他们的代码存在很大问题。尽管有这样的修复,但有些旧计时器并不喜欢我。)
似乎在这里找到了同样的问题。
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时在列中迭代。