Pregunta

Tengo este código fortran 'simplificado'

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

Uno de los gurús de la programación me advirtió que fortran accede a los datos de manera eficiente en el orden de las columnas, mientras que c accede a los datos de manera eficiente en el orden de las filas. Me sugirió que echara un buen vistazo al código y que estuviera preparado para cambiar de bucle para mantener la velocidad del programa anterior.

Siendo el programador perezoso que soy, y reconociendo los días de esfuerzo involucrados y los errores que probablemente cometa, comencé a preguntarme si podría haber una técnica #define que me permita convertir este código de forma segura y fácil.

¿Tienes alguna sugerencia?

¿Fue útil?

Solución

En C, los arreglos multidimensionales funcionan así:

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

En otras palabras, son matrices realmente planas y [] [] es solo azúcar sintáctica.

Supongamos que haces esto:

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

Estás caminando secuencialmente a través de la memoria, y fingiendo que a y b están distribuidos en orden de la columna principal. Es un poco horrible en ese a [x] [y]! = At ??(a, x, y)! = A [y] [x] , pero siempre y cuando recuerdes que está engañado así estarás bien.

Editar

Hombre, me siento tonto. La intención de esta definición es hacer en (a, x, y) == en [y] [x] , y lo hace. Así que el mucho más simple y más fácil de entender

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

sería mejor que lo que sugerí anteriormente.

Otros consejos

¿Estás seguro de que tus chicos de FORTRAN hicieron las cosas bien?

El fragmento de código que originalmente publicaste ya está accediendo a las matrices en orden de fila mayor (que es 'ineficiente' para FORTRAN, 'eficiente' para C).

Como lo ilustra el fragmento de código y como se menciona en su pregunta, obtener este "correcto" puede ser propenso a errores. Preocúpese de que el código FORTRAN se traslade a C primero, sin preocuparse por detalles como este. Cuando el puerto está funcionando, entonces puede preocuparse por cambiar los accesos de orden de columna a los accesos de orden de fila (si es que realmente importa después de que el puerto esté funcionando).

Uno de mis primeros trabajos de programación fuera de la universidad fue arreglar una aplicación C de larga duración que había sido portada desde FORTRAN. Las matrices eran mucho más grandes que las suyas y tomaba algo alrededor de 27 horas por carrera. Después de arreglarlo, corrieron en aproximadamente 2.5 horas ... ¡muy dulce!

(Está bien, realmente no fue asignado, pero tenía curiosidad y encontré un gran problema con su código. A algunos de los antiguos no les gustaba mucho a pesar de esta solución)

Parece que el mismo problema se encuentra aquí.

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

Tu bucle (para que sea bueno FORTRAN) sería:

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

De lo contrario, estás marchando a través de los arreglos en la fila mayor, lo que podría ser altamente ineficiente.

Al menos creo que así sería en FORTRAN, ha pasado mucho tiempo.


Vio que has actualizado el código ...

Ahora, querría intercambiar las variables de control de bucle para iterar en las filas y luego dentro de esa iteración en las columnas si está convirtiendo a C.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top