Fortran Array to C array. Volevano trucchi macro stupidi
-
03-07-2019 - |
Domanda
Ho questo codice fortran "semplificato"
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 dei guru della programmazione mi ha avvertito che fortran accede ai dati in modo efficiente nell'ordine delle colonne, mentre c accede ai dati in modo efficiente nell'ordine delle righe. Mi ha suggerito di dare una buona occhiata al codice e di essere pronto a cambiare loop per mantenere la velocità del vecchio programma.
Essendo il programmatore pigro che sono, e riconoscendo i giorni di sforzo coinvolti e gli errori che probabilmente farò, ho iniziato a chiedermi se potesse esistere una tecnica #define che mi permetta di convertire questo codice in modo sicuro e facile.
Hai qualche suggerimento?
Soluzione
In C, le matrici multidimensionali funzionano in questo modo:
#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 altre parole, sono matrici davvero piatte e [] []
è solo zucchero sintattico.
Supponi di fare questo:
#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);
Stai camminando in sequenza attraverso la memoria e fingendo che a
e b
siano effettivamente disposti in ordine di colonna maggiore. È un po 'orribile in quel a [x] [y]! = At ??(a, x, y)! = A [y] [x]
, ma finché ricordi che è stato eliminato così, starai bene.
Modifica
Amico, mi sento stupido. L'intenzione di questa definizione è fare in (a, x, y) == at [y] [x]
, e lo fa. Quindi molto più semplice e facile da capire
#define at(a, i, j) (a)[j][i]
sarebbe meglio di quello che ho suggerito sopra.
Altri suggerimenti
Sei sicuro che i tuoi ragazzi FORTRAN abbiano fatto le cose bene?
Lo snippet di codice originariamente pubblicato sta già accedendo alle matrici nell'ordine delle righe principali (che è "inefficiente" per FORTRAN, "efficiente" per C).
Come illustrato dallo snippet di codice e come indicato nella tua domanda, ottenere questo "corretto" può essere soggetto a errori. Preoccupati di portare prima il codice FORTRAN su C senza preoccuparti di dettagli come questo. Quando la porta funziona, allora puoi preoccuparti di modificare gli accessi all'ordine delle colonne agli accessi all'ordine delle righe (se è davvero importante dopo che la porta funziona).
Uno dei miei primi lavori di programmazione fuori dal college è stato quello di riparare un'app C di lunga durata che era stata trasferita da FORTRAN. Gli array erano molto più grandi dei tuoi e impiegavano circa 27 ore a corsa. Dopo averlo riparato, hanno funzionato in circa 2,5 ore ... piuttosto dolce!
(OK, in realtà non è stato assegnato, ma ero curioso e ho riscontrato un grosso problema con il loro codice. Alcuni dei vecchi timer non mi piacevano molto nonostante questa correzione.)
Sembra che lo stesso problema sia stato trovato qui.
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
Il tuo loop (per essere un buon FORTRAN) sarebbe:
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
Altrimenti stai marciando attraverso le matrici in fila maggiore, il che potrebbe essere altamente inefficiente.
Almeno credo che sia così in FORTRAN - è passato molto tempo.
Ti ho visto aggiornato il codice ...
Ora, si desidera scambiare le variabili di controllo del ciclo in modo da iterare sulle righe e quindi all'interno di quelle iterate sulle colonne se si sta convertendo in C.