Programmazione Strutturata: Procedure, Subroutines, Functions Programmazione Strutturata: motivazione Dato un problema è possibile suddividerlo in sottoproblemi più facili da capire e da risolvere, in modo che scelto un algoritmo che risolva ciascun sottoproblema, l’algoritmo che risolve il problema di partenza può essere ottenuto dalla composizione degli algoritmi più semplici. In altre parole, l’algoritmo risolutivo di un problema complesso può essere descritto per mezzo di macroblocchi che rappresentano algoritmi risolutivi di problemi più semplici. 2 Programmazione Strutturata: tecnica Un macroblocco può essere codificato come un’unità di programma indipendente o procedura. Le procedure sono moduli di programma che concorrono a costituire programmi complessi atti a risolvere problemi complessi. 3 Principali vantaggi della programmazione strutturata : Sviluppo e debugging indipendente delle singole procedure: ogni macroblocco può essere codificato e compilato come un’unità di programma indipendente (procedura); Codice riutilizzabile: è possibile che una procedura sia utilizzabile in più programmi oppure più volte nello stesso programma, con una conseguente riduzione del lavoro complessivo di programmazione ed una semplificazione della fase di correzione degli errori. Isolamento degli effetti collaterali: le procedure comunicano con il programma principale, che le invoca, solo attraverso una lista di variabili. Le uniche variabili del programma principale che possono essere modificate dalla procedura sono quelle incluse nella lista di variabili. 4 Esempio Problema: Calcolo dell’ area di una Corona Circolare r1 r2 AreaCorona = A1 – A2 A1= Area del cerchio di raggio r1; A2= Area del cerchio di raggio r2. Lo stesso sottoproblema, che consiste nel calcolo dell’ area di un cerchio di raggio noto, si ripete due volte. 5 Esempio di codice Fortran per il Calcolo dell’Area di una Corona Circolare PROGRAM Corona_Circolare REAL,PARAMETER:: pi= 3,1415926 REAL:: r1, r2, area1, area2, corona ……. READ (*,*) r1, r2 area1= pi x r1 x r1 area2 = pi x r2 x r2 corona = area1-area2 Write(*,*) corona END PROGRAM Osservazione : Il calcolo dell’area di un cerchio si ripete due volte, per valori diversi dei dati 6 Tale calcolo (area di un cerchio) potrebbe essere codificato come un programma indipendente da eseguire più volte. I valori forniti dalle due esecuzioni potrebbero essere messi in Input al programma CORONA OPPURE: Può essere costruita una procedura per il calcolo dell’area di un cerchio: questa procedura potrà essere richiamata dal programma principale Corona due volte: una prima volta per effettuare il calcolo dell’area del cerchio esterno e una seconda volta per il calcolo dell’area del cerchio interno. Program Corona area A1 area A2 Procedura area_cerchio return end L’algoritmo per il calcolo dell’area del cerchio viene codificato una sola volta e viene richiamato dall’algoritmo principale ogni volta che necessita eseguirlo tale calcolo . 8 Regole per la comunicazione tra le due unità di programma La lista dei parametri costituisce il canale di comunicazione tra l’algoritmo principale e la procedura. -- Vi deve essere una perfetta corrispondenza in numero ed in tipo tra le due liste: quella dei parametri attuali e quella dei parametri formali -- La corrispondenza tra i singoli parametri nelle due liste è per posizione nell’ambito della lista Nell’algoritmo chiamante call area_cerchio (r1, area1) parametri attuali Nella procedura richiamata procedura area_cerchio(raggio, area) parametri formali Strumenti Fortran per la realizzazione di procedure Il Fortran dispone di due tipi di procedure Subroutine --Può restituire più valori --E’ richiamata con una istruzione Function --Restituisce un singolo valore -- E’ richiamata con il suo nome 10 PASSAGGIO DEI PARAMETRI : La corrispondenza tra i parametri attuali e quelli formali si realizza tramite il passaggio dell’indirizzo di memoria del parametro attuale al sottoprogramma chiamato che, mentre è in esecuzione, lo usa come indirizzo del corrispondente parametro formale. Nel codice … CALL subroutine ( Aattuale , Battuale) … … subroutine ( Aformale , Bformale) … memoria Aattuale Battuale 10101010 10111010 Quando la esecuzione: Aformale Bformale subroutine Aformale corrisponde alla va in stessa locazione di memoria di Aattuale e Bformale corrisponde alla stessa locazione di memoria Battuale 11 PASSAGGIO DEI PARAMETRI - se il parametro è un array : Attraverso il nome dell’array viene passato alla procedura l’indirizzo dell’array cioè, come sappiamo, l’indirizzo della prima componente. L’indirizzo della prima componente del parametro formale coinciderà con l’indirizzo della prima componente di quello attuale Le altre componenti dell’array, essendo memorizzate nelle locazioni consecutive, si corrispondono automaticamente. 12 PASSAGGIO DEI PARAMETRI - se il parametro è un array : RICORDA ! Bisogna prestare particolare attenzione a quante sono le componenti dell’array per il programma chiamante e quante sono per il sottoprogramma ! Per gli array bidimensionali bisogna tener conto anche di come sono memorizzate le componenti (ad es in Fortran: per colonne) in Fortran è vitale far in modo che coincidano la dimensione di una colonna dell’array cosi come è dichiarato nel programma chiamante e quella con cui è dichiarato nella procedura. Ciò è indispensabile affinchè coincidano gli indirizzi dei singoli elementi dell’array… 13 La Subroutine: chiamata Una subroutine è una procedura che viene invocata per mezzo di una specifica istruzione : CALL nome_subroutine (lista_parametri_attuali) Il programma chiamante fornisce i valori di input alla subroutine e riceve i valori di output dalla subroutine attraverso la lista dei parametri attuali. 14 La Subroutine: struttura Una subroutine è un’unità di programma Fortran che assume la forma seguente: SUBROUTINE nome_subroutine (lista_parametri_formali) … (sezione dichiarativa) … (sezione esecutiva) RETURN END SUBROUTINE nome_subroutine 15 La Subroutine: struttura– l’attributo INTENT SUBROUTINE sub( var1, var2, sum, volte) REAL , INTENT (IN) :: var1, var2 REAL , INTENT (OUT) :: sum INTEGER, INTENT (INOUT) :: volte sum = var1 + var2 volte = volte +1 RETURN 16 La Subroutine: struttura (variabili locali) SUBROUTINE acerc( r, a) REAL , INTENT (IN) :: r REAL , INTENT (OUT) :: a REAL, PARAMETER :: pi = 3.14 a = pi * ( r * r) RETURN Parametri della subroutine costante LOCALE alla subroutine 17 La Subroutine: esempio chiamata Programma chiamante Program Corona Subroutine SUBROUTINE CIRC (RAG, AREA) CALL CIRC(R1,A1) CALL CIRC(R2,A2) end REAL, INTENT(IN) :: RAG REAL; INTENT (OUT) :: AREA RETURN La Function: chiamata Una function è una procedura che viene invocata per mezzo del suo nome, e non con una specifica istruzione. var = nome_function (lista_parametri_attuali) Una ‘chiamata a function’, o ‘riferimento a function’ dal punto di vista della teoria dei linguaggi formali, è un “primario”, cioè è della stessa natura di una costante o di una variabile semplice, dunque può comparire nel programma ovunque potrebbe comparire una variabile semplice. La Function: struttura (1) tipo FUNCTION nome_function (lista_parametri) … (sezione dichiarativa) … (sezione esecutiva) nome_function = …….. ….. RETURN END FUNCTION [nome_function] 20 La Function: struttura Nell’unità di programma ‘function’, il nome della function viene usato come nome di una variabile del tipo dichiarato nella intestazione della function; Tale variabile deve comparire almeno una volta a sinista dell’uguale in una frase di assegnazione, cioè a tale variabile deve essere sempre assegnato un valore durante l’esecuzione della function; Al termine della esecuzione della function il valore di tale variabile è il ‘valore della function’, cioè il valore restituito al programma chiamante; L’istruzione return restituisce il controllo al programma chiamante nel punto in cui è stata chiamata la function, cioè nel punto esatto in cui compare il riferimento alla function. La Function: esempio Programma chiamante Program Corona Sottoprogramma di tipo function REAL FUNCTION CIRC(RAG) A1=CIRC(R1) A2=CIRC(R2) end CIRC= pi * r *r END FUNCTION CIRC 22 INTRINSIC FUNCTIONS ( funzioni intrinseche) Ogni linguaggio di programmazione fornisce un insieme di functions predefinite (intrinseche) a cui è possibile far riferimento, nelle espressioni, senza doverle riscrivere Il codice che implementa queste funzioni è messo a disposizione, in forma precompilata e quindi rilocabile, sotto forma di librerie Le librerie (purchè presenti sul disco) vengono linkate automaticamente insieme al programma chiamante dal relocating loader. Funzioni Intrinseche del Fortran Di natura specificamente matematica SIN (X), COS(X), SQRT(X)….. EXP(X) , LOG(X)…. Di carattere generale MOD(X,Y), MIN(A,B), MAX(A,B)…. Di utilità CHAR… SHIFT… funzioni per uso di puntatori… ecc. ecc. Di utilità : chiamate ad una routine del sistema operativo Come ad es. CPU_Time(x) , second(x) Uso della subroutine ‘cpu_time’ program test_cpu_time real :: start, finish , time call cpu_time(start) …. ! Codice fortran da temporizzare …… call cpu_time(finish) time = finish – start write)(*,*) "Tempo impiegato: ", time , " secondi” end program test_cpu_time 25 FINE SUBROUTINES /FUNCTIONS IN FORTRAN 26 ESEMPI 27 Prodotto scalare di due vettori : flow_chart start n a i ,i = 1, n bi ,i = 1, n sca = 0 i=0 i= i+1 sca = sca + a i * bi i == n FALSO VERO sca stop Laboratorio di Prgrammazione Prof_A.C.Simoncelli a.a. 2011/12 28 PRODOTTO SCALARE TRA DUE VETTORI PROGRAM scalare IMPLICIT NONE INTEGER, parameter :: n = 10 ! dim. comune INTEGER :: i REAL :: sca REAL, DIMENSION (n) :: vett1 = 0., vett2 = 0. ! creo i due vettori elem_i: DO i=1, n vett1(i) = i vett2(i) = 1 END DO elem_i ! calcolo del prodotto scalare vett1 X vett2 sca = 0. accumulo : DO i=1, n sca = sca + vett1(i) * vett2(i) END DO accumulo !output WRITE(*,*) ' Il prodotto scalare dei vettori' WRITE(*,*) WRITE(*,100) 'vett1 =', (vett1(i), i=1,n) WRITE(*,100) 'vett2 =', (vett2(i), i=1,n) WRITE(*,*) 'e'' il numero: ' , sca 100 FORMAT ( A8 , 10f5.0) STOP END PROGRAM scalare ESECUZIONE : C:\MyFor\STUDENTI\ASS_19_11>scalare Il prodotto scalare dei vettori vett1 = 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. vett2 = 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. e' il numero: 55. C:\MyFor\STUDENTI\ASS_19_11> Laboratorio di Prgrammazione Prof_A.C.Simoncelli a.a. 2011/12 29 start Prodotto di due matrici, righe per colonne: flow_chart nria, ndimcom, ncob a ij ; i = 1, nria ; j = 1, ndimcom bij ; i = 1, ndimcom; j = 1, ncob i=0 i=i+1 j=0 sca = 0 j= j+ 1 k=0 Calcola l’elemento pij della matrice prodotto: pij = prodotto scalare riga-a i X colonna-bj k= k+1 sca = sca + a ik * bkj FALSO j==ncob k == ndimcom FALSO VERO VERO FALSO p i j = sca i ==nria VERO pij ; i = 1, nria ; j = 1, ncob stop Laboratorio di Prgrammazione Prof_A.C.Simoncelli a.a. 2011/12 30 PRODOTTO DI DUE MATRICI di dimensioni compatibili PROGRAM matmat ! Crea due matrici di dimensioni compatibili (m X n) , (n x k) ! e ne calcola il prodotto di IMPLICIT NONE ! dimensione comune = ncom INTEGER,parameter :: ncom = 4 , nri1 = 2, nco2 = 3 INTEGER :: i,j,k REAL :: sca !var. appoggio per accumulo somma REAL, DIMENSION (nri1, ncom) :: mat1 = 0. REAL, DIMENSION (ncom, nco2) :: mat2 = 0. REAL, DIMENSION (nri1, nco2) :: matprod = 0. !---------------creazione prima matrice rigam1_i: DO i=1, nri1 elemento1_ij : DO j = 1, ncom mat1(i,j) = 2*i + j END DO elemento1_ij END DO rigam1_i !---------------creazione seconda matrice rigam2_i: DO i=1, ncom elemento2_ij : DO j = 1, nco2 mat2(i,j) = j END DO elemento2_ij END DO rigam2_i !------- calcolo elementi del prodotto !-------matprod = mat1 X mat2 rigapro_i: DO i = 1, nri1 elepro_ij: DO j=1, nco2 sca = 0. accumulo: DO k=1, ncom sca = sca + mat1(i,k) * mat2(k,j) END DO accumulo matprod(i,j)= sca END DO elepro_ij END DO rigapro_i !-----------------output WRITE(*,*) ' Il prodotto della matrice di dimensione', nri1,'x',ncom printriga: DO i=1, nri1 WRITE(*,100) (mat1(i,j),j = 1,ncom) END DO printriga WRITE(*,*) ' per la matrice di dimensione', ncom,'x',nco2 printri: DO i=1, ncom WRITE(*,100) (mat2(i,j),j = 1,nco2) END DO printri WRITE(*,*) 'e'' la matrice di dimensione', nri1,'x',nco2 printlinea: DO i=1, nri1 WRITE(*,100) (matprod(i,j),j = 1,nco2) END DO printlinea 100 FORMAT ( 2x, 10f5.0) STOP END PROGRAM matmat Laboratorio di Prgrammazione Prof_A.C.Simoncelli a.a. 2011/12 31 Si potrebbe scrivere un programma per il calcolo del prodotto righe per colonne in cui il prodotto scalare necessario per calcolare ogni elemento del prodotto non viene codificato all’interno del programma ma viene scritto sotto forma di procedura e richiamato dal programma principale ogni volta che è necessario…. 32 UN ESEMPIO UN PO’ PIU’ COMPLESSO Progettiamo ed implementiamo un programma Fortran che sia in grado di verificare la validità della nota relazione per le matrici trasposte: (A x B ) T = B T x A T controllando che essa sussista per qualsiasi coppia di matrici A e B fornite in input, del tutto arbitrarie purché di dimensioni compatibili. 33 Diagramma a grossi blocchi start Leggi matrici A, B Calcola C = A x B maxel == 0 vero falso Calcola CT= trasposta di C Scrivi ‘NON VERIFICATA’ Calcola AT = trasposta di A Calcola BT = trasposta di B Calcola PT = BT x AT Scrivi ‘VERIFICATA’ Calcola DIFF = CT - PT Calcola ADIFF = ABS(DIFF) Calcola maxel = massimo elemento di ADIFF stop 34 UNA SUBROUTINE PER CALCOLARE LA TRASPOSTA DI UNA MATRICE SUBROUTINE TRASP (D,dmaxdim,drighe,dcolonne,DT) INTEGER, INTENT(IN) :: dmaxdim, drighe, dcolonne INTEGER :: i, j REAL, DIMENSION (dmaxdim,dmaxdim), INTENT(IN) :: D REAL, DIMENSION (dmaxdim,dmaxdim), INTENT(OUT) :: DT DO i = 1, dcolonne DO j = 1, drighe DT(i,j) = D(j,i) END DO END DO RETURN END SUBROUTINE TRASP 35 UNA SUBROUTINE PER CALCOLARE IL PRODOTTO DI DUE MATRICI SUBROUTINE PROD (MA,maxdima,MB,maxdimb, arighe,acolonne,brighe,bcolonne,PP,maxdimp, ok) INTEGER , INTENT(IN) :: maxdima, maxdimb, maxdimp, arighe , acolonne , brighe , bcolonne LOGICAL, INTENT(OUT) :: ok REAL, DIMENSION(maxdima,maxdima), INTENT(IN) :: MA, MB REAL, DIMENSION (maxdimp,maxdimp), INTENT(OUT) :: PP INTEGER :: i, j, k ! variabili locali - contatori REAL :: app ! variabile locale per accumulo prodotto scalare IF ( acolonne == brighe) THEN ! si puo' calcolare il prodotto ok = .TRUE. DO i = 1, arighe DO j = 1, bcolonne app = 0. DO k = 1, acolonne app = app + MA(i,k)* MB(k,j) END DO PP(i,j) = app END DO END DO ELSE ! dimensioni effettive incompatibili: impossibile calcolare il prodotto ok = .FALSE. ENDIF RETURN END SUBROUTINE PROD 36 UNA SUBROUTINE PER CALCOLARE LA SOMMA DI DUE MATRICI SUBROUTINE SUMMAT (M1,M2,dimassima,nrighe,ncolonne,SUM) INTEGER, INTENT(IN) :: dimassima, nrighe, ncolonne INTEGER :: i, j REAL, DIMENSION (dimassima,dimassima), INTENT(IN) :: M1,M2 REAL, DIMENSION (dimassima,dimassima), INTENT(OUT) :: SUM rigai: DO i = 1, nrighe elementoij: DO j = 1, ncolonne SUM(i,j) = M1(i,j) + M2(i,j) END DO elementoij END DO rigai RETURN END SUBROUTINE SUMMAT 37 UNA FUNCTION PER TROVARE IL MASSIMO ELEMENTO DI UNA MATRICE REAL FUNCTION MAXMAT (mat,maxdim,nrim,ncom) INTEGER, INTENT(IN) :: maxdim,nrim,ncom INTEGER :: i, j REAL, DIMENSION (maxdim,maxdim), INTENT(IN) :: mat maxmat = mat(1,1) rigai: DO i = 1, nrim elementoij: DO j = 1, ncom IF (mat(i,j) > maxmat) maxmat = mat(i,j) END DO elementoij END DO rigai RETURN END FUNCTION MAXMAT 38 Il nostro MAIN : solo uno dei possibili programmi per implementare l’algoritmo utilizzando tutte le precedenti procedure PROGRAM matrix IMPLICIT NONE ! dichiarazione delle costanti e delle variabili INTEGER, PARAMETER :: maxdim = 20 REAL, DIMENSION (maxdim, maxdim) :: A, B, AT, BT REAL, DIMENSION (maxdim, maxdim) :: PR, PRT, PRATBT REAL, DIMENSION (maxdim, maxdim) :: DIFF INTEGER :: nria, ncoa, nrib, ncob INTEGER :: i, j, ierror LOGICAL :: ok REAL :: maxel, maxmat … continua 39 Il nostro MAIN ….. continua ! INPUT DATI E VERIFICA OPEN (UNIT = 8, FILE = 'mata', STATUS = 'OLD', ACTION = 'READ', IOSTAT = ierror) READ(8,*) nria, ncoa rrigaa : DO i = 1, nria READ(8,*) ( A(i,j), j = 1, ncoa) END DO rrigaa CLOSE(8) ! Echo WRITE (*,*) WRITE (*,*) ' Matrice A : ' , nria, 'righe,', ncoa, 'colonne' wrigaa : DO i = 1 , nria WRITE(*,*) ( A(i,j), j = 1, ncoa) END DO wrigaa OPEN (UNIT = 8, FILE = 'matb', STATUS = 'OLD', ACTION = 'READ', IOSTAT = ierror) READ(8,*) nrib, ncob rrigab : DO i = 1 , nrib READ(8,*) ( B(i,j), j = 1, ncob) END DO rrigab CLOSE(8) WRITE (*,*) WRITE (*,*) ' Matrice B: ' , nrib, 'righe,', ncob, 'colonne' wrigab : DO i = 1 , nrib WRITE(*,*) ( B(i,j), j = 1, ncob) END DO wrigab 40 Il nostro MAIN ….. continua ! Calcola matrice prodotto CALL PROD (A,maxdim,B,maxdim,nria,ncoa,nrib,ncob,PR,maxdim, ok) WRITE (*,*) ok IF ( ok) THEN WRITE (*,*) WRITE (*,*) ' Matrice prodotto di A x B' , nria, 'righe,', ncob, 'colonne' wrigap : DO i = 1 , nria WRITE(*,100) ( PR(i,j), j = 1, ncob) END DO wrigap ENDIF ! Calcola le tre trasposte CALL TRASP (A,maxdim,nria,ncoa,AT) CALL TRASP (B,maxdim,nrib,ncob,BT) CALL TRASP (PR,maxdim,nria,ncob,PRT) ! Calcola il prodotto delle trasposte CALL PROD (BT,maxdim,AT,maxdim,ncob,nrib,ncoa,nria,PRATBT,maxdim, ok) 41 Il nostro MAIN ….. continua ! Calcola la matrice differenza CALL SUMMAT (PRT, -PRATBT, maxdim,ncob,nria,DIFF) ! Calcola il massimo tra I valori assoluti degli elementi della matrice maxel = MAXMAT (ABS(DIFF),maxdim,ncob,nria) WRITE (*,*) 'massimo valore assoluto', maxel ! Finalmente : il controllo è effettuato su maxel IF (maxel == 0. ) THEN WRITE (*,*) 'La relazione risulta verificata: (AxB)t = Bt x At' ELSE WRITE (*,*) 'In questo caso la relazione (AxB)t = Bt x At non risulta verificata:' END IF STOP 100 FORMAT ( 1x, 20F8.2 ) END PROGRAM matrix 42 Ora bisogna eseguirlo ! Aprire il terminale e cominciare a lavorare 43 FINE (22.5.2012) 44