250 likes | 387 Views
Il linguaggio Fortran 90: 3. Procedure e Funzioni. Stefano Leonardi Dipartimento di Informatica e Sistemistica. Procedure. Il problema da risolvere viene spesso decomposto in tante parti logiche di facile soluzione.
E N D
Il linguaggio Fortran 90: 3. Procedure e Funzioni Stefano Leonardi Dipartimento di Informatica e Sistemistica
Procedure • Il problema da risolvere viene spesso decomposto in tante parti logiche di facile soluzione. • E’ possibile realizzare le funzionalità di base attraverso unità di programma indipendenti dette procedure • Le unità di programma possono essere compilate e testate separatamente. • Le unità di programma possono essere utilizzate in più programmi che necessitano tale funzionalità.
Procedure (cont.) • E’ possibile isolare la comunicazione delle procedure con il programma principale ad un insieme di parametri definiti nell’intestazione. • Nelle Subroutine i dati di input e di output sono comunicati attraverso i parametri. • Nelle Funzioni solo i dati di input sono comunicati attraverso i parametri mentre il risultato è indicato dal nome della funzione.
Subroutines • Specifica di una subroutine SUBROUTINE nome_subroutine (lista_argomenti) sezione dichiarativa sezione esecutiva RETURN END SUBROUTINE [nome_subroutine] • Invocazione di una subroutine nel proramma principale CALL nome_subroutine (lista_argomenti)
Subroutines (cont.) • I parametri di lista_argomenti nella dichiarazione sono detti parametri formali (o fittizi) • I parametri di lista_argomenti nella chiamata sono detti paramentri attuali (o effettivi) • I parametri attuali devono corrispondere ai parametri formali (o fittizi). • Il controllo torna all’istruzione che segue la CALL dopo l’istruzione RETURN • Le variabile usate all’interno della Subroutine sono dette variabili locali
Calcolo Ipotenusa SUBROUTINE calc_ipotenusa(lato_1, lato_2, ipotenusa) ! scopo: calcolare l’ipotenusa di un triangolo rettangolo date le ! lunghezza dei due cateti IMPLICIT NONE REAL, INTENT(IN) :: lato_1 !lunghezza primo cateto REAL, INTENT(IN) :: lato_2 !lunghezza secondo cateto REAL, INTENT(OUT) :: ipotenusa !lunghezza ipotenusa !Dichiara le variabili locali REAL :: temp !Calcolo ipotenusa temp = lato_1**2 + lato_2**2 ipotenusa = SQRT(temp) RETURN END SUBROUTINE calc_ipotenusa
Calcolo Ipotenusa (cont.) ! File prova_ipotenusa.for Program prova_ipotenusa !Scopo: Programma per provare la Subroutine calc_ipotenusa IMPLICIT NONE REAL :: c1 !Lunghezza primo cateto REAL :: c2 !Lunghezza secondo cateto REAL :: ipot !Lunghezza ipotenusa WRITE (*,*) 'Inserisci la lunghezza del primo cateto: ' READ (*,*) c1 WRITE (*,*) 'Inserisci la lunghezza del secondo cateto: ' READ (*,*) c2 CALL calc_ipotenusa (c1, c2, ipot) WRITE(*,*) 'La lunghezza dell''ipotenusa e'':', ipot STOP END PROGRAM prova_ipotenusa
Commenti: • I nomi dei parametri attuali non sono necessariamente uguali ai nomi dei parametri formali • I tipi dei parametri formali devono corrispondere uno ad uno ai tipi dei parametri attuali • INTENT (IN): Il parametro formale è usato solo per passare i dati di input alla Subroutine • INTENT (OUT): Il parametro formale è usato solo per passare i dati di output alla Subroutine • INTENT (IN OUT): Il parametro formale è usato per passare i dati di input e output alla Subroutine USARE CON CAUTELA!!
Condivisione di Procedure • Le procedure sono contenute in un modulo che verrà indicato nelle unità di programma che le utilizzano • Il modulo ed il programma sono compilati separatamente MODULE mie_sub CONTAINS SUBROUTINE sub1 (a,b,c) ……… END SUBROUTINE sub1 SUBROUTINE sub2 (a,b,c) ……… END SUBROUTINE sub2 END MODULE mie_sub
Condivisione di Procedure (cont.) PROGRAM prog_main USE mie_sub IMPLICITE NONE CALL sub1 (x,y,z) END PROGRAM prog_main
Stampa di Figure ! File: figure3.for ! Scopo: Definizione ed uso di SUBROUTINE: ! - con argomenti (1) ! - con costanti e variabili locali MODULE modulo_stampe_3 ! Questo modulo contiene la definizione di procedure per la stampa ! di figure e messaggi CONTAINS SUBROUTINE stampa_triangolo(dim) ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE ! DICHIARAZIONE ARGOMENTI FITTIZI INTEGER, INTENT(IN) :: dim ! lunghezza del lato !DICHIARAZIONE COSTANTI E VARIABILI LOCALI INTEGER, PARAMETER :: max_lung = 25 INTEGER :: i ! indice del ciclo CHARACTER(max_lung) :: linea ! linea da stampare
Stampa di Figure (cont.) ! *** SEZIONE ESECUTIVA *** ! DO i = 1, max_lung linea(i:i) = ' ' END DO DO i = 1, dim linea(i:i) = '*' WRITE (*,*) linea END DO RETURN END SUBROUTINE stampa_triangolo
Stampa di Figure (cont.) SUBROUTINE stampa_quadrato(dim) IMPLICIT NONE ! DICHIARAZIONE ARGOMENTI FITTIZI INTEGER, INTENT(IN) :: dim ! lunghezza del lato ! DICHIARAZIONE COSTANTI E VARIABILI LOCALI INTEGER, PARAMETER :: max_lung = 25 INTEGER :: i ! indice del ciclo CHARACTER(max_lung) :: linea ! linea da stampare DO i = 1, max_lung linea(i:i) = ' ' END DO DO i = 1, dim linea(i:i) = '*' END DO DO i = 1, dim WRITE (*,*) linea END DO RETURN END SUBROUTINE stampa_quadrato END MODULE modulo_stampe_3
Stampa di Figure (cont.) PROGRAM stampa_figure_3 !E' possibile scegliere la forma e la dimensione ! *** SEZIONE DICHIARATIVA *** ! USE modulo_stampe_3 IMPLICIT NONE CHARACTER(1) :: ch ! serve per il dialogo con l'utente INTEGER :: dimensione ! serve per l'acquisizione della dimensione ! *** SEZIONE ESECUTIVA *** ! DO WRITE (*,*) '*** IMMETTI UN CARATTERE A SCELTA FRA I SEGUENTI ***' WRITE (*,*) '***** T: stampa un triangolo' WRITE (*,*) '***** Q: stampa un quadrato' WRITE (*,*) '***** F: per terminare il programma' WRITE (*,*) READ (*,*) ch IF (ch == 'q' .OR. ch == 'Q' .OR. ch == 't' .OR. ch == 'T') THEN WRITE (*,*) 'Di che dimensione? ' READ (*,*) dimensione END IF
Stampa di Figure (cont.) SELECT CASE (ch) CASE ('T','t') CALL stampa_triangolo(dimensione) CASE ('Q','q') CALL stampa_quadrato(dimensione) END SELECT IF (ch == 'f' .OR. ch == 'F') EXIT END DO STOP END PROGRAM stampa_figure_3
Funzioni • Procedure che svolgono delle funzioni particolari non presenti tra le funzioni intrinseche (SIN(x), INT(x), etc…) • I parametri indicano i valori di input su cui calcolare le funzioni. • Occorre dichiarare nella funzione una variabile con stesso nome della funzione che definisce il tipo del risultato. • Il risultato della funzione è assegnato al nome della variabile • La funzione è utilizzabile in espressioni delle stesso tipo. • E’ preferibile non modificare all’interno di una funzione i parametri di input che vengono tutti definiti come INTENT (IN) • Modifiche ai parametri di input sono detti effetti collaterali (side effects)
Funzioni (cont.) FUNCTION nome (lista argomenti) sezione dichiarativa tipo :: nome sezione esecutiva nome = espressione RETURN END FUNCTION nome
Calcolo di un polinomio ! File: test_quadf.for ! Scopo: Definizione ed uso di FUNCTION MODULE modulo_quadf ! Questo modulo contiene la function quadf() CONTAINS FUNCTION quadf (x,a,b,c) !calcola un polinomio del tipo f(x)= a*x**2+b*x+c IMPLICIT NONE !Dichiara gli argomenti REAL :: quadf REAL, INTENT(IN) :: x ! Valore della variabile REAL, INTENT(IN) :: a, b, c ! Coefficienti del polinomio quadf = a*x**2+b*x+c RETURN END FUNCTION quadf END MODULE modulo_quadf
Calcolo di un polinomio(cont.) PROGRAM test_quadf !Scopo: provare la funzione quadf ! *** SEZIONE DICHIARATIVA *** ! USE modulo_quadf IMPLICIT NONE REAL :: a, b, c, x !Dati di input ! *** SEZIONE ESECUTIVA *** ! WRITE(*,*) 'Inserisci i coefficienti a, b, c: ' READ(*,*) a, b, c WRITE(*,*) 'Valore in cui valutare il polinomio: ' READ(*,*) x WRITE(*,*) 'quadf(', x, ') =', quadf(x,a,b,c) STOP END PROGRAM test_quadf
Condivisione di dati • I moduli permettono anche la condivisione di dati tra diverse unità di programma. • I dati sono accessibili a tutte le unità di programma che usano un determinato modulo ed alle procedure definite nello stesso modulo. • All’interno di un modulo si possono includere sia dati che procedure che operano sui dati. • E’ possibile imporre con l’istruzione SAVE che i valori dei dati non siano modificati tra l’esecuzione di due procedure.
Modulo Contatore ! File: counter.for MODULE counter_mod ! Questo modulo realizza un MODULO per un contatore intero IMPLICIT NONE INTEGER :: cont ! Variabile condivisa CONTAINS SUBROUTINE init() IMPLICIT NONE cont = 0 RETURN END SUBROUTINE init
Modulo Contatore (cont.) SUBROUTINE incrementa() IMPLICIT NONE cont = cont + 1 RETURN END SUBROUTINE incrementa FUNCTION valore() IMPLICIT NONE INTEGER :: valore valore = cont RETURN END FUNCTION valore END MODULE counter_mod !================================================================ PROGRAM counter USE counter_mod IMPLICIT NONE CHARACTER(1) :: ch
Modulo Contatore (cont.) DO WRITE (*,*) '*** IMMETTI UN CARATTERE A SCELTA FRA I SEGUENTI ***' WRITE (*,*) '***** A: azzera il contatore' WRITE (*,*) '***** I: incrementa il contatore' WRITE (*,*) '***** V: visualizza il contatore' WRITE (*,*) '***** F: per terminare il programma ' READ (*,*) ch SELECT CASE (ch) CASE ('A','a') CALL init() CASE ('I','i') CALL incrementa() CASE ('V','v') WRITE(*,*) valore() END SELECT IF (ch == 'f' .OR. ch == 'F') EXIT END DO STOP END PROGRAM counter
Avvertenze per Elf 90 • Subroutine e funzioni devono essere necessariamente definite all'interno di un MODULE • Una dichiarazione del tipo INTEGER FUNCTION nome_funzione (x) non viene compilata, e va sostituita con FUNCTION nome_funzione(x) INTEGER :: nome_funzione • Il tipo di una funzione non deve essere ridichiarata nell'unità di programma che la usa. • La clausola INTENT è obbligatoria per tutti gli argomenti passati ad un'unità di programma.
Compilazione di Procedure e Funzioni • Compilare semparatamente i file contenenti i Module e il file contenente il Programma principale, es: main.for • Collegare i file oggetto con l’istruzione: > elf90 main.obj • Eseguire il programma digitando: > main