我有这个'简化'的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时在列中迭代。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top