From 056f1a8d58b4ad9e64cf8c70e3c9dbd8572235be Mon Sep 17 00:00:00 2001 From: Leonardo Robol Date: Fri, 6 Nov 2009 16:55:43 +0100 Subject: [PATCH] Aggiunto qualche esempio sulle subroutine --- AppFortran.tex | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/AppFortran.tex b/AppFortran.tex index d10872b..6a94abe 100644 --- a/AppFortran.tex +++ b/AppFortran.tex @@ -156,4 +156,88 @@ a quel determinato file sostituendo quell'intero a \lstinline-*-. Questo codice Abbiamo qui introdotto anche la chiamata \lstinline-CLOSE()- che serve appunto per chiudere un file. \`E normalmente buona norma chiudere tutti i file che si aprono e quindi, in programma corposi, conviene sempre scrivere la chiamata ad \lstinline-OPEN()- insieme -alla chiamata \lstinline-CLOSE()- per evitare di dimenticarla. \ No newline at end of file +alla chiamata \lstinline-CLOSE()- per evitare di dimenticarla. + +\section{Subroutine} +Mano a mano che il programma cresce diventerà necessario razionalizzare la disposizione di +funzioni e strutturare meglio il listato. In particolare siamo interessati a scrivere delle +funzioni che si occupino di svolgere un determinato compito in modo che poi possiamo chiamarle +senza preoccuparci (troppo) di come sono implementate. +Quelle che in C si chiamavano funzioni in Fortran si chiamano \emph{subroutine}. La sintassi +per una subroutine assomiglia molto a quella di un programma: +\begin{lstlisting}[frame=tb,caption=Una subroutine] + SUBROUTINE nome(...) + ! [ Dichiarazioni ] + ! [ Corpo della subroutine ] + END SUBROUTINE +\end{lstlisting} +Una particolarità per così dire ``curiosa'' è che le variabili passate alla subroutine dovranno +essere ridichiarate all'interno della stessa perché essa ci possa accedere. Le variabili inoltre +vengono sempre passate per riferimento (quello che succede in C passando per riferimento o quello +che succede in C++ passando una reference) e, per conludere, non c'è un'istruzione di ritorno\footnote{% +O perlomeno, non ne ho mai incontrate. Notare però che programmo in fortran da pochi giorni e quindi.. potrei +scoprirle prossimamente :) }. +Ci saranno quindi variabili di Input e variabili di Output\footnote{So che sono schizzinoso, ma trovo che sia +una cosa \underline{orribile}}, ma tutte insieme nella chiamata della funzione. +Per chiarire le idee, e spiegare i passaggi che mancano, proponiamo un esempio di una funzione che prenda un +numero e lo moltiplichi per due\footnote{che esempio inutile, direte voi\ldots e avete anche ragione ma +in questo momento non mi viene in mente niente di più costruttivo} +\begin{lstlisting}[frame=tb,caption=Un semplice programma che fa uso di subroutine] + ! Questo programma prende in input un numero e lo moltiplica per due; + ! Di per se' e' piuttosto inutile ma mostra come si utilizza una subroutine + ! nell'ambito di un programma + + PROGRAM sub_doppio + + REAL :: x; + ! Leggo dallo standard input x + READ(*,*) x; + + ! Lo moltiplico per due facendo uso della subroutine + CALL doppio(x); + + ! Lo stampo. Atttenzione! La subroutine ha modificato il vero + ! valore di x perche' le ho di fatto passato un puntatore + WRITE(*,*) x; + +! Terminiamo l'esecuzione del programma principale. +END PROGRAM sub_doppio + +SUBROUTINE doppio(x) + REAL :: x; + x = x * 2; +END SUBROUTINE doppio +\end{lstlisting} +Naturalmente si possono fare esempi molto più complessi, e soprattutto più utili. Ad esempio, supponiamo +di implementare la subroutine \lstinline-dotprod- che avevamo pensato parlando del pagerank per fare il prodotto +matrice vettore con una matrice sparsa. Non la riportiamo qui perché è già stata scritta (si veda il Listato~\ref{lst:matrixvec}) +ma commentiamo alcuni fatti: +\begin{itemize} + \item Le keyword \lstinline-INTENT(IN)- e \lstinline-INTENT(OUT)- servono per l'appunto a specificare se una variabile + è da considerarsi di input o di output. Questo di fatto non cambia nulla, a parte che il compilatore ci avviserà + se tentiamo di modificare variabili di input; + \item La \lstinline-SUBROUTINE- può venir scritta in un file separato e poi linkata insieme al file eseguibile che + la richiama. Spiegheremo meglio questo concetto con un esempio; +\end{itemize} + +Supponiamo di avere scritto la subroutine in un file di nome \verb-dotprod.f90-, e di aver successivamente +scritto un listato \verb-matrici.f90- in cui compaia l'istruzione \lstinline-CALL dotprod(...)-. Sarebbe tedioso +dover copiare il contenuto del file \verb-dotprod.f90- all'interno di \verb-matrici.f90- per poi compilarlo. +In effetti esiste un metodo più pratico per agire. +\begin{enumerate} + \item Compilare i file sorgenti separatamente, senza creare l'eseguibile ma solamente i \emph{file oggetto} + che contengono la versione compilata del listato, senza che le referenze siano stare risolto. Questo significa + che all'interno del file oggetto associato a \verb-matrici.f90- ci sarà una chiamata ad una \lstinline-dotprod()- + senza che abbia la minima idea di dove andare a prenderla; questa operazione si realizza su Linux con \verb-f95- in questo + modo: \\ + \verb+# f95 -c dotprod.f90 matrici.f90+ + + \item Il secondo passo consiste nel creare un eseguibile unico con le dipendenze risolte, ovvero in cui ci sia + la chiamata a \lstinline-dotprod()- ma questa volta sia chiaro dove poterla trovare\footnote{sono conscio che questa + spiegazione non è molto chiara. Cercherò di migliorarla}; questo compito viene eseguito dal \emph{linker} che, su Linux, + fa ancora parte di \verb-f95-\footnote{forse si portebbe discutere sulla correttezza di questa affermazione, in ogni caso noi + daremo il comando f95 per eseguire l'operazione. Quello che poi lui faccia davvero, compreso chiamare altri programmi, + per il momento non è affar nostro}; il comando è il seguente: \\ + \verb+# f95 -o matrici matrici.o dotprod.o+ +\end{enumerate} + -- 2.1.4