Sottoprogrammi in Fortran Paolo Bison Fondamenti di Informatica A.A. 2007/08 Università di Padova Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.1 Elementi sintattici modulo unità di programma contenente definizioni di user-defined types, variabili e sottoprogrammi compilazione separata visibilità degli elementi dichiarati in un modulo PUBLIC elementi accessibili da altri moduli PRIVATE elementi condivisi solamente tra gli elementi del modulo sottoprogrammi subroutines (procedure) functions (funzioni) Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.2 Definizione di modulo sintassi R1104x is R1104 is R1104z is or or or R212 is R213 is or module private-module private-module MODULE module-name [ use-stmt ] ... [ PRIVATE ] [ module-entity-def ] ... [ module-subprogram-part ] END MODULE module-name module-entity-def [ derived-type-def ] [ other-type-declaration-stmt ] [ module-procedure-interface-block ] [ external-procedure-interface-block ] module-subprogram-part CONTAINS module-subprogram [ module-subprogram ] ... module-subprogram function-subprogram subroutine-subprogram Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.3 Visibilità degli identificatori per tutti gli elementi si deve dichiarare se sono PRIVATE o PUBLIC attributo nella dichiarazione R511 is or access-spec PUBLIC PRIVATE integer, private :: y,k,z real, public :: t,m definizione mediante un access-stmt R522 is access-stmt access-spec [ :: access-id-list ] public :: xx,yy private :: lc, high senza lista definisce accesso di default (Fortran 90/95) Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.4 Istruzione USE definisce da quali moduli si importa gli elementi di tipo PUBLIC R1107 use-stmt is USE module-name [ , rename-list ] R1108 rename is local-name => use-name Constraint:A module-name shall appear in at most one USE statement in a scoping unit. Constraint:A module shall not be made accessible by more than one use statement in a scoping unit. Constraint:The module shall appear in a previously processed program unit. Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.5 Campo di validità per gli elementi PRIVATE il modulo per gli elementi PUBLIC il modulo + altri moduli/programmi che dichiarino di utilizzare tale modulo. Quest’ultimi possono ridefinire gli identificatori dichiarati nei moduli che usano solo se li rinominano. con la rename-list Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.6 moduli.f90 ! ! moduli.f90 ! module modA integer,public :: k=10 real, public :: x=5.0 integer,private :: l=-100 end module modA module modB integer,public :: k=20 real,public :: y=20.9 integer,private :: l=99 end module modB Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.7 moduli.f90 module modC use modA private integer,public :: l=55 real,private :: y=-8.9 end module modC program moduli use modA,pippo=>x use modB use modC integer :: m,n integer :: x=-333 ! errore se non ci fosse pippo=>x print *,x,y,l ! print *,k ! errore: k dichiarato sia in modA che in modB end program moduli Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.8 Definizione di sottoprogramma sintassi R1216 is function-subprogram function-stmt specification-part [ execution-part ] end-function-stmt R1221 subroutine-subprogram is subroutine-stmt [ specification-part ] [ execution-part ] end-subroutine-stmt R1221v specification-part is [ use-stmt ] ... [ dummy-declaration-stmt] ... [ result-type-declaration-stmt ] [ other-type-declaration-stmt ] ... R1217 function-stmt is [ RECURSIVE ] FUNCTION function-name ([ dummy-arg-name-list ]) RESULT (result-name) R1220 end-function-stmt is END FUNCTION function-name R1222 subroutine-stmt is [ RECURSIVE ] SUBROUTINE subroutine-name ( [ dummy-arg-list ] ) R1224 end-subroutine-stmt is END SUBROUTINE subroutine-name Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.9 Parametri formali dummy-arg-name-list lista dei parametri formali (identificatori separati da virgola) subroutine (x,y,z,c) dummy-declaration-stmt dichiarazioni di tipo per i parametri formali (dummy) presenti nella dummy-arg-name-list real :: x,y,z character :: c Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.10 Attributi dei parametri formali intent ( intent-spec ) indica l’uso inteso per il parametro formale con i seguenti valori di intent-spec: in il parametro è utilizzato per fornire dati al chiamato out il parametro è utilizzato per ritornare dati al chiamante ed è indefinto alla chiamata inout il parametro è utilizzato per passare dati in entrambi i sensi optional può non esserci il corrispondente parametro attuale nella chiamata al sottoprogramma; in tal caso il valore è indefinito funzione intrinseca present(par-name) per vedere se il parametro è presente Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.11 Attivazione sottoprogrammi sintassi R1210 function-reference is function-name ( [ actual-arg-spec-list ] ) R1211 call-stmt is CALL subroutine-name ( [ actual-arg-spec-list ] ) R1212 actual-arg-spec is [ keyword = ] actual-arg R1213 keyword is dummy-arg-name R1214 actual-arg is expr or variable or subprogram-name Constraint: The keyword = may be omitted from an actual-arg-spec only if the keyword = has been omitted from each preceding actual-arg-spec in the argument list. Constraint: A procedure-name actual-arg shall not be the name of an intrinsic function. Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.12 param.f90 ! param.f90 ! esempio di passaggio di parametri module modA public :: subA contains subroutine subA(i,k,l,m) integer,intent(in) :: i,k integer,intent(in),optional :: l,m print *,"-------------" print *,"i",i,"k",k if (present(l)) then print *,"l",l end if if (present(m)) then print *,"m",m end if end subroutine subA end module modA Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.13 param.f90 program moduli use modA call subA(5,3) call subA(k=8,i=-4) call subA(1,2,3) call subA(1,2,3,4) call subA(1,2,m=3) end program moduli Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.14 Valore di ritorno per le funzioni dichiarazione del result-name nella result-type-declaration-stmt function somma_funct(x,y) result(z) integer, intent(in) :: x,y integer :: z sconsigliabile avere side-effects nelle funzioni (vietati in F) Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.15 modulo_somma.f90 ! modulo_somma.f90 ! somma tra due interi realizzata sia con ! una subroutine sia con una function module somma public :: somma_subrt,somma_funct contains subroutine somma_subrt(x,y,z) integer, intent(in) :: x,y integer, intent(out) :: z z=x+y end subroutine somma_subrt function somma_funct(x,y) result(z) integer, intent(in) :: x,y integer :: z z=x+y end function somma_funct end module somma Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.16 modulo_somma.f90 program modulo_somma use somma integer ::k,l,t read *,k,l call somma_subrt(k,l,t) print *,t print *,somma_funct(k,l) end program modulo_somma Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.17 side_effects.f90 module strange public :: fun,sub integer, public :: k contains function fun() result(ris) real :: ris k=3*k ris=5 end function fun end module strange program side_effects use strange k=3 print *,k+fun()+k k=3 print *,k+k+fun() end program side_effects Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.18 Terminazione dei sottoprogrammi fine logica end subroutine / end function istruzione return sintassi R1226 is return-stmt RETURN termina l’esecuzione del sottoprogramma Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.19 return.f90 module test public :: test_n contains function test_n(n) result(f) ! ritorna .FALSE. se n<=0 o somma di tutti ! i numeri tra 1 e n e’ dispari, .TRUE. altrimenti integer,intent(in) :: n logical :: f; integer :: somma,i f=n>0; if (.not. f) then; return; end if somma=0; do i=1,n; somma=somma+i; end do f=modulo(somma,2)==0 end function test_n end module test program main use test print *,test_n(6); print *,test_n(4) print *,test_n(7); print *,test_n(-15) print *,test_n(0) end program main Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.20 Variabili locali Horribile Visu modalità di gestione non definita nelle specifiche del linguaggio attributo save forza attivazione/disattivazione dell’associazione corrispondente save implicito dichiarazione variabile locale con inizializzazione Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.21 local_var.f90 ! local_var.f90 ! module somma public :: media,devstd contains function media(n) result(m) integer,intent(in) :: n real :: m; integer :: somma,i somma=0; do i=1,n; somma=somma+i; end do m=somma/n end function media function devstd(n) result(sigma) integer,intent(in) :: n real :: sigma integer :: i; real :: somma=0,m m=media(n); do i=1,n; somma=somma+(i-m)**2; end do sigma=sqrt(somma/n) end function devstd end module somma Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.22 local_var.f90 program local_var use somma print *,media(100) print *,devstd(100) end program local_var Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.23 Stringhe/array come parametri stringhe specificazione (len = *) nella dichiarazione del parametro formale array ulteriori parametri il cui valore da la dimensione subroutine calc(data_array,n,m)} integer,intent(in) :: n,m real,dimension(n,m),intent(inout) :: data_array} uso di : per ogni dimensione subroutine calc(data_array) real,dimension(:,:),intent(inout) :: data_array} funzioni intrinseche: lbound(arr,dim) ubound(arr,dim) size(arr,dim) Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.24 param_array.f90 ! param_array.f90 ! esempio di passaggio di parametri module array public :: subA contains subroutine subA(arr_in,arr_out) integer,dimension(:,:),intent(in) :: arr_in integer,dimension(:,:),intent(out) :: arr_out integer :: k,l if ((size(arr_in,1)/=size(arr_out,1)) .or. (size(arr_in,2)/=size(arr_out,2))) then print *,"array differenti" do k=lbound(arr_out,1),ubound(arr_out,1) do l=lbound(arr_out,2),ubound(arr_out,2) arr_out=0 end do end do return end if arr_out=3*arr_in end subroutine subA end module array Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.25 param_array.f90 program param_array use array integer,dimension(2,3) :: arrA, arrB integer,dimension(3,3) :: arrC arrA=reshape((/1,-1,3,-2,5,4/),(/2,3/)) call subA(arrA,arrB) print *,arrA print *,arrB call subA(arrA,arrC) print *,arrC end program param_array Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.26 Array automatici array locali le cui dimensioni sono specificate con espressioni in cui possono apparire i parametri integer,dimension(n+1,m) :: dati locali creazione/distruzione dell’associazione non è possibile la loro inizializzazione nella dichiarazione Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.27 Passaggio di subroutine e/o function definizione del nome, dei parametri formali e dell’eventuale valore di ritorno in un blocco INTERFACE R1202 is R1205 is or dummy-procedure-interface-block INTERFACE interface-body [ interface-body ] ... END INTERFACE interface-body function-stmt [ specification-part ] end-function-stmt subroutine-stmt [ specification-part ] end-subroutine-stmt Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.28 func_graph.f90 ! func_graph.f90 ! rappresentazione grafica di una funzione module graph public :: draw_func contains subroutine draw_func(func) interface function func(x) result(y) real,intent(in) :: x real :: y end function func end interface real, parameter :: d = 0.4 ! 1/4, 4 campioni ! nell’intervallo [x,x+1] integer, parameter :: s = 10 ! 10 caratteri di ampiezza ! per l’intervallo [y,y+1] integer, parameter :: h = s+2 ! massimo valore positivo ! asse x integer, parameter :: lim =80 ! numero di campionamenti integer :: i, k logical, dimension(-h:h,0:lim-1) :: grid character (len=lim) :: linea Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.29 func_graph.f90 ! ! inizializzazione ! do i=-h,h do k=0,lim-1 grid(i,k)=.false. end do end do ! ! calcolo campioni ! do k=0,lim-1 grid(nint(s*func(d*k)),k)=.true. end do Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.30 func_graph.f90 ! ! visualizzazione ! do i=h,-h,-1 linea = "" do k=0,lim-1 if (grid(i,k)) then linea(k+1:k+1) ="*" else if (i==0) then linea(k+1:k+1) = "-" else linea(k+1:k+1) = " " end if end do print *,linea end do end subroutine draw_func end module graph Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.31 func_graph.f90 module functions public :: f_sin,f_sinc contains function f_sin(x) result(y) real,intent(in) :: x real :: y y=sin(x) end function f_sin function f_sinc(x) result(y) real,intent(in) :: x real :: y if (x==0.0) then y=1.0 else y=sin(x)/x end if end function f_sinc end module functions Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.32 func_graph.f90 program modulo_graph use graph use functions call draw_func(f_sin) print * call draw_func(f_sinc) end program modulo_graph Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.33 Gestione errori assegnazione di particolari valori ad elementi visibili all’esterno del sottoprogramma: variabile non locale parametro di tipo out o inout Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.34 gest_errori.f90 module div integer,public :: err ! /= 0 segnala un errore public :: div1,div2 contains subroutine div1(x,y,z) integer, intent(in) :: x,y integer, intent(out) :: z err=0 if (y==0) then; err=1 else; z=x/y end if end subroutine div1 subroutine div2(x,y,z,err) integer, intent(in) :: x,y integer, intent(out) :: z,err err=0 if (y==0) then; err=1 else; z=x/y end if end subroutine div2 end module div Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.35 gest_errori.f90 program main use div integer ::k,l,t,errore read *,k,l call div1(k,l,t) if (err/=0) then; print *,"errore" else; print *,t end if call div2(k,l,t,errore) if (errore/=0) then; print *,"errore" else; print *,t end if end program main Sottoprogrammi in Fortran, Paolo Bison, FI07, 2008-01-08 – p.36