Из массива Фортрана в массив C.Требуются глупые макро-трюки

StackOverflow https://stackoverflow.com/questions/227627

  •  03-07-2019
  •  | 
  •  

Вопрос

У меня есть этот «упрощенный» код Фортрана

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], но пока вы помните, что все устроено вот так, с вами все будет в порядке.

Редактировать

Чувак, я чувствую себя тупым.Цель этого определения состоит в том, чтобы сделать at(a, x, y) == at[y][x], и это так.Так гораздо проще и понятнее

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

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

Другие советы

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

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

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

Одним из моих первых заданий по программированию вне колледжа было исправление долго работающего приложения на 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top