Fortran 数组到 C 数组。 想要愚蠢的宏观技巧

发布于 2024-07-07 08:26:46 字数 371 浏览 4 评论 0原文

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

你有什么建议吗?

I have this 'simplified' fortran code

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

One of the programming gurus warned me, that fortran accesses data efficiently in column order, while c accesses data efficiently in row order. He suggested that I take a good hard look at the code, and be prepared to switch loops around to maintain the speed of the old program.

Being the lazy programmer that I am, and recognizing the days of effort involved, and the mistakes I am likely to make, I started wondering if there might a #define technique that would let me convert this code safely, and easily.

Do you have any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

残疾 2024-07-14 08:26:46

在 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);

您按顺序遍历内存,并假装 ab 实际上是按列主顺序排列的。 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]

会更好。

In C, multi-dimensional arrays work like this:

#define array_length(a) (sizeof(a)/sizeof((a)[0]))
float a[100][200];
a[x][y] == ((float *)a)[array_length(a[0])*x + y];

In other words, they're really flat arrays and [][] is just syntactic sugar.

Suppose you do this:

#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);

You're walking sequentially through memory, and pretending that a and b are actually laid out in column-major order. It's kind of horrible in that a[x][y] != at(a, x, y) != a[y][x], but as long as you remember that it's tricked out like this, you'll be fine.

Edit

Man, I feel dumb. The intention of this definition is to make at(a, x, y) == at[y][x], and it does. So the much simpler and easier to understand

#define at(a, i, j) (a)[j][i]

would be better that what I suggested above.

烂人 2024-07-14 08:26:46

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

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

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

Are you sure your FORTRAN guys did things right?

The code snippet you originally posted is already accessing the arrays in row-major order (which is 'inefficient' for FORTRAN, 'efficient' for C).

As illustrated by the snippet of code and as mentioned in your question, getting this 'correct' can be error prone. Worry about getting the FORTRAN code ported to C first without worrying about details like this. When the port is working - then you can worry about changing column-order accesses to row-order accesses (if it even really matters after the port is working).

也只是曾经 2024-07-14 08:26:46

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

One of my first programming jobs out of college was to fix a long-running C app that had been ported from FORTRAN. The arrays were much larger than yours and it was taking something around 27 hours per run. After fixing it, they ran in about 2.5 hours... pretty sweet!

(OK, it really wasn't assigned, but I was curious and found a big problem with their code. Some of the old timers didn't like me much despite this fix.)

It would seem that the same issue is found here.

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

Your looping (to be good FORTRAN) would be:

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

Otherwise you are marching through the arrays in row-major, which could be highly inefficient.

At least I believe that's how it would be in FORTRAN - it's been a long time.


Saw you updated the code...

Now, you'd want to swap the loop control variables so that you iterate on the rows and then inside that iterate on the columns if you are converting to C.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文