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