4

我有这个“简化”的 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 技术可以让我安全、轻松地转换这段代码。

你有什么建议吗?

4

3 回答 3

4

您确定您的 FORTRAN 人员做对了吗?

您最初发布的代码片段已经以行优先顺序访问数组(这对于 FORTRAN 来说是“低效的”,对于 C 来说是“高效的”)。

如代码片段所示以及您的问题中提到的那样,获得此“正确”可能容易出错。担心首先将 FORTRAN 代码移植到 C 中,而不用担心这样的细节。当端口工作时 - 然后您可以担心将列顺序访问更改为行顺序访问(如果在端口工作后它甚至真的很重要)。

于 2008-10-22T21:43:48.517 回答
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]

会比我上面建议的更好。

于 2008-10-23T14:23:10.030 回答
2

我大学毕业后的第一份编程工作是修复一个从 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 时在列内迭代。

于 2008-10-22T21:54:53.753 回答