Fortran Array для массива C Тупые макрокоманды - PullRequest
4 голосов
/ 23 октября 2008

У меня есть этот «упрощенный» код 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, который позволил бы мне легко и безопасно преобразовать этот код.

У вас есть предложения?

Ответы [ 3 ]

4 голосов
/ 23 октября 2008

В 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]

будет лучше того, что я предложил выше.

4 голосов
/ 23 октября 2008

Вы уверены, что ваши ребята из Фортрана все сделали правильно?

Фрагмент кода, который вы первоначально разместили, уже обращается к массивам в порядке следования строк (который неэффективен для FORTRAN, эффективен для C).

Как показано в фрагменте кода и как уже упоминалось в вашем вопросе, получение этого «правильного» может быть подвержено ошибкам. Беспокоитесь о том, чтобы сначала перенести код FORTRAN на C, не беспокоясь о таких деталях. Когда порт работает - тогда вы можете беспокоиться об изменении доступа к порядку столбцов на доступ к порядку строк (если это действительно имеет значение после работы порта).

2 голосов
/ 23 октября 2008

Одним из моих первых заданий по программированию вне колледжа было исправление долго работающего приложения на C, которое было перенесено с FORTRAN. Массивы были намного больше, чем у вас, и это заняло около 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

Ваш цикл (чтобы быть хорошим Фортраном) будет:

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

В противном случае вы проходите через массивы в мажорной строке, что может быть крайне неэффективным.

По крайней мере, я верю, что так будет на Фортране - это было давно.


увидел, что вы обновили код ...

Теперь вам нужно поменять местами переменные управления циклами, чтобы итерировать по строкам, а затем внутри этой итерации по столбцам, если вы конвертируете в C.

...