Tecnicamente's Weblog

Just another WordPress.com weblog

Archivi delle etichette: fortran95

Fortran95, il ciclo “DO” su matrici di grandi dimensioni

Se state usando il Fortran95 i motivi sono semplici, o vi stanno obbligando oppure volete usare un linguaggio di programmazione che non ha eguali nelle applicazioni del calcolo numerico ed in particolar modo nei calcoli dove si fa uso pesante di matrici.

Questo breve articolo ha due scopi:

  1. mostrare che bisogna organizzare le matrici nel modo migliore per permettere ai cicli di lettura di essere molto efficienti;
  2. mostrare le ottimizzazioni intrinseche del linguaggio e del compilatore;

Supponiamo di avere due matrici di grande dimensione la [A] e la [B], il calcolo che si vuole eseguire è c(i,j) = a(i,j) + b(i,j). Voglio trovare la matrice somma [C]=[A]+[B].

Operazione estremamente semplice, supponiamo ancora che decidiamo di usare il linguaggio C e che i dati siano interi, vediamo cosa accade usando il seguente codice:

#include<stdio.h>
#include<time.h>

#define X 10000
#define Y 10000

int main(void){
 int i, j;
 float t0, t1;
 //int a[X][Y], b[X][Y], c[X][Y];
 int **a, **b, **c;

/* allocazione della memoria */
 a = (int **)calloc(X,sizeof(int *));
 b = (int **)calloc(X,sizeof(int *));
 c = (int **)calloc(X,sizeof(int *));

 for(i=0;i<X;i++){
    a[i] = (int *)calloc(Y,sizeof(int));
    b[i] = (int *)calloc(Y,sizeof(int));
    c[i] = (int *)calloc(Y,sizeof(int));
 }

/* inizializzazione delle matrici */
 for(i=0;i<X;i++){
    for(j=0;j<Y;j++){
       a[i][j] = 1;
       b[i][j] = 2;
    }
 }
 
/* somma scorrendo per le colonne */
 t0 = clock();
 for(i=0;i<X;i++){
   for(j=0;j<Y;j++){
     c[i][j] = a[i][j] + b[i][j];
   }
 }
 
 t1 = clock();
 printf("%d\n",c[X-1][Y-1]);
 printf("tempo richiesto somme su colonne = %f\n",(double)(t1 - t0) / CLOCKS_PER_SEC);

/* somma scorrendo le righe */
 t0 = clock();
 for(j=0;j<Y;j++){
   for(i=0;i<X;i++){
     c[i][j] = a[i][j] + b[i][j];
   }
 }
 t1 = clock();
 printf("%d\n",c[X-1][Y-1]);
 printf("tempo richiesto somme su colonne = %f\n",(double)(t1 - t0) / CLOCKS_PER_SEC);

 return 0;
}

Il cui risultato sul mio povero PC è rappresentato nella seguente immagine:

C

Ok ma perchè ho messo un codice in C ed un test del risultato?

Ovviamente per mostrare come in Fortran95 sia comodo descrivere lo stesso algoritmo e per vedere quali sono i risultati in termini di tempo di accesso, quindi qui il codice:

program prova
implicit none
  integer :: i,j
  integer, parameter :: x=10000, y=10000
  real :: t0,t1
  integer, dimension(x,y) :: a,b,c

  a=1 ; b = 2

!SOMMA SCORRENDO LE COLONNE
  call cpu_time(t0)
  do i=1,x
    do j=1,y
      c(i,j) = a(i,j) + b(i,j)
    enddo
  enddo
  call cpu_time(t1)
  print*, c(x,y)
  print*, "tempo richiesto somme su colonne = ",t1-t0
  print*,""

!SOMMA SCORRENDO LE RIGHE
  do j=1,y
    do i=1,x
      c(i,j) = a(i,j) + b(i,j)
    enddo
  enddo
  call cpu_time(t1)
  print*, c(x,y)
  print*, "tempo richiesto somme su righe = ", t1-t0
  print*,""

!SOMMA IN MODO NATIVO DEL FORTRAN
  call cpu_time(t0)
  c=a+b
  call cpu_time(t1)
  print*, c(x,y)
  print*, "tempo richiesto somme tra matrici = ", t1-t0

end program prova

Con il seguente risultato:F

Come vedete la principale differenza tra i due linguaggi è che in Fortran le MATRICI ed i VETTORI sono tipi nativi, quindi è possibile fare delle operazioni direttamente su di esse.

Occorre tenere presente che ho usato i seguenti compilatori gcc e gfortran, quindi il backend è lo stesso, il perchè della differenza di risultato lo lascio agli esperti, io non so spiegarlo.

E’ interessante notare come una implementazione non oculata degli accessi agli array in C può essere disastrosa.

Tutti i modi usati in Fortran sono migliori, in particolare l’uso delle operazioni a livello “nativo” sulle matrici permette di ridurre notevolmente le righe di codice oltre al non trascurabile fatto avere tempi di calcolo migliori che in C.

Una interessante possibilità dei compilatori fortran è quella di parallelizzare il codice, cosa che purtroppo non riesco a testare :(.

 

Buon Coding in Fortran.

Come installare Intel(R) Fortran Compiler XE 12.1 su Ubuntu 12.04 LTS

Intel offre da anni una versione gratis del suo compilatore fortran per scopi non commerciali e non c’è dubbio che tale compilatore sia tra i migliori se non il migliore attualmente disponibile.

Quindi se state realizzando un software non commerciale, una bella compilazione con il compilatore Intel e le sue ottimizzazioni per i processori Intel potrebbe darvi grandi soddisfazioni.

Bene cominciamo, per prima cosa occorre il compilatore, lo trovate qui: http://software.intel.com/en-us/articles/non-commercial-software-download/

Scaticate e scompattate il file e lanciate come root il file “install.sh”, vi apparirà il seguente menù:

date invio e andate avanti.

Ovviamente questo tutorial non avrebbe senso se l’installazione fosse stata semplice :), infatti vi trovere subito dei problemi:

Selezionate 2 per analizzare i dettagli.

Ed ecco l’origine dei nostri mali:

Provate a forzare l’installazione selezionando 1.

Legge la licenza ed alla fine digitate “accept”.

Alla schermata per l’attivazione scegliete il menù 1:

A questo punto occore inserire il codice seriale che vi è stato spedito via email durante la registrazione per il download del compilatore.

Alla seguente schermata indicate dove installare i files, /opt va benissino:

Bene siamo quasi alla fine seguite le indicazione dell’ultima schermata:

date quindi un bel “$ sudo /opt/intel/bin/compilervars.sh ia32”

Nel mio caso tale comando non ha dato esito, ho quindi provveduto per via manuale alla modifica della variabile $PATH aggiungendo il percorso dei file binari del compilatore.

date i seguenti comandi:

$ cd
$ gedit .profile

e modificate il file come segue:

tutto fatto 🙂

Buon lavoro