Fortran: la sintassi
Sottoprogrammi
Appena i programmi crescono in complessita', puo' risultare utile
spezzare l' elaborazione in sottoproblemi e associare alle istruzioni
che risolvono ciascun sottoproblema una unita' di
(sotto)programma indipendente.
Il Fortran mette a disposizione del programmatore due tipi principali
di sottoprogrammi: le function e
le subroutine.
La principale differenza tra i due tipi di sottoprogrammi e' nella
sintassi relativa all' utilizzo e dichiarazione.
Una function corrisponde da vicino al concetto matematico di funzione:
ad un certo numero di argomenti, ciascuno col suo valore, corrisponde
un solo valore della funzione. Il nome della funzione (es f(x,y) ) puo' essere usato in un'
espressione come sinonimo del valore associato dalla funzione f al valore x e y delle variabili
indipendenti. P.es. q = 2.5 + t*sqrt(3*f(x,y)+z).
Tra i diversi modi con cui si possono dichiarare e usare i
sottoprogrammi in Fortran, in questo corso selezioniamo solo la
modalita' attraverso i moduli.
I moduli sono dei "contenitori" di software Fortran in grado di
contenere: dichiarazioni di tipi dati, variabili, costanti e
sottoprogrammi. Lo schema di uilizzo dei moduli e' indicato nell'
esempio seguente:
module nome_mod
real, parameter :: pi = acos(-1.0)
contains
function area(r) result(s)
real, intent(in) :: r
real :: s
s = pi*r**2
end function area
end module nome_mod
program pippo
use nome_mod
real :: x, circ
read*,x
circ = 2*pi*x
print*, circ, area(x)
end program pippo
Nell' esempio, e' stato dichiarato un modulo che contiene una costante
simbolica di tipo real (l' attributo parameter fa si' che il
valore assegnato a pi non possa mai essere modificato nel programma) e
una function (area) che ad un argomento di tipo real fa corrispondere i
prodotto del quadrato dello stesso per la costante pi.
Per poter accedere alla costante pi
e alla function area il
programma chiamante (pippo) deve "utilizzare" il modulo
(istruzione use nome_mod), la
cui posizione deve obbligatoriamente precedere qualsiasi altra
istruzione non eseguibile.
Da notare anche la completa indipendenza dei nomi all' interno della
function (es. r) da quello dell' argomento con cui la
function viene chiamata (x).
Lo spazio delle variabili della function e' completamente
indipendente da quello del/dei programa/i che utiizzano la
function. L' unica comunicazione tra i due mondi avviene
attraverso gli argomenti ed il valore ritornato dalla function al
programma che la utilizza.
Da notare l' utiizzo dell' attributo intent(in) per gli
argomenti della function.
Le subroutine si impiegano generalmente quando non e'
previsto un volore di ritorno oppure quando si vogliono modificare
piu' variabili.
La dichiarazione di una subroutine (da inserire in un modulo come nel
caso delle function) e':
subroutine nome_sub( lista argomenti )
implicit none
! dichiarazione degli argomenti con attributo
! intent(in) per argomenti in solo ingresso (non modificabili dala subroutine)
! intent(out) per argomenti in sola uscita (cui viene assegnato un valore nella subroutine)
! intent(inout) per argomenti che vengono modificati
! istruzioni subroutine
end subroutine nome_sub
In pratica, tutte le variabili con attributo intent(in) possono stare solo a destra del
segno di assegnazione (=).
Tutte quelle con intent(out)
possno solo stare a sinistra dell' assegnazione.
Tutte quelle con intent(inout)
possono stare sia a destra sia a sinistra nelle assegnazioni.
Se non ci sono argomenti si omettono anche le parentesi dopo il nome
della suboutine.
Per utilizzare la subroutine si ricorre al' istruzione
call nome_sub(lista argomenti)
Per esempio, se vogliamo definire una subroutine senza argomenti che
scrive qualcosa su schermo potremo avere un programma cosi'
organizzato:
module banner
contains
subroutine scrivi_istruzioni
implicit none
print*,"Questo programma serve solo come esempio."
print*,"Non verra' generato nessun output a parte questa scritta."
end subroutine scrivi_istruzioni
end module banner
program esempio
use banner
implicit none
call scrivi_istruzione
end program esempio
Un programma piu' complesso che usa una subroutine che , dato il raggio
di un cerchio ne calcola l' area e la lunghezza dela circonferenza e'
il seguente:
module circolare
real, parameter :: pi = acos(-1.0)
contains
function area(r) result(s)
real, intent(in) :: r
real :: s
s = pi*r**2
end function area
subroutine calcola_tutto(r,superficie,lunghezza)
implicit none
real,intent(in) :: r
real,intent(out) :: superficie,lunghezza
superficie = area(r)
lunghezza = 2*pi*r
end subroutine calcola_tutto
end module
program test
use circolare
implicit none
real :: raggio, sup, lun
print*," raggio = ?"
read*,raggio
call calcola_tutto(raggio, sup,lun)
print*," area = ",sup
print*," lunghezza = ",lun
end program test