Il linguaggio Fortran 90: 4. Array: Vettori e Matrici
Vettori Gruppi di variabili dello stesso tipo memorizzate in locazioni contigue di memoria. La i-esima posizione dell’array a è indicata con a(i) Gli elementi di un array sono normali variabili
Dichiarazione di variabili vettore REAL, DIMENSION (20) :: a L’attributo DIMENSION serve per dichiarare la lunghezza del vettore CHARACTER(len=20), DIMENSION (50) :: cognome Indica un vettore di 50 elementi ognuno dei quali è una stringa di 20 caratteri Costanti di tipo array: (/ 1, 2, 3, 4, 5 /) Inizializzazione di un array: INTEGER, DIMENSION (5) :: a = (/ 1, 2, 3, 4, 5 /) DO i=1, 5 a(i)=i END DO Il range di variabilità può essere fissato altrimenti: REAL DIMENSION (inf : sup) :: a
Somma di due vettori ! File: somvett1.for ! Scopo: esempio di uso di array PROGRAM somma_vettori ! Questo programma calcola la somma di due vettori a 3 componenti ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE INTEGER, PARAMETER :: dimensione = 3 INTEGER, DIMENSION(dimensione) :: v1, v2 ! i due vettori letti INTEGER, DIMENSION(dimensione) :: somma ! il vettore somma INTEGER :: i ! indice di ciclo per scandire le componenti dei vettori ! *** SEZIONE ESECUTIVA *** ! ! lettura primo vettore WRITE(*,*) 'Immetti il primo vettore!' DO i = 1, dimensione ! leggiamo il vettore una componente alla volta WRITE(*,*) 'Componente ', i, ' ? ' READ (*,*) v1(i) END DO
Somma di due vettori (cont.) ! lettura secondo vettore WRITE(*,*) 'Immetti il secondo vettore!' DO i = 1, dimensione ! leggiamo il vettore una componente alla volta WRITE(*,*) 'Componente ', i, ' ? ' READ (*,*) v2(i) END DO ! calcolo vettore somma somma(i) = v1(i) + v2(i) ! N.B. si potrebbe fare direttamente somma = v1 + v2 ! stampa del vettore somma WRITE(*,*) 'Il vettore somma e'':' WRITE(*,*) 'Componente ', i, ' : ', somma(i) STOP END PROGRAM somma_vettori
Passaggio di Parametri Vettore Array fittizi di forma presunta Una procedura non conosce in generale la dimensione dei parametri effettivi array passati alla procedura Array fittizi non specificano la dimensione dell’array REAL, DIMENSION (:) :: a INTEGER :: i DO i = LBOUND (a,1), UBOUND (a,1) a (i) = 0 END DO In alternativa occorre passare come parametro la dimensione degli array
Passaggio di Parametri di Tipo Vettore ! File: util-vet.for MODULE operazioni_su_vettori ! Questo modulo contiene alcune unita‘ che effettuano operazioni su ! Vettori: ! - leggi_vettore : subroutine per la lettura di un vettore di interi ! di lunghezza arbitraria ! - stampa_vettore : subroutine per la stampa di un vettore di interi ! - somma_vettori : funzione per la somma vettoriale di due vettori di ! interi di lunghezza arbitraria (passata come parametro) ! - somma_vettori_sub : subroutine per la somma vettoriale di due ! vettori di interi di lunghezza arbitraria. Analoga alla precedente ! ma non e' necessario passare la lunghezza. CONTAINS
Passaggio di Parametri di Tipo Vettore (cont.) SUBROUTINE leggi_vettore (vet) IMPLICIT NONE ! ** DICHIARAZIONE ARGOMENTI FITTIZI INTEGER, INTENT(IN OUT), DIMENSION(:) :: vet ! il vettore di input ! ** DICHIARAZIONE VARIABILI LOCALI INTEGER :: i ! indice di ciclo DO i = LBOUND(vet,1), UBOUND(vet,1) WRITE(*,*) 'Componente ', i, ' ? ' READ (*,*) vet(i) END DO RETURN END SUBROUTINE leggi_vettore
Passaggio di Parametri di Tipo Vettore (cont.) SUBROUTINE stampa_vettore (vet) ! DICHIARAZIONE ARGOMENTI FITTIZI INTEGER, DIMENSION(:), INTENT(IN) :: vet ! Vettore di input ! DICHIARAZIONE VARIABILI LOCALI INTEGER :: i ! indice del ciclo DO i = LBOUND(vet,1), UBOUND(vet,1) WRITE(*,*) 'Componente ', i, ':', vet(i) END DO RETURN END SUBROUTINE stampa_vettore
Passaggio di Parametri di Tipo Vettore (cont.) FUNCTION somma_vettori (vet1, vet2, dim) IMPLICIT NONE ! ** DICHIARAZIONE ARGOMENTI FITTIZI INTEGER, DIMENSION(:), INTENT(IN) :: vet1, vet2 ! i vettori di input INTEGER, INTENT(IN) :: dim ! la lunghezza dei vettori ! ** DICHIARAZIONE TIPO FUNZIONE INTEGER, DIMENSION(dim) :: somma_vettori ! ** DICHIARAZIONE VARIABILI LOCALI INTEGER :: i ! indice del ciclo DO i = LBOUND(vet1,1), UBOUND(vet1,1) somma_vettori(i) = vet1(i) + vet2(i) END DO RETURN END FUNCTION somma_vettori
Passaggio di Parametri di Tipo Vettore (cont.) SUBROUTINE somma_vettori_sub (vet1, vet2, ris) IMPLICIT NONE ! ** DICHIARAZIONE ARGOMENTI FITTIZI INTEGER, DIMENSION(:), INTENT(IN) :: vet1, vet2 ! i vettori di input INTEGER, DIMENSION(:), INTENT(OUT) :: ris ! il vettore di output INTEGER :: i ! indice del ciclo ! *** SEZIONE ESECUTIVA DO i = LBOUND(vet1,1), UBOUND(vet1,1) ris(i) = vet1(i) + vet2(i) END DO RETURN END SUBROUTINE somma_vettori_sub
Passaggio di Parametri di Tipo Vettore (cont.) ! File: somvett2.for ! Scopo: Uso di sottoprogrammi che manipolano array unidimensionali di ! due vettori a 3 componenti, usando le SUBROUTINE PROGRAM somma_vettori_2 ! *** SEZIONE DICHIARATIVA *** ! USE operazioni_su_vettori IMPLICIT NONE INTEGER, PARAMETER :: dimensione = 3 INTEGER, DIMENSION(dimensione) :: v1, v2 ! i due vettori letti INTEGER, DIMENSION(dimensione) :: somma ! il vettore somma
Passaggio di Parametri di Tipo Vettore (cont.) ! *** SEZIONE ESECUTIVA *** ! WRITE(*,*) 'Immetti il primo vettore!' CALL leggi_vettore(v1) ! lettura secondo vettore WRITE(*,*) 'Immetti il secondo vettore!' CALL leggi_vettore(v2) ! calcolo vettore somma con la funzione somma = somma_vettori(v1,v2,dimensione) ! stampa del vettore somma WRITE(*,*) 'Il vettore somma e'':' CALL stampa_vettore(somma) ! calcolo vettore somma con la subroutine CALL somma_vettori_sub(v1,v2,somma) WRITE(*,*) 'Il vettore somma (calcolato in altra maniera) e'':' STOP END PROGRAM somma_vettori_2
Ordinamento di un Vettore Ordinare un vettore di n interi in modo non decrescente.
Algoritmo di Ordinamento loop1: DO i=1, n-1 “Tova la posizione k_min del minimo intero nelle posizioni da i a n” “Scambia l’elemento nella posizione i con l’elemento nella posizione k_min” END DO loop1
Ordinamento di un Vettore (Cont.) “Trova la posizione k_min del minimo intero nelle posizioni da i a n” k_min = i loop2: DO j=i+1, n IF (a(j) < a(k_min)) k_min = j END DO loop2 “Scambia l’elemento nella posizione i con l’elemento nella posizione k_min” tmp = a(i) a(i) = a(kmin) a(kmin) = tmp
Ordinamento di un Vettore (Cont.) SUBROUTINE ordinavett(v) ! Scopo: ordinamento di un vettore di interi IMPLICIT NONE ! Dichiarazione parametri formali INTEGER, DIMENSION (:), INTENT (IN OUT) :: v ! Dichiarazione variabili locali INTEGER :: i, j, k_min, i_min, i_max, tmp i_min = LBOUND(v,1) i_max = UBOUND(v,1) loop1: DO i=i_min, (i_max - 1) k_min = i loop2: DO j=i+1, i_max IF (v(j) < v(k_min)) k_min = j END DO loop2 tmp = v(i) v(i) = v(k_min) v(k_min) = tmp END DO loop1 RETURN END SUBROUTINE ordinavett
Ordinamento di un Vettore (Cont.) ! File: test_ordinavett.for ! Scopo: testare la subroutine ordinavett(v) che ordina un vettore di interi PROGRAM test_ordinavett USE operazioni_su_vettori IMPLICIT NONE INTEGER, PARAMETER :: dimensione = 3 INTEGER, DIMENSION(dimensione) :: v ! vettore da leggere e ordinare WRITE(*,*) 'Immetti il vettore di interi da ordinare ' CALL leggi_vettore(v) ! stampa del vettore inserito WRITE(*,*) 'Vettore inserito: ' CALL stampa_vettore(v) ! ordino il vettore somma con la funzione ordinavett(v) CALL ordinavett(v) ! stampa del vettore ordinato WRITE(*,*) 'Vettore ordinato: ' STOP END PROGRAM test_ordinavett
Matrici Vettori a due dimensioni Ogni elemento è indicato da un indice di riga ed un indice di colonna L’elemento della matrice di indice di riga i ed indice di colonna j è indicato con a(i,j)
Dichiarazione di Matrici INTEGER, DIMENSION (5,10) :: a REAL, DIMENSION (0:100, 5:20) :: valori Inizializzazione di una Matrice INTEGER, DIMENSION (7,10) :: mat DO i=1, 7 DO j=1, 10 mat(i,j) = 0 END DO
Gestione delle matrici ! File: mod_matr.for MODULE modulo_matrici ! Questo modulo contiene alcune unita‘ che effettuano operazioni su ! matrici: ! - leggi_matrice : subroutine per la lettura di una matrice ! bidimensionale di interi di forma arbitraria ! - stampa_matrice : subroutine per la stampa di una matrice ! - somma_matrici : funzione per la somma vettoriale di due matrici ! bidimensionali di interi di forma arbitraria ! - prodotto_matrici : funzione che calcola il prodotto di due ! matrici di interi CONTAINS
Gestione delle matrici (cont) SUBROUTINE leggi_matrice (mat) IMPLICIT NONE ! ** DICHIARAZIONE ARGOMENTI FITTIZI INTEGER, INTENT(IN OUT), DIMENSION(:,:) :: mat ! matrice di input ! ** DICHIARAZIONE VARIABILI LOCALI INTEGER :: i, j, r_min, r_max, c_min, c_max r_min = LBOUND (mat,1) r_max = UBOUND (mat,1) c_min = LBOUND (mat,2) c_max = UBOUND (mat,2) WRITE(*,*) 'Inserisci matrice', (r_max-r_min+1), ' *',(c_max-c_min+1) DO i = r_min, r_max DO j = c_min, c_max WRITE(*,*) 'componente ', i, j, ' : ' READ (*,*) mat(i,j) END DO RETURN END SUBROUTINE leggi_matrice
Gestione delle matrici (cont) SUBROUTINE stampa_matrice (mat) IMPLICIT NONE ! ** DICHIARAZIONE ARGOMENTI FITTIZI INTEGER, INTENT(IN), DIMENSION(:,:) :: mat ! matrice di input ! ** DICHIARAZIONE VARIABILI LOCALI INTEGER :: i, j, r_min, r_max, c_min, c_max r_min = LBOUND (mat,1) r_max = UBOUND (mat,1) c_min = LBOUND (mat,2) c_max = UBOUND (mat,2) DO i = r_min, r_max WRITE(*,*) 'riga', i DO j = c_min, c_max WRITE(*,*) ' col.', j, ' =', mat(i,j) END DO RETURN END SUBROUTINE stampa_matrice
Somma di Matrici SUBROUTINE somma_matrici(a, b, c) IMPLICIT NONE ! Dichiarazioni parametri fittizi INTEGER, DIMENSION(:,:), INTENT (IN) :: a, b INTEGER, DIMENSION (:,:),INTENT (OUT) :: c ! Dichiarazione variabili locali INTEGER :: i, j, r_min, r_max, c_min, c_max r_min = LBOUND (a,1) r_max = UBOUND (a,1) c_min = LBOUND (a,2) c_max = UBOUND (a,2) DO i = r_min, r_max DO j = c_min, c_max c(i,j) = a (i,j) + b (i,j) END DO RETURN END SUBROUTINE somma_matrici
Moltiplicazione tra Matrici Date due matrici a(n:m) e b(m:p) calcolare la matrice prodotto c(n:p). DO i=1, n DO j=1, p END DO
Moltiplicazione tra Matrici (cont.) SUBROUTINE prodotto_matrici (a,b,c,n,m,p) IMPLICIT NONE ! Dichiarazioni parametri formali INTEGER, INTENT(IN) :: n, m, p INTEGER, DIMENSION (n,m), INTENT (IN) :: a INTEGER, DIMENSION (m,p), INTENT (IN) :: b INTEGER, DIMENSION (n,p), INTENT (OUT) :: c ! Dichiarazione variabili locali INTEGER :: i, j, k DO i = 1, n DO j = 1, p c(i,j) = 0 DO k = 1, m c(i,j) = c(i,j) + a(i,k) * b(k,j) END DO RETURN END SUBROUTINE prodotto_matrici
Calcolo del minimo locale Data una matrice a(n:m) calcolare per ogni elemento a(i,j) il minimo tra a(i,j) e gli elementi adiacenti.
Calcolo del minimo locale (cont.) SUBROUTINE minimo_locale(a,b,n,m) IMPLICIT NONE INTEGER, INTENT(IN) :: n, m INTEGER, DIMENSION(n,m), INTENT (IN) :: a INTEGER, DIMENSION (n,m),INTENT (OUT) :: b ! Dichiarazione variabili locali INTEGER :: i, j, k, l, i1,i2, j1, j2,min IF ((n < 2) .OR. (m < 2)) THEN b = a ELSE loop1: DO i = 1, n loop2: DO j = 1, m “Calcolo del minimo locale nell’intorno di a(i,j) ed assegnazione a b(i,j)” END DO loop2 END DO loop1 END IF RETURN END SUBROUTINE minimo_locale END MODULE modulo_matrici
Calcolo del minimo locale (cont.) “Calcolo del minimo locale nell’intorno di a(i,j)”: IF (i == 1) THEN i1 = 1 ELSE i1 = i-1 END IF IF (i == n) THEN i2 = n i2 = i+1 IF (j == 1) THEN j1 = 1 j1 = j-1 IF (j == m) THEN j2 = m j2 = j+1
Calcolo del minimo locale (cont.) min = a(i,j) loop3: DO k = i1, i2 loop4: DO l = j1, j2 IF (a(k,l) < min) min = a(k,l) END DO loop4 END DO loop3 b(i,j) = min
Potenza elettrica erogata Per ogni istante di tempo si conosce la potenza elettrica erogata da n generatori. L’osservazione delle potenza erogata prosegue per m istanti di tempo Scrivere una SUBROUTINE che calcoli la potenza media erogata da ogni generatore lungo gli m istanti di tempo ed una SUBROUTINE che calcoli la potenza totale erogata dagli n generatori ad ogni istante di tempo
Potenza elettrica erogata(cont.) I dati di input alla procedura sono rappresentati in una matrice di reali erogati(n,m) di n righe ed m colonne. I dati di output sono rappresentati in un vettore media(n) ed un vettore totale(m)
Potenza elettrica erogata(cont.) Esempio: 4 generatori, 5 istanti di tempo
Potenza elettrica erogata(cont.) Calcolo della potenza media SUBROUTINE pot_media (erogati, n, m, media) ! Scopo: calcolo della potenza media erogata da ogni generatore ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE ! Dichiarazione parametri formali REAL, DIMENSION(:,:), INTENT(IN) :: erogati INTEGER, INTENT(IN) :: n, m REAL, DIMENSION(:), INTENT(OUT) :: media ! Dichiarazione variabili locali INTEGER :: i,j REAL ::temp
Potenza elettrica erogata(cont.) Calcolo della potenza media ! *** SEZIONE ESECUTIVA *** ! DO i=1, n ! Calcola la potenza media del generatore i temp = 0. DO j=1, m ! Scandisci gli m istanti di tempo temp = temp + erogati(i,j) END DO media(i) = temp / m RETURN END SUBROUTINE pot_media
Potenza elettrica erogata(cont.) Calcolo della potenza totale SUBROUTINE pot_totale (erogati, n, m, totale) ! Scopo: calcolo della potenza totale erogata da ogni generatore ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE ! Dichiarazione parametri formali REAL, DIMENSION(:,:), INTENT(IN) :: erogati INTEGER, INTENT(IN) :: n, m REAL, DIMENSION(:), INTENT(OUT) :: totale ! Dichiarazione variabili locali INTEGER :: i,j REAL ::temp
Potenza elettrica erogata(cont.) Calcolo della potenza totale ! *** SEZIONE ESECUTIVA *** ! DO i=1, m ! Calcola la potenza totale erogata al tempo i temp = 0. DO j=1, n ! Scandisci gli n generatori temp = temp + erogati(j,i) END DO totale(i) = temp RETURN END SUBROUTINE pot_totale
Calcolo dei prodotti scalari Una matrice x(n:m) memorizza le componenti di n vettori ad m dimensioni Scrivere una SUBROUTINE che calcoli il prodotto scalare tra tutte le coppie di vettori Il risultato e’ formato di n**2 prodotti scalari che memorizziamo in una matrice prod (n:n)
Calcolo dei prodotti scalari EX: m=3 v1 = x(1,1) i + x(1,2) j+ x(1,3) k v2 = x(2,1) i + x(2,2) j+ x(2,3) k v1 v2 = x(1,1) * x(2,1) + x(1,2) * x(2,2) + x(1,3) * x(2,3)
Calcolo dei prodotti scalari (cont.) SUBROUTINE prodotto_scalare (x, n, m, prod) ! Scopo: calcolo dei prodotti scalari tra tutte le coppie di n righe ! di una matrice x(n,m). ! Ritorna la matrice dei prodotti scalari prod(n,n) ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE !Dichiarazione parametri formali INTEGER, INTENT(IN) :: n, m REAL, DIMENSION(:,:), INTENT(IN) :: x ! x(i,j) memorizza la j-ma componente dell’i-mo vettore REAL, DIMENSION(:,:), INTENT(OUT) :: prod ! Prod(i,j) memorizza il prodotto scalare tra il vettore i ed il ! vettore j !Dichiarazione variabili locali INTEGER :: i, j, k REAL :: tmp
Calcolo dei prodotti scalari (cont.) ! *** SEZIONE ESECUTIVA *** ! DO i = 1, n DO j = 1, n tmp = 0.0 DO k = 1, m tmp = tmp + x(i,k) * x(j,k) END DO WRITE(*,*)'prod(',i,j,') = ',tmp prod (i,j) = tmp RETURN END SUBROUTINE prodotto_scalare