Installazione di un compilatore gfortran - nau.unimore.it · Installazione di un compilatore Per...
Transcript of Installazione di un compilatore gfortran - nau.unimore.it · Installazione di un compilatore Per...
Installazione di un compilatore
Per installare un compilatore Fortran, ad esempio il compilatore gfortran, si procede come segue.Sui computer su cui e installato il
sistema operativo Unix/Linux o per i computer MAC di Apple: collegarsi al sito web
gcc.gnu.org/wiki/GFortranBinaries
e scegliere (“cliccando”) la versione del compilatore gfortran per il sistema operativo adottato allesezioni MacOS e GNU/Linux.
Ad esempio, per il sistema operativo MacOS scegliere una delle versioni del compilatore in base allaversione del sistema operativo. Per le versioni piu recenti scegliere Yosemite.
Perche il compilatore possa essere eseguito e necessario che sul computer sia presente l’applicazioneXcode. Se non e presente (o se non sono installati i command line tools), “cliccare” su detailedinstructions can be found here per un’installazione guidata (scaricare da AppStore il file Xcode, poi“aprire” Xcode, “andare” in preferenze poi in downloads e poi in command line tools e “cliccare” suinstall).
sistema operativo Windows: collegarsi al sito web
www.equation.com/servlet/equation.cmd?fa=fortran
e scegliere (“cliccando”) gcc-5.1.0-64.exe oppure gcc-5.1.0-32.exe se il tipo di sistema e a 64 oa 32 bit (per Windows7, si veda: pannello di controllo > sistema e sicurezza > sistema).
Il compilatore gfortran compila file scritti in Fortran77, 90, 95 e 2003 con estensione .fIl compilatore gfortran ha, ad esempio, le opzioni:
-c per compilare senza creare i collegamenti (crea il file oggetto ma non il file eseguibile);
-o per rinominare il file eseguibile
Su Unix/Linux di default il file eseguibile si chiama a.out mentre su windows a.exe
Ad esempio, si crea un file Fortran 77 oppure Fortran 90 (95, 2003) oppure scritto in modo misto cheviene salvato con il nome nome.f (la scrittura del file avviene con l’esecuzione di un editor, ad esempio:vi, wordpad, edit, winedt, ...).Per l’esecuzione del compilatore (compilazione del programma), si “apre” il prompt dei comandi e, daldirettorio dove e presente il file nome.f, si scrive nella linea dei comandi
gfortran -o nome nome.f
e viene creato il file eseguibile (codice tradotto in linguaggio macchina con la libreria del linguaggioinclusa) che si chiama nome
Si esegue allora il file eseguibile, digitando dalla linea dei comandi
nome
Su Unix/Linux l’esecuzione avviene digitando ./nome
Se ad esempio, in un file salvato con il nome file1.f e scritto un codice che contiene il programmaprincipale ed alcuni sottoprogrammi chiamati dal programma principale stesso e, in un altro file, che sichiama file2.f sono scritti altri sottoprogrammi richiamati comunque dal programma principale (che escritto in file1.f), allora la compilazione deve creare un unico file eseguibile contenente le traduzioni inlinguaggio macchina di entrambi i file file1.f e file2.f.La creazione di questo file eseguibile, chiamato ad esempio file1, avviene con il comando
1
gfortran -o file1 file1.f file2.f
Se e presente un modulo (sia di dati o di sottoprogrammi o di dati e di sottoprogrammi insieme) chee stato salvato nel file denominato miomodulo.f, si deve prima compilare il modulo con l’opzione -cmediante il comando (dalla linea dei comandi, nel direttorio che comprende il file miomodulo.f)
gfortran -c miomodulo.f
e poi, si devono compilare i file contenenti il programma principale e i sottoprogrammi che usano ilmodulo memorizzato nel file miomodulo.f. Ad esempio se il file fileXX.f usa il modulo memorizzatonel file miomodulo.f, dopo il comando di compilazione del modulo si deve eseguire il comando
gfortran -o fileXX fileXX.f miomodulo.f
che crea il file eseguibile fileXX che usa il modulo scritto nel file miomodulo.f. Eseguire dunque
fileXX
Due testi di riferimento per il linguaggio Fortran, rispettivamente nelle versioni 77 e 90/95 sono, adesempio:
• Comincioli V.: Fortran 77: Introduzione e Applicazioni Numeriche, McGraw–Hill, Milano, 1991.
• Chapman S.J.: Fortran 90/95: Guida alla Programmazione, Seconda Edizione, McGraw–Hill, Mi-lano, 2004.
2
LINGUAGGIO DI PROGRAMMAZIONE
FORTRAN
FORTRAN = FORmula TRANSlation
• John Backus sviluppa il linguaggio Fortran per il calcolatore IBM 704 (1954).
• Linguaggio di programmazione vicino alla notazione matematica =⇒ Linguaggio del Calcolo Sci-entifico.
• Versioni Fortran: Fortran I (1957), Fortran II e Fortran III (1958), Fortran IV (1961), Fortran66 (1966), Fortran 77 (1977), Fortran 90 (1990), Fortran 95 (1995), Fortran 2003 (2003), Fortran2008 (2008).
• Programma Fortran composto da un programma principale (detto Main) e da uno o piu sottopro-grammi (Function e/o Subroutine).
• Il programma principale e ciascun sottoprogramma e detto unita di programma.
• Il programma principale con (o senza) i sottoprogrammi richiamati dal programma principale, econtenuto in un file identificato da un nome.estensione.
• il compilatore Fortran riconosce come file scritti in linguaggio Fortran (e dunque da tradurre inlinguaggio macchina) quelli con una particolare estensione. Generalmente i compilatori Fortranriconoscono, come file Fortran nelle diverse versioni, i file con estensione .f .F .for .FOR .f77 .F77.f90 .F90 .f95 .F95 .f03 .F03 .f08 .F08
• Tutti o alcuni sottoprogrammi richiamati da un programma principale possono essere scritti in unfile Fortran che viene compilato insieme al file Fortran che contiene il programma principale percreare un unico eseguibile contenente il programma principale e i sottoprogrammi.
• I compilatori delle versioni 90–2008 del Fortran devono compilare codici in cui sono presenti tutteo alcune istruzioni scritte in Fortran 77.
Nel seguito si indica con Fortran le regole e le istruzioni comuni alle versioni Fortran 77 e Fortran90/95/2003; con F77 le istruzioni solo per la versione Fortran 77 e con F90 le istruzioni solo per leversioni Fortran 90/95/2003.
Due testi di riferimento per il linguaggio Fortran, rispettivamente nelle versioni 77 e 90/95 sono, adesempio:
3
• Comincioli V.: Fortran 77: Introduzione e Applicazioni Numeriche, McGraw–Hill, Milano, 1991.
• Chapman S.J.: Fortran 90/95: Guida alla Programmazione, Seconda Edizione, McGraw–Hill, Mi-lano, 2004.
4
Struttura di un programma
Un programma principale in Fortran e strutturato come segue:
program nomeistruzioni dichiarative di variabili e costantiistruzioni eseguibili (statements)end
• program ed end sono parole chiave;
• end e l’istruzione di fine; e obbligatoria e deve essere presente una sola volta in ogni unita diprogramma come ultima istruzione;
• program nome e l’istruzione che assegna al programma un nome simbolico:
– il nome del programma non ha nessuna relazione con il nome del file contenente il programmastesso;
– il nome del programma deve essere diverso dal nome delle variabili, delle costanti e dellefunction presenti nel programma;
– l’istruzione program nome e opzionale;
– in F90: l’istruzione end puo essere sostituita dall’istruzione
end program
oppure daend program nome
Queste due istruzioni rendono obbligatoria l’istruzione program nome.
In Fortran:
• tutte le istruzioni dichiarative devono essere scritte prima della prima istruzione eseguibile;
• le istruzioni eseguibili possono essere etichettate:
– l’etichetta (label) e identificata da una a cinque cifre scritte consecutivamente, la prima diversada 0 (ovvero sono numeri interi da 1 a 99999):
– l’etichetta si ha solo per le istruzioni eseguibili;
– non si possono avere piu istruzioni con la stessa etichetta;
– piu istruzioni possono rimandare (con l’istruzione goto label) ad un’istruzione etichettata;
– etichettare solo le istruzioni necessarie (quelle destinazioni di salti incondizionati);
– l’ordine numerico delle etichette non ha significato (i.e. una istruzione puo essere etichettatacon 10 e quella successiva con 5, quella dopo ancora con 12 e cosı via);
• i nomi di variabili, costanti o del programma:
– devono essere scritti con le lettere dell’alfabeto inglese (maiuscole e minuscole sono viste comelo stesso carattere), le cifre (da 0 a 9) e il carattere (sottolineatura); le lettere e le cifre sichiamano anche caratteri alfanumerici e versioni non recenti di compilatori F77 riconoscono inomi solo costituiti dai caratteri alfanumerici;
– devono iniziare con una lettera;
5
– non possono essere piu lunghi di 31 caratteri (versioni non recenti di compilatori F77 ri-conoscono solo nomi con al massimo 6 caratteri);
– non possono essere uguali a parole chiave;
• nelle istruzioni, non vi e distinzione tra lettere maiuscole e minuscole;
• il carattere di spaziatura (blank) puo essere usato per migliorare la leggibilita di un programma; ilcompilatore ignora il carattere di spaziatura.1
In F77 ogni riga in un’unita di programma deve essere conforme alle seguenti regole di posizione dellacolonna:
• colonne 1–5: riservate alle etichette;
• colonna 1: la presenza dei caratteri c, C oppure * indica che la riga e una riga di commento; questariga non viene processata dal compilatore;
• colonna 6: la presenza di un carattere (eccetto 0 e la spaziatura) indica che sulla riga c’e la con-tinuazione dell’istruzione della riga precedente. Ovvero la linea di codice e scritta su due righe. Sipuo scrivere una linea di codice su 19 righe al massimo;
• colonne 7–72: riservate alla scrittura delle istruzioni;
• colonne 73–80: qualsiasi carattere scritto viene ignorato. Utile per scrivere commenti o numerarele linee di codice.
In F90:
• l’istruzione puo iniziare da colonna 1 (in poi);
• le etichette possono iniziare da colonna 1 (in poi) e l’istruzione sottointesa dall’etichetta puo iniziaredal carattere subito dopo la fine dell’etichetta;
• il carattere & a fine riga indica che la linea di codice prosegue nella riga successiva;
• su una riga, cio che e scritto dal carattere ! in poi viene ignorato dal compilatore; in generale, da! in poi si scrivono i commenti (questa regola viene anche riconosciuta nei piu recenti compilatoriF77);
• nelle istruzioni dichiarative ed eseguibili il carattere ; (punto e virgola) separa istruzioni scrittesulla stessa riga.
1Ovviamente il carattere di spaziatura non viene ignorato dal compilatore, che anzi segnala errore, se esso e posizionatointernamente a un nome, ad una parola chiave o ad una etichetta.
6
Costanti e Variabili
In Fortran le costanti e le variabili che hanno nome la cui prima lettera e una delle seguenti sei lettere
i j k l m n
sono implicitamente dichiarate intere.Le costanti e le variabili che hanno nome la cui prima lettera non e i,j,k,l,m,n, ovvero tutte le letteredell’alfabeto inglese dalla a alla h e dalla o alla z, sono implicitamente dichiarate reali in precisionesemplice.
Se si vogliono dichiarare costanti e variabili altrimenti, esse devono essere dichiarate esplicitamente.
Costanti
In Fortran le costanti sono identificate da un valore e da un tipo (il tipo del valore).Vi sono costanti numeriche (di tipo intero, reale in precisione semplice, reale in precisione doppia, com-plesso), di tipo carattere o stringa e di tipo logico o booleano. Ad esempio sono:
• costanti intere: 2 -5 21458934;
• le costanti reali in precisione semplice (2, 0.002, 2, 2 · 102, 3 · 105, 2 · 10−4):
2. 0.002 2.0 2.e02 3e+05 2.e-4
• le costanti reali in precisione doppia (4, 3 · 10−90, 0.5 · 10289):4.0d0 3d-90 0.50d289
• costante complessa, ovvero coppia di numeri reali in precisione semplice: (6e-2, 4.03)
• costanti booleane: .true. .false.
• costanti carattere, ovvero stringhe scritte tra apici:
’dato=’ ’il valore e’’=’ ’non c’’e’’’
Nella scrittura di costanti numeriche in Fortran, dopo il carattere e o d si prevedono, rispettivamente,al massimo 3 o 4 cifre. La prima e riservata al segno (opzionale se positivo) e le altre all’esponente delnumero (espresso in base 10) che per i numeri in precisione semplice, ovvero memorizzati su 32 bit, almassimo e 38 mentre per i numeri in precisione doppia, ovvero memorizzati su 64 bit e 308.
In Fortran, nella stringa ’il valore e’’=’, il terzo apice, scritto subito dopo il secondo apice, servead indicare che il secondo apice non e il carattere di fine stringa ma e un carattere da scivere; il quartoapice e il carattere di fine stringa. Il risultato delle stringa e
il valore e’=In F90 le costanti di tipo carattere possono essere racchiuse da doppio apice ". Gli esempi sopra si
scrivono: "dato=", "il valore e’’=", "non c’’e’’". Ovviamente, stringhe che hanno apici di inizio edi fine stringa diversi non sono corrette (e.g., ’dato=").
In Fortran si possono dichiarare costanti con nome.Le istruzioni dichiarative in F77 sono ad esempio:
real pi,eps
integer c
parameter(pi=3.1415, c=200)
parameter(eps=1.e-7)
oppure, sfruttando la dichiarazione implicita del Fortran
parameter(pi=3.1415, ic=200)
parameter(eps=1.e-7)
7
In F90 le stesse istruzioni si scrivono
real, parameter :: pi=3.1415, eps=1.e-7
integer, parameter :: c=200
oppure, sfruttando la dichiarazione implicita del Fortran
parameter :: pi=3.1415, ic=200
parameter :: eps=1.e-7
Si osserva che in F77 le istruzioniparameter(pi=3.1415)
real pi
non sono corrette, in quanto viene assegnato il valore 3.1415 alla variabile pi che viene implicitamentedichiarata intera e, con l’istruzione di dichiarazione successiva, la costante pi viene dichiarata esplicita-mente. Il compilatore segnala una doppia dichiarazione.In Fortran e possibile assegnare il valore ad una costante mediante espressioni aritmetiche, designatoridi funzioni matematiche elementari e mediante l’utilizzo di costanti assegnate in precedenza. Ad esempiosono possibili le istruzioni, rispettivamente in F77 e F90
parameter(pi=4*atan(1)) parameter :: pi=4*atan(1)
parameter(pi2=2*pi) parameter :: pi2=2*pi
parameter(nx=100,nx2=nx*2) parameter :: nx=100,nx2=nx*2
Variabili semplici
In Fortran le variabili semplici si dichiarano implicitamente (come specificato all’inizio) oppure esplicita-mente. Per la dichiarazione esplicita si usano le 6 parole chiave di tipo e si elencano i nomi delle variabiliseparate da una virgola.Ad esempio in F77 e F90 rispettivamente, in una unita di programma, si possono avere le seguentiistruzioni dichiarative:
real a,b real*4 :: a,b
real c real :: c
integer d,it integer :: d,it
double precision r1 real*8 r1
complex z complex :: z
logical z1 logical :: z1
character iniziale character :: iniziale
character*10 prima character(len=10) :: prima, ultima
character ultima*10 character(15) :: id
character*15 id
• In F90 per le variabili di tipo reale in precisione semplice si usa indistintamente la parola chiavereal o real*4 (4 sta per 4 byte). La parola chiave real*4 e comunque riconosciuta anche dai piurecenti compilatori F77.
• In F90 la parola chiave double precision del F77 viene sostituita con real*8 (8 sta per 8 byte).La parola chiave real*8 e comunque riconosciuta anche dai piu recenti compilatori F77.
• In F90 e possibile assegnare variabili intere su 16 bit (2 byte) con l’istruzione dichiarativa2
integer*2 :: x,y
2In F90 e anche possibile impostare la precisione in modo indipendente dal processore mediante le istruzioni kind eselect real kind. Si veda
• Chapman S.J.: Fortran 90/95: Guida alla Programmazione, Seconda Edizione, McGraw–Hill, Milano, 2004.
8
• In F90 per l’assegnazione di variabili, i caratteri :: (due volte due punti) sono opzionali.
• Nell’esempio, le variabili carattere definite sono: una variabile carattere (di nome iniziale) com-posta da un carattere (8 bit), due variabili carattere (di nome prima e ultima) composte da 10caratteri ciascuna e una variabile (di nome id) di 15 caratteri.
• len e una parola chiave che sta per length (lunghezza).
• Nell’esempio, utilizzando la dichiarazione implicita del Fortran, le istruzioni di dichiarazioni dellevariabili reali a, b e c e della variabile intera it si possono omettere.
• In Fortran una variabile deve essere dichiarata una volta sola.
• In Fortran si possono avere piu di una parola chiave per tipo in un’unita di programma. Nell’esempiole parole chiave real e character sono ripetute per dichiarare variabili diverse.
In F90 si puo assegnare il valore (iniziale) di una variabile nell’istruzione di dichiarazione (esplicita). Adesempio se si vuole inizializzare le variabili reali a, b a zero e non la variabile c3 l’istruzione si scrive
real :: a=0, b=0, c
In Fortran e possibile rendere inattiva la dichiarazione implicita inserendo, come prima istruzione di-chiarativa, l’istruzione
implcit none
In tal caso ogni variabile (semplice o con indice) e costante con nome dovra essere dichiarata esplicita-mente.L’istruzione implicit puo essere usata per dichiarare implicitamente alcune variabili. Ad esempio, leistruzioni in F77 e F90 rispettivamente
implicit integer(a) implicit, integer :: a
real a1 real :: a1
producono il risultato che, sono intere tutte le variabili (semplici o con indice) che iniziano per a, adeccezione della variabile semplice a1 che e dichiarata reale in precisione semplice.Ad esempio, per dichiarare implicitamente in doppia precisione il tipo di tutte le variabili (semplici o conindice) che iniziano per le lettere dell’alfabeto inglese dalla a alla d e dalla o alla z e con la lettera g, leistruzioni in F77 e F90 rispettivamente sono
implicit double precision(a-d,g,o-z) implicit, real*8 ::a-d,g,o-z
oppurre “spezzando” l’istruzione, ad esempio
implicit double precision(a-d,o-z) implicit, real*8 ::a-d,o-z
implicit double precision(g) implicit, real*8 ::g
3E una “buona norma” inizializzare a zero tutte le aree di memoria da utilizzare in un codice.
9
Variabili con indice
Le variabili con indice (o array o variabili strutturate) sono un insieme omogeneo e ordinato di dati esono definite mediante la dichiarazione di tipo e di dimensione.
• Quando si dichiara una variabile strutturata il compilatore assegna lo spazio sufficiente per memo-rizzarne tutte le componenti.
• L’allocazione in memoria delle componenti dell’array crea un insieme di locazioni contigue, il cuinumero e definito dalle dichiarazioni di tipo e di dimensione.
La dichiarazione completa (tipo e dimensione) degli array in un programma principale prevede la specificadel tipo e della dimensione. Indicando con tipo1 e tipo2 una parola chiave tra quelle di specifica del tipo(integer, real, ...) come per la dichiarazione di una variabile semplice, in F77 e in F90 la dichiarazionedi variabili con indice si scrive rispettivamente
tipo1 nome1 tipo1, dimension(e1 : e2) :: nome1tipo2 nome2 tipo2, dimension(e3 : e4, e5 : e6) :: nome2dimension nome1(e1:e2),nome2(e3:e4,e5:e6)
dove e1, e2, e3, e4, e5, e6 sono costanti intere o valori interi di espressioni.
• Si ha e1≤e2, e3≤e4 e e5≤e6.
• Se e1 o e3 o e5 sono uguali ad 1, sono opzionali.
Le variabili nome1 e nome2 sono rispettivamente composte da e2–e1+1 e da (e4 –e3+1)· (e6–e5+1)elementi.Se si hanno piu variabili dello stesso tipo (in F77) o dello stesso tipo e stessa dimensione (in F90), questepossono essere elencate nella stessa istruzione dichiarativa separate da virgola.
Si riportano alcuni esempi di specifica di tipo e di dimensione che possono presentarsi nelle istruzionidichiarative di un programma principale:
integer imax integer,parameter::imax=70
parameter(imax=70) real,dimension(100)::a,b
real a, b, x, a1 real,dimension(0:50)::x
real b1 real,dimension(0:imax-1,imax)::a1
integer c real,dimension(10,10)::b1
character*4 car integer,dimension(imax)::c
dimension a(100),x(0:50),c(imax),a1(0:imax-1,imax) character(len=4),dimension(-10,10)::car
dimension b(100),b1(10,10),car(-10:10)
Utilizzando la dichiarazione implicita del Fortran (modificando il nome della variabile intera c in ic),queste stesse istruzioni dichiarative si semplificano in
parameter(imax=70) parameter::imax=70
dimension a(100),x(0:50),a1(0:imax-1,imax) dimension(100)::a,b
character*4 car dimension(0:50)::x
dimension b(100),b1(10,10),car(-10:10) dimension(0:imax-1,imax)::a1
dimension ic(imax) dimension(10,10)::b1
dimension(imax)::ic
character(len=4),dimension(-10,10)::car
Il Fortran permette un’ulteriore semplificazione delle istruzioni dichiarative specificando, nella dichiarazionedi tipo, la dimensione della variabile nel nome. Dunque, queste ultime istruzioni si scrivono
parameter(imax=70) parameter::imax=70
real a(100),x(0:50), a1(0:imax-1,imax) real::a(100),b(100),x(0:50),b1(10,10)
character*4 car(−10 : 10) real::a1(0:imax-1,imax)
real b(100),b1(10,10) integer::ic(imax)
integer ic(imax) character(len=4)::car(-10,10)
10
• In Fortran, come per le variabili semplici, una variabile con indice deve essere dichiarata una voltasola.
• In Fortran, come per le variabili semplici, si possono avere piu di una parola chiave per tipo inun’unita di programma (la parola chiave real nell’esempio).
• In F77 la sequenza di istruzionidimension a(100)
real a
non e corretta; il compilatore segnala una doppia dichiarazione.
• In F90, come per le variabili semplici, per l’assegnazione di variabili con indice, i caratteri :: (duevolte due punti) sono opzionali.
• In F90, come per le variabili semplici, e possibile assegnare valori alle variabili (inizializzare) nelleistruzioni dichiarative. Ad esempio si possono avere le seguenti istruzioni dichiarative
real,dimension(100)::a=0
integer,dimension(0:5)::b=(/0,1,2,3,4,5/)
real,dimension(10,10)::mat=1
che assegnano valori a tutte4 le componenti delle variabili: alle componenti degli array ad unadimensione a e b vengono asssegnati i valori 0 per le componenti a(i) di a con i=1,...,100, e i valori0,1,2,3,4,5 per le componenti b(i) di b con i=0,...,5; agli elementi mat(i,j), i=1,...,5, j=1,...,5,dell’array a due dimensioni mat viene assegnato il valore 1.
Le stesse istruzioni dichiarative per gli array a e b si possono scrivere
real,dimension(100)::a(/0,i=1,100/)
integer,dimension(0:5)::b=(/i,i=0,5/)
real,dimension(10,10)::mat=1
Indirizzo degli elementi dell’array
In Fortran la posizione in memoria del generico elemento v(i) di un array ad una dimensione e a(i,j)di un array a due dimensioni e specificata come segue:
1. si indichi con tipo una parola chiave di specifica di tipo (e.g., real, integer,...), e con l il numerodi bit necessari per un valore di tipo (e.g. l = 32 se tipo e integer o real*4, l = 64 se tipo ereal*8,...);
2. siano le variabili v e a dichiarate, ad esempio con la scrittura in F77, come segue
real v(i0:N)
real a(i0:LD,j0:M)
allora se si indicano conIND[v(i0)] e IND[a(i0,j0)]
gli indirizzi in memoria della prima componente, rispettivamente dell’array v e a, allora gli indirizzi inmemoria delle componenti v(i) e a(i,j) sono
IND[v(i)] = IND[v(i0)] + (i-i0) ∗ lIND[a(i,j)] = IND[a(i0,j0)] + (j-j0)*LD ∗ l + (i-i0) ∗ l
ovvero l’array a di due dimensioni “non esiste”, ma esiste come un “lungo” array colonna di (LD-i0+1)·(M-j0+1)elementi dove gli elementi della seconda colonna (j=2) sono disposti “sotto” quelli della prima (j=1), quellidella terza (j=3) sono “sotto” quelli della seconda (j=2) e cosı via. Ovvero, il Fortran, memorizza idati di un array per colonna. Il valore LD e detto leading.
4In F90 non si puo inizializzare un numero di componenti di un array inferiore al numero delle componenti allocate.
11
Variabili allocabili con indice in F90
Il processo di memorizzazione degli array visto in precedenza in cui si deve specificare quanta memoriabisogna allocare per memorizzare un determinato array, si chiama allocazione statica della memoria.Il F90 prevede anche una allocazione dinamica della memoria.Il programma imposta dinamicamente la dimensione dell’array ogni volta che viene eseguito in mododa essere “sufficientemente grande” per risolvere il problema corrente. In tal modo non c’e spreco dimemoria e consente che il programma sia eseguito da calcolatori che hanno poca o molta memoria diRAM indistintamente.Un array che utilizza la memoria in modo dinamico viene dichiarato allocabile e viene allocato, medianteun’istruzione eseguibile, prima di essere utilizzato.L’istruzione dichiarativa per dichiarare allocabili due array x ed y ad una dimensione e un array a a duedimensioni, ad esempio reali, e la seguente
real, allocatable, dimension(:):: x,y
real, allocatable, dimension(:,:):: a
• i due punti : sono dei segnaposto; non si conosce quanto e grande l’array;5
• array allocabili non possono essere inizializzati ad un valore nell’istruzione dichiarativa;
• un array dichiarato con i due punti : e detto array a forma differita; per contro un array le cuidimensioni sono dichiarate esplicitamente in un’istruzione di dichiarazione e detto array di formaesplicita.
Se si vuole, ad esempio, che la dimensione dell’array x sia 101, con indice delle componenti da 0 a 100,dell’array y sia n, dove n ha un valore calcolato o letto in una precedente istruzione eseguibile e, dell’arraya sia 1000× 1000, allora con le istruzioni eseguibili che dimensionano gli array si scrivono
allocate(x(0:100),stat=infox)
allocate(y(n),stat=infoy)
allocate(a(1000,1000),stat=infoa)
che possono essere scritte anche in una o due istruzioni eseguibili elencando tra le parentesi gli array daallocare, e.g.
allocate(x(0:100),y(n),a(1000,1000),stat=info)
dunque il numero di componenti dell’array con l’indice iniziale e finale viene stabilito mediante un’istruzioneeseguibile. Essi possono essere costanti intere con o senza nome, variabili intere di cui e noto il valore almomento dell’allocazione o, in generale, espressioni che danno come risultato un numero intero.
• La clausola stat= in qualsiasi istruzione allocate, assegna alla variabile intera a destra dell’uguale(nell’esempio a infox o infoy o infoa o info) il valore 0 se l’allocazione ha avuto successo, oppureun valore intero positivo (dipende dal compilatore) se l’allocazione non ha avuto successo, ovverosi richiede troppa memoria rispetto a quella messa a disposizione dal compilatore quando abbiamodichiarato l’array allocabile.
Alla fine del processo in cui si usano array allocabili si “rilascia” la memoria con l’istruzione di “deallo-cazione”; ad esempio se si “dealloca” l’array a, l’istruzione e
deallocate(a,stat=info)
e se la variabile intera info e uguale a zero, allora la “deallocazione” di a ha avuto successo. Se non epresente l’istruzione di “deallocazione”, essa avviene quando si esegue l’istruzione di fine (end).
5Il compilatore riserva un’area di memoria la cui grandezza e sconosciuta al programmatore.
12
Funzioni intrinseche
In Fortran esistono piu di 40 funzioni intrinseche. Sono funzioni intrinseche le funzioni matematicheelementari e le funzioni di conversioni di tipo. Le funzioni intrinseche si scrivono con un designatore difunzione e l’argomento (o gli argomenti separati da virgola) tra parentesi tonde.Si elencano alcune funzioni intrinseche che, in generale, forniscono un risultato del tipo del o degli argo-menti.Per abbreviazione, si indica in tabella con I, R, D, C, Z rispettivamente il tipo intero, reale in precisionesemplice, reale in precisione doppia, carattere e complesso dell’argomento x e del risultato. Ad esempiotra le funzioni matematiche elementari vi sono
funzione tipo dell’argomento tipo del risultato definizione
abs(x) IRDZ IRDR |x|sqrt(x) RDZ RDZ
√x
mod(x,y) I I resto di x/ysign(x) IRD I segno di xexp(x) RDZ RDZ ex
log(x) RDZ RDZ logexlog10(x) RD RD log10xsin(x) RDZ RDZ sinxcos(x) RDZ RDZ cosxtan(x) RD RD tanxasin(x) RD RD arcsinxacos(x) RD RD arccosxatan(x) RD RD arctanxsinh(x) RD RD sinhxcosh(x) RD RD coshxtanh(x) RD RD tanhx
Le funzioni di conversione di tipo sono:
funzione tipo dell’argomento tipo del risultato
int(x) IRD Ireal(x) IRD Rdble(x) IRD Dichar(x) C Ichar(x) I C
e convertono rispettivamente l’argomento in numero intero (si considera la parte intera dell’argomento),in reale in precisione semplice, in reale in precisione doppia, nell’intero corrispondente al codice ASCIIdell’argomento carattere e nel carattere ASCII del corrispondente valore intero dell’argomento.
In Fortran l’argomento di una funzione puo essere una costante, una variabile, un’espressione o anche ilrisultato di un’altra funzione. Ad esempio sono valide le seguenti istruzioni di assegnazione alla variabiley del valore della funzione sin:
y=sin(3.141593)
y=sin(x)
y=sin(pi*x)
y=sin(sqrt(x))
13
Istruzione di elaborazione di espressioni
In Fortran un’istruzione di elaborazione di un’espressione si scrive nel modo seguente
x =espressione
ovvero il risultato dell’espressione a destra del segno uguale viene assegnato alla variabile x a sinistra delsegno uguale. In Fortran si hanno le seguenti
• espressione aritmetica:
– operatori aritmetici+ − ∗ / ∗ ∗
– operandi aritmetici sono le espressioni aritmetiche.
Definizione di espressione aritmetica:6
1. ogni variabile IRDZ e un’espressione aritmetica, rispettivamente IRDZ;
2. ogni costante, con o senza nome, IRDZ e un’espressione aritmetica, rispettivamente IRDZ;
3. ogni funzione intrinseca con risultato IRDZ e un’espressione aritmetica rispettivamenteIRDZ;
4. se X e un’espressione aritmetica, anche (X) e un’espressione aritmetica;
5. se X ed Y sono due espressioni aritmetiche, anche X + Y , X − Y , X ∗ Y , X/Y e X ∗ ∗Ysono espressioni aritmetiche;
6. se applichiamo un numero finito di volte le regole 1–5 si ottiene un’espressione aritmetica;
– priorita: parentesi piu interne fino alle piu esterne, valutazione di funzioni, elevamento apotenza, divisione/moltiplicazione, addizione/sottrazione. A parita di livello di parentesi, leoperazioni si svolgono da sinistra verso destra tranne l’elevamento a potenza che si svolge dadestra verso sinistra;
– espressione aritmetica tra operandi di tipo diverso7
x I I I R R Dy I R D R D D
x⊗ y I R D R D D
Si osservi il risultato delle seguenti istruzioni, supponendo di usare la dichiarazione implicitadi variabili:
i=2/3 risultato: i=0i=2./3 risultato: i=0x=2/3 risultato: x=0x=2./3 risultato: x=0.6i=2; j=3; x=i/j risultato: x=0i=2; j=3; x=real(i)/j risultato: x=0.6
• espressione relazionale:
– operatori relazionali
.lt. .le. .eq. .ne. .ge. .gt. in F77
< <= == /= >= > in F90
– operandi relazionali sono le espressioni aritmetiche.
– Il risultato di un’espressione relazionale e un valore logico.
6Per abbreviazione, si indica con I, R, D, Z rispettivamente il tipo intero, reale in precisione semplice, reale in precisionedoppia e complesso.
7Con il simbolo ⊗ si indica un qualsiasi operatore aritmetico.
14
• espressione logica:
– operatori logici.and. .or. .not. .eqv. .xor.
– operandi logici sono le espressioni logiche.
Definizione di espressione logica:8
1. ogni variabile di tipo logico e un’espressione logica;
2. ogni costante con o senza nome di tipo logico e un’espressione logica;
3. ogni espressione relazionale e un’espressione logica;
4. se X e un’espressione logica, anche (X) e un’espressione logica;
5. se X ed Y sono due espressioni logiche, anche X opl Y e un’espressione logica;
6. se applichiamo un numero finito di volte le regole 1–5 si ottiene un’espressione logica.
– priorita: parentesi piu interne fino alle piu esterne, operatori aritmetici, operatori relazionali,.not., .and., .or., .eqv./.xor..
Istruzione di salto incondizionato
L’istruzione eseguibile di salto incondizionato in Fortran si scrive con la parola chiave go to oppuregoto seguita da un’etichetta che sottointende all’istruzione eseguibile successiva. Ad esempio l’istruzione
goto 10
rimanda all’istruzione etichettata con 10.
Istruzione di salto condizionato
In Fortran e presente l’istruzione di salto condizionato altrimento detta di if aritmetico. Questaistruzione si scrive
if(E)l1, l2, l3
dove E indica un’espressione aritmetica ed l1, l2 ed l3 sono tre etichette.
• Se l’espressione E assume un valore negativo allora si “salta” all’istruzione con etichetta l1.
• Se l’espressione E assume un valore nullo allora si “salta” all’istruzione con etichetta l2.
• Se l’espressione E assume un valore positivo allora si “salta” all’istruzione con etichetta l3.
◦ Se, ad esempio l1 = l2, allora si “salta” all’istruzione con etichetta l1 se l’espressione E e minore ouguale a 0.
◦ Se l1 = l2 = l3, l’istruzione e equivalente all’istruzione di salto incondizionato goto l1
Ad esempio, supponendo che x e y siano due variabili e 10, 20, 30 siano tre etichette, un’istruzione disalto condizionato e la seguente:
if(x-y)10,20,30
Istruzione di arresto
L’istruzione eseguibile di arresto in Fortran si scrive con la parola chiave stop. Questa istruzione non vaconfusa con l’istruzione di fine programma (end) che non e un’istruzione eseguibile. Ci possono essere piuistruzioni eseguibili di arresto stop ma, per ogni unita di programma ci deve essere una sola istruzionedi fine programma end.Se un’istruzione di arresto non e presente nel programma, il programma si arresta quando trova l’istruzionedi fine programma end.
8Si indica con opl un qualsiasi operatore logico.
15
Istruzione di condizione
In Fortran e prevista l’istruzione di condizione o di if logico. Se si indica con C un’espressione logical’istruzione di condizione ha la forma
if (C) thenistruzione/i
endif
oppureif (C) then
istruzione/i 1else
istruzione/i 2endif
Nel primo caso (costrutto if–then) si eseguono le istruzioni se l’espressione logica C e vera, nel secondocaso (scelta dicotomica o costrutto if–then–else) si eseguono le istruzioni 1 se l’espressione logicaC e vera e le istruzioni 2 se l’espressione logica C e falsa.Nel caso in cui ci sia una sola istruzione da eseguire se l’espressione logica C e vera, in Fortran si prevedeanche la scrittura dell’istruzione di condizione in un’unica riga (istruzione di if)
if (C) istruzione
In Fortran vi e anche il costrutto elseif che si presenta nella seguente forma9
if (C1) thenistruzione/i 1
elseif (C2) thenistruzione/i 2else
istruzione/i 3endif
Il risultato e l’esecuzione dell’istruzione/i 1 se C1 e vera, dell’istruzione/i 2 se C1 e falsa e C2 e vera edell’istruzione/i 3 se C1 e C2 sono entrambe false.Il costrutto si puo ampliare introducendo altre condizione di elseif. Ad esempio
if (C1) thenistruzione/i 1
elseif (C2) thenistruzione/i 2
elseif (C3) thenistruzione/i 3else
istruzione/i 4endif
In tal caso l’istruzione/i 1 e eseguita se C1 e vera, l’istruzione/i 2 e eseguita se C1 e falsa e C2 e vera,l’istruzione/i 3 e eseguita se C1 e C2 sono false e C3 e vera e l’istruzione/i 4 e eseguita se C1, C2 e C3sono false.
Le parole if, then, else, elseif e endif sono parole chiave.
9Si indicano con C1, C2 e C3 tre differenti espressioni logiche.
16
L’istruzione continue in F77
L’istruzione continue presente in F77, costituita dalla sola parola continue su una riga
continue
permette di evidenziare un punto del programma; essa ha il solo effetto di far proseguire sequenzialmentel’esecuzione del programma.Si puo verificare che il costrutto if–then–else puo essere ottenuto mediante le istruzioni if, goto econtinue.continue e una parola chiave.
Il ciclo do
Il ciclo do (do–loops) e il costrutto del linguaggio Fortran per eseguire una o piu istruzioni (nucleo delciclo) un numero di volte noto a priori.
Se si indica con l un’etichetta, il ciclo do in F77 ha la seguente forma
do l, c = e1, e2, e3istruzione/i
l continue
Il ciclo do in F90 ha la seguente forma (costrutto do–enddo)
do c = e1, e2, e3istruzione/i
enddo
dove, in Fortran:
• do e enddo sono parole chiave;
• c e la variabile contatore, preferibilmente intera;
• e1 e una variabile, una costante o, in generale, un’espressione aritmetica, preferibilmente intera,che indica il valore di inizio ciclo ed e il primo valore che assume il contatore c;
• e2 e una variabile, una costante o, in generale, un’espressione aritmetica, preferibilmente intera,che indica il valore di fine ciclo;
• e3 e una variabile, una costante o, in generale, un’espressione aritmetica, preferibilmente intera ecomunque non nulla, che indica il valore del passo del ciclo. E opzionale se uguale ad 1.
Il nucleo del ciclo viene eseguito per ogni valore del contatore c che varia da e1 a e2 con passo e3.
◦ Se e3 e positivo, le istruzioni che costituiscono il nucleo del ciclo sono eseguite se e2≥e1.
◦ Se e3 e negativo (ciclo a ritroso), le istruzioni che costituiscono il nucleo del ciclo sono eseguite see1≥e2.
Per quanto concerne le regole del ciclo sopra descritto:
• non e possibile modificare il valore della variabile contatore c o di e1 o di e2 o di e3 medianteun’istruzione del nucleo del ciclo;
• non e possibile “saltare dentro al ciclo” ad un’istruzione etichettata del nucleo del ciclo mediantel’istruzione (fuori dal ciclo) di salto incondizionato goto;
17
• e possibile “uscire” dal ciclo mediante un’istruzione di condizione e di salto incondizionato (o diarresto) presenti nel nucleo del ciclo (ciclo incompleto).
In F77:
• la virgola dopo l’etichetta l e opzionale;
• e possibile omettere l’istruzione continue, mettendo l’etichetta l sull’ultima istruzione del ciclo:
do l, c = e1, e2, e3istruzione 1...
l istruzione k
• l’etichetta l non puo stare su una linea di codice di do, goto, if, elseif, endif, return, stop eend;
• vi sono casi in cui e necessaria l’istruzione continue. Ad esempio, se C e un’espressione logica,
do l, c = e1, e2, e3istruzione 1...
if (C) goto l...
istruzione kl continue
non e infatti possibile scrivere il ciclo nel modo seguente
do l, c = e1, e2, e3istruzione 1...
if (C) continue...
istruzione kl continue
Deve presentarsi una sola istruzione continue per ogni do;
• i compilatori piu recenti del F77 riconoscono il ciclo do con il costrutto do–enddo.
In Fortran c’e la possibilita di fare cicli annidati (nested) a due o piu indici. Ad esempio in F90 unciclo annidato a due indici ha la forma
do i = i1, i2, i3istruzione/i 1do j = j1, j2, j3istruzione/i 2
enddo
enddo
In F77 un ciclo annidato puo avere la seguente forma
do 10, i = i1, i2, i3istruzione/i 1do 20, j = j1, j2, j3istruzione/i 2
20 continue
10 continue
18
• Le etichette 10 e 20 possono sottointendere anche le ultime istruzioni del corpo del ciclo di i e delciclo j rispettivamente.
• E errato “chiudere” prima il ciclo esterno di quello interno; ovvero non e corretto
do 10, i = i1, i2, i3istruzione/i 1do 20, j = j1, j2, j3istruzione/i 2
10 continue
20 continue
Questo errore e evitato se si usa il costrutto do–enddo.
• Se, come in questo esempio, non vi sono istruzioni tra le due istruzioni continue che chiudono idue cicli interno ed esterno, allora si puo scrivere
do 10, i = i1, i2, i3istruzione/i 1do 10, j = j1, j2, j3
istruzione/i 210 continue
oppure
do 10, i = i1, i2, i3istruzione/i 1do 10, j = j1, j2, j3istruzione/i 2
10 ultima istruzione 2
Il ciclo while
Il ciclo while (while–loops),
mentre la condizione e vera esegui le istruzioni
e un ciclo in cui non e noto a priori quante volte si devono eseguire una o piu istruzioni.In Fortran il ciclo while si puo “simulare” con il costrutto if–then e l’istruzione goto.Se si indica con C un’espressione logica e con l un’etichetta, si hanno le istruzioni
l if (C) then
istruzione/igoto l
endif
Il ciclo until
Il ciclo until (until–loops),
ripeti le istruzioni finche la condizione non diventa vera
e un ciclo in cui non e noto a priori quante volte si devono eseguire una o piu istruzioni.In Fortran il ciclo until si “simula” con il costrutto if–then e l’istruzione goto.Se si indica con C un’espressione logica e con l un’etichetta, si hanno le istruzioni
l prima istruzionealtra/e istruzione/iif (.not. C) goto l
19
Istruzioni di lettura e scrittura
In Fortran le istruzioni di lettura e di scrittura si implementano con le parole chiave read e write seguitedalle variabili o dalle costanti o in generale dalle espressioni, separate da virgola, che si vogliono scriveree leggere.Le istruzioni di lettura e di scrittura si scrivono rispettivamente
read(*,*) write(*,*)
• il primo asterisco * specifica che l’unita di ingresso (lettura) o di uscita (lettura) e quella di default;cioe la tastiera per unita di ingresso e il video per unita di uscita;
• il secondo asterisco * indica che il formato per leggere o per scrivere utilizzato e quello di default,ovvero il formato libero.
Il do implicito
In Fortran e possibile per la lettura o la scrittura di array il do implicito.Ad esempio si suppone di dover scrivere l’array
x =
123
la scrittura, ad esempio in F90,
do i=1,3
write(*,*) x(i)
enddo
visualizza123
mentre la scrittura Fortran
write(*,*) (x(i),i=1,3) visualizza 1 2 3
Se si suppone di dover scrivere l’array bidimensionale
a =
1 2 34 5 67 8 9
La scrittura, ad esempio in F90,
do i=1,3
do j=1,3
write(*,*) a(i,j)
enddo
enddo
visualizza
123456789
mentre la scrittura, ad esempio in F90,
do i=1,3
write(*,*)(a(i,j),j=1,3)
enddo
visualizza1 2 34 5 67 8 9
ed ancora la scrittura in Fortran
write(*,*) ((a(i,j),j=1,3),i=1,3) visualizza 1 2 3 4 5 6 7 8 9
L’istruzione read segue la stessa sequenza di dati come per l’istruzione write, ad eccezione che, quando idati sono introdotti direttamente da tastiera, puo essere premuto il tasto invio (tasto enter) opzionalmentedopo l’ingresso di ogni dato.
20
Il ridirezionamento dei dati in ingresso e in uscita
In Fortran e possibile ridirezionare i dati in lettura e in scrittura, quando questi sono letti dall’unita didefault mediante i sistemi operativi windows dal prompt dei comandi o unix/linux dalla linea di comandodel terminale.Ad esempio se il file eseguibile esempio e il file compilato del file Fortran esempio.f in cui sono presentile seguenti istruzioni di lettura e di scritura da e su l’unita di default
read(*,*)n
read(*,*)(x(i),i=1,n)
write(*,*)’matrice da vettore’
do i=1,n
write(*,*)(x(i)*x(j),j=1,n)
enddo
allora, il comando eseguito dal prompt dei comandi o dalla linea di comando del terminale
esempio<in>out
prevede che esista un file di dati che abbiamo chiamato in10 contenente, ad esempio dei dati disposti inquesto modo e con questi valori
31 0 2
e produce un file di dati che abbiamo chiamato out in cui c’e scritto
matrice da vettore
1 0 20 0 02 0 4
Se il file di dati in non e stato creato, l’esecuzione di esempio non puo avvenire.E ovviamente possibile produrre solo un file di uscita dati inserendo i dati in lettura da tastiera come in
esempio>out
oppure inserire i dati di ingresso da file e visualizzare i dati di uscita su video come in
esempio<in
10Ovviamente il nome del file di ingresso dati e del file di uscita dati e scelto dal programmatore.
21
Lettura e scrittura mediante file
In Fortran e possibile leggere e scrivere dati da e su file con istruzioni eseguibili dell’unita di programmae non soltanto da sistema operativo. E necessario in questo caso “aprire il file” e questo avviene conl’istruzione open.L’istruzione eseguibile open si scrive nel modo seguente:
open(unit=..., file=..., status=..., form=..., action=..., access=..., iostat=...)
dove soltanto unit e file sono obbligatori.Al posto dei puntini ...:
• unit=numero intero positivo; e.g. unit=8
I numeri 5 e 6 indicano la tastiera e il video, i.e. read(5,*) e read(*,*) indicano la stessa unitadi ingresso dati e write(6,*) e write(*,*) indicano la stessa unita di uscita dati;
• file=nome del file. Ad esempio se chiamiamo out il file su cui vogliamo scrivere i risultati allora
file=’out’
Se il nome del file e una variabile carattere, ad esempio in F90
character(len=10)::dati
allorafile=dati
• status=’old’ se il file specificato dal nome esiste gia;
status=’new’ se il file specificato dal nome non esiste11;
status=’unknown’ se non e noto se esiste il file specificato dal nome12; se non e specificato lo statodel file allora il file si considera unknown;
status=’replace’ se si vuole aprire un nuovo file (di uscita) con il nome specificato o se tale fileesiste, sostituirlo;
status=’scratch’ se si vuole creare un file temporaneo da eliminare quando si “chiude” il file.13.Se si usa la clausola status=’scratch’ non si deve specificare la clausola action=.
• form=’formatted’ se il file e formattato (leggibile) altrimenti la clausola e form=’unformatted’.Per file non formattati le istruzioni di lettura e scrittura da e su file14 si scrivono
read(8)x,y,z write(8)x,y,z
Se non si specifica se il file e formattato o meno, il file viene considerato formattato.
• action=’read’ se il file e di sola lettura;
action=’write’ se il file e di sola scrittura;
action=’readwrite’ se il file e di lettura e scrittura. Se non e specificato se il file e di lettura oscrittura si considera sia di lettura che di scrittura.
• access=’sequential’ se il file viene esaminato sequenzialmente (questa e anche la procedura senon e specificato diversamente nella clausola di accesso al file); access=’direct’ se l’accesso al filee diretto.
11Ovviamente si intende un file non esistente nel direttorio in cui si esegue il file eseguibile. Se il file specificato dal nomeesiste allora viene segnalato errore in esecuzione.
12Se il file esiste allora status=’unknown’ e come status=’old’, se il file non esiste e come status=’new’.13Utile quando si vogliono salvare risultati intermedi ma non per registare dati che devono essere salvati alla fine del
programma.14Si suppone, ad esempio, che nell’istruzione open si sia posto unit=8.
22
• iostat=variabile intera; il valore della variabile intera e 0 se l’apertura del file ha avuto successo,altrimenti la variabile assume un valore diverso da zero15.
L’istruzione di chiusura del file eclose(...)
dove al posto dei puntini c’e il numero intero positivo specificato nella clausola unit=.Se l’istruzione close non e presente, il file si chiude quando trova l’istruzione di fine programma end.
Si possono aprire contemporaneamente piu file, purche diversi, ovvero con diversa clausola file=.
Ad esempio si vuole leggere dei dati dal file che si chiama in e scrivere i dati elaborati su un file chechiamiamo out. Il file in ha, ad esempio, questa disposizione di valori
31 0 2
Nel punto dell’unita di programma Fortran in cui si vuole leggere i dati si “apre” il file in e si scrivonole seguenti istruzioni eseguibili
open(unit=8,file=’in’,status=’old’,form=’formatted’,action=’read’,access=’sequential’,iostat=ierr)
read(8,*)n
read(8,*)(x(i),i=1,n)
if(ierr.ne.0)stop
close(8)
Quando si vogliono scrivere i dati sul file out, successivamente alle istruzioni di lettura del file in, allorasi scrivono le seguenti istruzioni eseguibili
open(unit=8,file=’out’,status=’new’,form=’formatted’,action=’write’,access=’sequential’,iostat=ierr)
write(8,*)’matrice da vettore’
do i=1,n
write(8,*)(x(i)*x(j),j=1,n)
enddo
if(ierr.ne.0)stop
close(8)
Il file out risulta esserematrice da vettore
1 0 20 0 02 0 4
15Il valore diverso da zero dipende dal compilatore.
23
L’istruzione format
In Fortran, la lettura o la scrittura dei dati con formato puo essere fatta mediante la specifica di formatonell’istruzione read o write oppure mediante l’istruzione eseguibile format.Ci limitiamo ad alcuni esempi.
• Sono equivalenti i seguenti segmenti di programma supponendo di utilizzare la dichiarazione im-plicita del Fortran.
read(*,’2I6’)i,j read(*,100)i,j
read(*,’3I6’)i1,12,i3 read(*,200)i1,12,i3
read(*,’2I6’)ip,jp read(*,100)ip,jp
100 format(2I6)
200 format(I6,I6,I6)
3I6, sia interno all’istruzione read che nell’istruzione format, significa che vengono letti tre (3)numeri interi (I) ciascuno che occupa sei (6) caratteri, incluso il segno. Se il numero occupa menodi 6 caratteri, esso viene scritto da destra lasciando spazi bianchi per il completamento dei caratteri.Si osserva che il numero -123456 non puo essere letto con tale formato. Analogamente se si usal’istruzione write.
• I numeri reali possono essere letti o scritti sia in forma posizionale (fixed) che esponenziale.
read(*,10)x,y
read(*,20)u,v
10 format(F7.1,F6.3)
20 format(E9.1,E103)
I numeri reali x e y sono scritti in “forma fissa” ed occupano rispettivamente 7 caratteri (incluso ilsegno16 e il punto radice) di cui 1 per la cifra dopo il punto radice e sei caratteri (incluso il segno eil punto radice) di cui 3 dopo il punto radice.
Ad esempio valori di x e y che rispettano i campi stabiliti dal formato sono
−123.4 12.456
In generale la forma Fi.j dovrebbe soddisfare i≥j+2 perche uno spazio ciascuno si deve riservareal punto radice e all’eventuale segno. La scrittura F.j indica che non si specificano caratteri pervalori a sinistra del punto radice, i.e., si intendono leggere o scrivere valori come 0.123.
I numeri reali u e v sono scritti in “forma esponenziale” ed occupano rispettivamente 9 caratteri dicui 1 per una cifra dopo il punto radice e 10 caratteri di cui 3 per tre cifre dopo il punto radice. Trai 9 e i 10 caratteri si deve tenere conto dell’eventuale segno e dei 4 caratteri della parte esponenzialeeSXX dove S indica il carattere riservato al segno e XX sono due cifre da 0 a 38. Ad esempio valoridi u e v che rispettano i campi stabiliti dal formato sono
−123.4e− 2 123.456e2
Allora in generale la forma Ei.j dovrebbe soddisfare i≥j+5.Nel caso di lettura o scrittura di numeri in precisione doppia, la notazione esponenziale diventa, adesempio, D9.1; in questo caso la forma Di.j dovrebbe soddisfare i≥j+6.Le stesse istruzioni possono essere incluse all’interno dell’istruzione read o write, se le variabili daleggere o da scrivere elencate successivamente all’istruzione stessa sono dello stesso tipo e soggetteallo stesso formato.
16Se positivo e ovviamente opzionale.
24
• I valori di tipo carattere possono essere letti o scritti, ad esempio, nel modo seguente
read(*,10)c
10 format(A8)
dove la variabile carattere c deve avere al massimo 8 caratteri.
• Nei formati di scrittura sono possibili caratteri come / che causa una linea bianca di stampa, oppureun numero naturale dopo il carattere X, e.g., 1X o 10X che indica che deve essere saltato un certonumero di spazi (nell’esempio, uno o dieci spazi); ad esempio
write(*,101)
write(*,100)x,y,i
101 format(1X,’calcolo eseguito’)
100 format(2X,’x= ’,F8.3,2X,’y= ’,F.4,2X,’i= ’,I5)
L’istruzione eseguibile format puo trovarsi in qualsiasi punto dell’programma. In generale tutte leistruzioni �format sono posizionate in fondo al programma prima dell’istruzione di fine programma end.
25
Operazioni globali su array in F90
In F90 e possibile eseguire operazioni su variabili con indice come se fossero operazioni su variabilisemplici.Ad esempio si scrivono le seguenti istruzioni dichiarative per array ad una e a due dimensioni e per scalari.Gli array ad una dimensione devono avere la stessa lunghezza e gli array a due dimensioni devono averelo stesso numero di righe e lo stesso numero di colonne:
integer,parameter::na=100,nx=30
real,dimension(na,na)::a,b,c
real,dimension(nx)::x,y,z
real ::s
sono possibili le seguenti istruzioni eseguibile che svolgono operazioni globali:
y=s*x e equivalente ado i=1,nx
y(i)=s*x(i)
enddo
y=s+x e equivalente ado i=1,nx
y(i)=s+x(i)
enddo
b=s*a e equivalente a
do i=1,na
do j=1,na
b(i,j)=s*a(i,j)
enddo
enddo
b=s+a e equivalente a
do i=1,na
do j=1,na
b(i,j)=s+a(i,j)
enddo
enddo
z=x+y e equivalente ado i=1,nx
z(i)=x(i)+y(i)
enddo
c=a+b e equivalente a
do i=1,na
do j=1,na
c(i,j)=a(i,j)+b(i,j)
enddo
enddo
In F90 molte funzioni intrinseche che sono utilizzate con valori scalari accettano anche gli array comeargomenti di ingresso e restituiscono un array in uscita.Ad esempio, se x e un array, allora sin(x) restituisce un array delle dimensioni di x avente per componentiil valore della funzione seno calcolata nella corrispondente componente dell’array x; i.e., se x e un arrayad una dimensione, la i–esima componente dell’array sin(x) e sin(x(i)).
Si nota che la scrittura write(*,*)x o write(*,*)a, dove si suppone che la variabile x sia un arrayad una dimensione e a sia un array a due dimensioni, comporta la stampa “per colonna” di tutti glielementi dell’array.Analogamente con read(*,*)x o read(*,*)a vengono letti “per colonna” gli elementi degli array.
26
Indicizzazione di array con triplette in F90
Nelle istruzioni esguibili in F90 e possibile indicare le componenti di un array17 ad una dimensione nonsoltanto con un solo indice x(i) ma anche con una tripletta di indici.Ad esempio le scritture x(1:5:2) e x(1:4) indicano che si stanno considerando rispettivamente le com-ponenti x(1), x(3) e x(5) per la prima scrittura e le componenti x(1), x(2), x(3) e x(4) per la secondascrittura.Dunque, se si suppone che la variabile con indice x sia dichiarata nel modo seguente
integer,parameter::nx=100
real,dimension(nx)::x
la scrittura
x(i1:i2:i3) indica che si considerano le componenti con indice da i1 a i2 con passo i3
x(i1:i2) indica che si considerano le componenti con indice da i1 a i2 con passo 1x(i1:) indica che si considerano le componenti con indice da i1 a nx
x(i1::i3) indica che si considerano le componenti con indice da i1 a nx con passo i3
x(:i2) indica che si considerano le componenti con indice da 1 a i2 con passo 1x(:i2:i3) indica che si considerano le componenti con indice da 1 a i2 con passo i3
x(:) indica che si considerano le componenti con indice da 1 a nx con passo 1x(::i3) indica che si considerano le componenti con indice da 1 a nx con passo i3
17Sia che esse siano utilizzate in espressioni e sia che esse siano variabili a cui assegnare il valore di un’espressione.
27
Altre istruzioni di F90
Le istruzioni cycle ed exit
In F90 sono presenti le istruzioni cycle ed exit. Ne vediamo il loro signifato con un esempio diprogramma.Esempio per l’istruzione cycle (si usa la dichiarazione di tipo implicita del Fortran):
program testcycle
do i=1,5
if(i==3)cycle
write(*,*) i
endddo
write(*,*)’fine ciclo’
stop
end program testcycle
L’esecuzione di questo programma scrive
1245fine ciclo
Esempio per l’istruzione exit (si usa la dichiarazione di tipo implicita del Fortran):
program testexit
do i=1,5
if(i==3)exit
write(*,*) i
endddo
write(*,*)’fine ciclo’
stop
end program testexit
L’esecuzione di questo programma scrive
12fine ciclo
• L’istruzione exit all’interno di un ciclo do arresta il ciclo; da non confondere con l’istruzione diarresto stop che invece arresta l’intero programma.
28
L’istruzione select case
In F90 e presente il costrutto di select case. Il costrutto ha la seguente forma:
nome: select case(E)case (selettore1)istruzioni 1case (selettore2)istruzioni 2...case default
altre istruzioniend select case nome
• Con E si indica un’espressione aritmetica.
• Se il valore dell’espressione aritmetica E e compreso nell’intervallo del selettore 1 allora si eseguonole istruzioni 1, se e compreso nell’intervallo del selettore 2 allora si eseguono le istruzioni 2 e cosıvia; se il valore di E non e con e compreso in nessun intervallo specificato dai selettori allora e il“caso default” e si eseguono le altre istruzioni.
• Il bloccocase default
altre istruzioni
e opzionale; se il valore dell’espressione aritmetica E non e compreso in nessun intervallo specificatodai selettori e non e presente il “blocco di default” allora il costrutto select case non vieneeseguito.
• Il nome del costrutto select case e opzionale.
Esempio 1 (si usa la dichiarazione di tipo implicita del Fortran):
select case(itemp)
case (:-1)
write(*,*)’valore ’’temp’’ minore di -1 ’
case (0)
write(*,*)’valore ’’temp’’ nullo ’
case (1:20)
write(*,*)’valore ’’temp’’ da 1 a 20 ’
case (21:)
write(*,*)’valore ’’temp’’ maggiore di 21 ’
end select case
Esempio 2 (si usa la dichiarazione di tipo implicita del Fortran):
select case(ivalore)
case (1,3,5,7,9)
write(*,*)’valore dispari da 1 a 10 ’
case (2,4,6,8)
write(*,*)’valore pari da 1 a 10 ’
case (11:)
write(*,*)’valore maggiore di 11 ’
case default
write(*,*)’valore negativo ’
end select case
29
Il ciclo do con nome
In F90 c’e la possibilita di assegnare un nome al ciclo do inserendo il nome seguito da : (due punti) primadella parola chiave do e dopo la parola chiave enddo. Con un esempio di un segmento di programma sene vede l’utilita.Se scrivo
do i=1,3
do j=1,3
if(j==2)cycle
ij=i*j
write(*,*)i,j,ij
enddo
enddo
come per l’esempio dell’istruzione cycle, il segmento di programma fornisce la scrittura
1 1 11 3 32 1 22 3 63 1 33 3 9
Se, ad esempio, si assegna un nome al ciclo esterno
esterno: do i=1,3
do j=1,3
if(j==2)cycle esterno
ij=i*j
write(*,*)i,j,ij
enddo
enddo esterno
allora si ha la scrittura di1 1 12 1 23 1 3
30
Il ciclo while/until in F90
In F90 e possibile scrivere il ciclo while o il ciclo di until utilizzando l’istruzione exit nel blocco diistruzioni comprese tra do ed enddo nel modo seguente:
do
istruzioni 1if(E) exit
istruzioni 2enddo
dove E e un’espressione logica. Le istruzioni 1 e le istruzioni 2 vengono eseguite finche l’espressione E efalsa. Se, dopo l’esecuzione delle istruzioni 1, l’espressione logica E diventa vera, allora si esegue, comeistruzione successiva, quella scritta sotto enddo.
Il costrutto do while
In F90 e possibile utilizzare il costrutto do while per la costruzione del ciclo while. Il costrutto do whileha la seguente forma:
do while (E)istruzione 1...istruzione kenddo
Se l’espressione logica E e vera, le istruzioni (istruzione 1,..., istruzione k) vengono eseguite; dopol’istruzione enddo si esegue l’istruzione do while e se l’espressione logica E e ancora vera, vengonoeseguite nuovamente le istruzioni (istruzione 1,..., istruzione k). Questo processo viene eseguito fino aquando l’espressione logica E diventa falsa; in tal caso la successiva istruzione da eseguire e quella scrittanella riga sotto enddo.Questo costrutto e meno flessibile del costrutto
do
...if(E) exit
...enddo
in quanto l’istruzione di condizione deve essere posizionata come prima istruzione del ciclo.
31
Il costrutto e l’istruzione where
In F90 e possibile assegnare dei valori ad un array mediante una maschera. Ad esempio, siano a e b duearray bidimensionali dichiarati nel modo seguente
integer, parameter::nd1=100, nd2=200
real, dimension(nd1,nd2) :: a,b
Supponiamo che siano stati assegnati dei valori reali a tutte le componenti dell’array a. Si vuole calcolarel’array b le cui componenti abbiano valore uguale alle rispettive componenti di a se queste sono positive,oppure siano nulle se le rispettive componenti di a sono nulle o negative. Questo si esegue con il segmentodi programma seguente
do i=1,nd1
do j=1,nd2
if(a(i,j) > 0) then
b(i,j)=a(i,j)
else
b(i,j)=0
endif
enddo
enddo
Queste istruzioni in F90 possono essere sostituite dal costrutto where definito nel modo seguente
nome: where(E1)istruzioni 1elsewhere(E2) nomeistruzioni 2...elsewhere nomealtre istruzioniend where nome
• E1, E2, ... sono array logici della stessa dimensione dell’array da “manipolare”;
• il nome del costrutto e opzionale.
Nell’esempio, il costrutto where si scrivewhere(a>0)
b=a
elsewhere
b=0
end where
Se nell’esempio l’array b e “inizializzato” a zero (ad esempio nell’istruzione dichiarativa), il costruttowhere puo essere sostituito dall’istruzione where nel modo seguente
where(a>0) b=a
32
Il costrutto forall
In F90 e possibile il costrutto forall cosı definito:
nome: forall (i1=n1:m1:l1, i2=n2:m2:l2, ..., E)istruzione 1...istruzione kend forall nome
oppure, se si deve eseguire una sola istruzione
forall (i1=n1:m1:l1, i2=n2:m2:l2, ..., E)istruzione
• i1, i2, ... sono contatori (variabili intere) che variano rispettivamente da n1, n2,... a m1, m2,... conpasso l1, l2,...; i passi sono opzionali se valgono 1.
• E e un’espressione logica; l’espressione logica puo essere opzionale.
Ad esempio, sia a un array bidimensionale dichiarato nel modo seguente
integer, parameter::nd1=100, nd2=200
real, dimension(nd1,nd2) :: a
e si suppone che siano stati assegnati dei valori reali a tutte le componenti dell’array a. Si vuole sovrascri-vere sull’elemento a(i,j) con valore diverso da zero, il suo valore reciproco. Questo calcolo si puo eseguirecon un ciclo do nel modo seguente
do i=1,nd1
do j=1,nd2
if(a(i,j) /= 0)
enddo
enddo
Lo stesso risultato lo si puo ottenere con l’istruzione forall
forall (i=1:nd1, j=1:nd2, a(i,j)/=0) a(i,j)=1.0/a(i,j)
Il ciclo do elabora gli elementi nell’ordine stabilito dal ciclo o dai cicli se essi sono annidati. Il costruttoforall elebora gli elementi nell’ordine selezionato dal processore. Ad esempio, siano a e b due arraybidimensionali e siano stati assegnati valori non nulli agli elementi a(i,j) per i e j a valori da 1 ad n,con n variabile assegnata. Le istruzioni
forall (i=1:n, j=1:n)
a(i,j)=sqrt(a(i,j))
b(i,j)=1.0/a(i,j)
end forall
comportano che tutti i valori a(i,j), (i.e., a(1,1),...,a(n,n)) vengono calcolati prima di calcolare ilprimo elemento b(1,1).
I puntatori
In F90 e possibile definire un puntatore, ovvero una variabile contenente nessun dato ma indirizzi dimemoria di un’altra variabile dove sono memorizzati i dati. Si veda per una trattazione delle variabilipuntatori il Cap. 11 del libro di Chapman, Fortran 90/95: Guida alla Programmazione, McGraw–Hill,2004.
33
Il sottoprogramma function
In Fortran sono possibili i sottoprogrammi funzione (function).Sottoprogrammi funzione sono le funzioni intrinseche del linguaggio e le funzioni definite dall’utente.Sia funz una funzione definita dall’utente.
Il nome della funzione e una variabile e contiene il valore della funzione stessa.
La funzione funz ha una definizione come segue:
tipo function funz(argomenti separati da virgola)istruzioni dichiarativeistruzione eseguibile 1...istruzione eseguibile kfunz=espressionereturn
end
Supponiamo che la funzione funz sia di tipo reale e che gli argomenti della funzione funz siano le variabilix, y e z. La prima istruzione della funzione si scrive allora
real function funz(x,y,z)
oppure, utilizzando la dichiarazione implicita del Fortran
function funz(x,y,z)
Il programma principale (in generale un’unita di programma) si avvale della function funz medianteun’istruzione eseguibile come
y=funz(a,s,x)
dove a, s e x sono tre variabili allocate.L’argomento x della function funz “legge” il valore memorizzato nel programma principale dalla varia-bile a, l’argomento y della function funz “legge” il valore memorizzato nel programma principale dallavariabile s e l’argomento z della function funz “legge” il valore memorizzato nel programma principaledalla variabile x.Gli unici dati memorizzati sono quelli del programma principale, gli argomenti x, y e z della function
funz e in generale di un sottoprogramma, sono parametri formali che leggono, utilizzano ed eventualmentemodificano le aree di memoria dove sono memorizzati i dati ai quali vengono indirizzati con la “chiamata”alla funzione o al sottoprogramma.Una function e in generale un sottoprogramma puo essere chiamato dall’unita di programma chiamantepiu di una volta con dati diversi. Ad esempio sono valide le chiamate
...y1=funz(x,5,4*atan(1))
...y=funz(y,y,z)
• Gli argomenti separati da virgola sono le variabili globali della function;
• gli argomenti possono essere di tipo e di dimensioni diversi tra di loro;
• gli argomenti devono coincidere per numero e tipo con i valori indicati nella chiamata;
• nella function possono essere utilizzate anche variabili locali;
34
• nella function, le istruzioni di dichiarazione di variabili semplici, globali e locali, seguono le stesse re-gole della dichiarazioni di variabili semplici nel programma principale; vale ovviamente la dichiarazioneimplicita di tipo del Fortran;
• gli argomenti della function sono variabili di ingresso, l’unica variabile di uscita e il nome dellafunction;
• e possibile modificare i valori degli argomenti all’interno della function; ovviamente la modifica siha anche a livello dell’unita di programma chiamante.
Una modifica degli argomenti di una function non ha molto senso, in tal caso si usa una subroutine.Per ovviare a questo, il F90 ha un’istruzione opzionale di specifica per indicare quali variabili sonodi ingresso, quali di uscita e quali di ingresso e uscita.
Nell’esempio della function funz, la dichiarazione delle variabili globali (che si suppone sianoreali) x, y e z in F90 puo essere scritta
real, intent(in)::x,y,z
oppure, utilizzando la dichiarazione implicita del Fortran
intent(in)::x,y,z
In tal caso, la presenza nella function di un’istruzione eseguibile di modifica di un argomento comex=... provoca una segnalazione di errore in fase di compilazione;
• in F90 l’istruzione di fine, end, puo scriversi anche nei modi
end function end function nome funzione
• in ogni function, l’istruzione end e presente una sola volta;
• l’istruzione eseguibile return e l’istruzione di arresto di un sottoprogramma che significa “ritornare”al programma chiamante. Ci possono essere piu di una istruzione return all’interno di un sottopro-gramma. L’istruzione stop all’interno di un sottoprogramma provoca l’arresto dell’intero processo.
Se l’istruzione return non e presente nel sottoprogramma o non viene mai eseguita, il “ritorno” alprogramma chiamante avviene quando si incontra l’istruzione di fine sottoprogramma end.
Si consideri il seguente esempio che crea la funzione che calcola il fattoriale di un numero. Si utilizza ladichiarazione implicita di tipo del Fortran. La variabile contatore i e una variabile locale.
function ifatt(n)
ifatt=1
do i=2,n
ifatt=ifatt*i
enddo
return
end
In Fortran, una function puo avere la lista degli argomenti vuota. Ad esempio, la funzione che calcolala precisione di macchina si scrive
real function eps()
eps=1
5 if (eps+1.gt.1)then
eps=eps/2
goto 5
endif
eps=eps*2
return
end
35
Il sottoprogramma subroutine
In Fortran sono possibili i sottoprogrammi (subroutine).Sia sub1 una subroutine definita dall’utente. La subroutine sub1 ha una definizione come segue:
subroutine sub1(argomenti separati da virgola)istruzioni dichiarativeistruzione eseguibile 1...istruzione eseguibile kreturn
end
Supponiamo che gli argomenti della subroutine siano, nell’ordine, le variabili reali x, y e z. Il programmaprincipale (in generale un’unita di programma) si avvale della subroutine sub1 mediante un’istruzioneeseguibile come
call sub1(a,s,x)
dove a, s e x sono tre variabili allocate.L’argomento x della subroutine sub1 “legge” il valore memorizzato nel programma principale dalla va-riabile a, l’argomento y della subroutine sub1 “legge” il valore memorizzato nel programma principaledalla variabile s e l’argomento z della subroutine sub1 “legge” il valore memorizzato nel programmaprincipale dalla variabile x.Gli unici dati memorizzati sono quelli del programma principale, gli argomenti x, y e z della subroutine
sub1 e in generale di un sottoprogramma, sono parametri formali che leggono, utilizzano ed eventualmentemodificano le aree di memoria dove sono memorizzati i dati ai quali vengono indirizzati con la “chiamata”alla subroutine o al sottoprogramma.Una subroutine e in generale un sottoprogramma puo essere chiamato dall’unita di programma chiamantepiu di una volta con dati diversi. Ad esempio sono valide le chiamate
...call sub1(x,5,4*atan(1))
...call sub1(y,y,z)
• Gli argomenti separati da virgola sono le variabili globali della subroutine;
• gli argomenti possono essere di tipo e di dimensioni diversi tra di loro;
• gli argomenti devono coincidere per numero e tipo con i valori indicati nella chiamata;
• nella subroutine possono essere utilizzate anche variabili locali;
• nella subroutine, le istruzioni di dichiarazione di variabili semplici, globali e locali, seguono lestesse regole della dichiarazioni di variabili semplici nel programma principale; vale ovviamentela dichiarazione implicita di tipo del Fortran;
• gli argomenti della subroutine sono variabili di ingresso e di uscita. Se un argomento non vienemodificato all’interno della subroutine allora quell’argomento puo essere visto come una variabiledi solo ingresso; il F90 ha un’istruzione opzionale di specifica per indicare quali variabili sono diingresso, quali di uscita e quali di ingresso e uscita. Ad esempio se x e di ingresso, y e di uscita ez e di ingresso e uscita, allora le istruzioni di dichiarazione delle variabili x, y e z, nella subroutine,si possono scrivere:
real, intent(in)::x
real, intent(out)::y
real, intent(inout)::z
Le stesse istruzioni possono essere scritte omettendo la parola chiave real utilizzando la dichiarazioneimplicita di tipo del Fortran.
36
• in F90 l’istruzione di fine, end, puo scriversi anche nei modi
end subroutine end subroutine nome subroutine
• in ogni subroutine, l’istruzione end e presente una sola volta;
• l’istruzione eseguibile return e l’istruzione di arresto di un sottoprogramma che significa “ritornare”al programma chiamante. Ci possono essere piu di una istruzione return all’interno di un sottopro-gramma. L’istruzione stop all’interno di un sottoprogramma provoca l’arresto dell’intero processo.
Se l’istruzione return non e presente nel sottoprogramma o non viene mai eseguita, il “ritorno” alprogramma chiamante avviene quando si incontra l’istruzione di fine sottoprogramma end;
• ogni function puo essere scritta come una subroutine.
37
L’istruzione external
Nella scrittura di un programma principale puo capitare di passare una o piu function come argomentodi un sottoprogramma, senza che questa o queste function siano chiamate direttamente dal programmaprincipale in altri punti del codice.In questo caso la function, passata come argomento a un sottoprogramma, nel programma principaledeve essere dichiarata esterna. La stessa dichiarazione deve essere fatta nel sottoprogramma che legge echiama direttamente la function.Nell’istruzione dichiarativa, la parola chiave per dichiarare esterna una funzione e external.Ad esempio, supponiamo che un programma principale passi alla subroutine sub1 la funzione reale f1
mediante una chiamata della subroutine e la funzione reale f2 mediante una seconda chiamata dellasubroutine; ovvero nel programma principale si hanno le istruzioni dichiarative ed eseguibili
program nome programmaexternal f1,f2
...
...call sub1(..., f1, ...)
...call sub1(..., f2, ...)
...stop
end
f1 e f2 sono due function reali, ad esempio di due argomenti reali
real function f1(a,b)
...f1=...return
end
real function f2(a,b)
...f2=...return
end
Allora, la subroutine sub1 ha questa forma
subroutine sub1(..., f, ...)
external f
...
...z=f(x,y)
...return
end
Se nel programma principale una function passata come argomento di un sottoprogramma viene anche“chiamata” direttamente, allora essa non e piu external.
38
Ad esempio si puo avere la situazione
program nome programmaexternal f2
...
...call sub1(..., f1, ...)
...t=f1(r,s)
...call sub1(..., f2, ...)
...stop
end
L’istruzione contains in F90
I sottoprogrammi possono essere “contenuti” nel programma principale con l’istruzione contains.
• In un sottoprogramma “contenuto” nel programma principale, le variabili globali, ovvero quellepassate come argomenti sono trattate come in un sottoprogramma “non contenuto” nel programmaprincipale.
• In un sottoprogramma “contenuto” nel programma principale, le variabili non passate come argo-menti sono: locali se dichiarate esplicitamente nel sottoprogramma oppure globali se non dichiarateesplicitamente nel sottoprogramma.
Si osservi il codice Fortran descritto sotto
program test
real x,y,z
x=1; y=10; z=20
v=100; w=200
call sub1(x,y,w,x)
write(*,*)’ stampa dopo sub1 ’
write(*,*)’x = ’,x
write(*,*)’y = ’,y
write(*,*)’z = ’,z
write(*,*)’v = ’,v
write(*,*)’w = ’,w
write(*,*)’ ’
! ri-inizializzazione
x=1; y=10; z=20
v=100; w=200
call sub2(x,y,w,x)
write(*,*)’ stampa dopo sub2 ’
write(*,*)’x = ’,x
write(*,*)’y = ’,y
write(*,*)’z = ’,z
write(*,*)’v = ’,v
write(*,*)’w = ’,w
stop
39
contains
subroutine sub1(x1,y1,w1,x)
real x1,y1,x
real v
x1=x1+1
y1=y1+1
z=z+1
y=y+1
v=v+1
w1=w1+1
x=x+1
write(*,*)’ stampa di prova in sub1 ’
write(*,*)’x1 (x) = ’,x1
write(*,*)’y1 (y) = ’,y1
write(*,*)’z = ’,z
write(*,*)’y = ’,y
write(*,*)’v = ’,v
write(*,*)’w1 (w) = ’,w1
write(*,*)’x (x) = ’,x
return
end subroutine sub1
end program
subroutine sub2(x2,y2,w2,x)
real x2,y2,x
real v
x2=x2+1
y2=y2+1
z=z+1
y=y+1
v=v+1
w2=w2+1
x=x+1
write(*,*)’ stampa di prova in sub2 ’
write(*,*)’x2 (x) = ’,x2
write(*,*)’y2 (y) = ’,y2
write(*,*)’z = ’,z
write(*,*)’y = ’,y
write(*,*)’v = ’,v
write(*,*)’w2 (w) = ’,w2
write(*,*)’x (x) = ’,x
return
end subroutine sub2
40
che fornisce i seguenti risultatistampa di prova in sub1
x1 (x) = 3.0000000
y1 (y) = 12.000000
z = 21.000000
y = 12.000000
v = 1.00000000
w1 (w) = 201.00000
x (x) = 3.0000000
stampa dopo sub1
x = 3.0000000
y = 12.000000
z = 21.000000
v = 100.000000
w = 201.00000
stampa di prova in sub2
x2 (x) = 3.0000000
y2 (y) = 11.000000
z = 1.00000000
y = 1.00000000
v = 1.00000000
w2 (w) = 201.00000
x (x) = 3.0000000
stampa dopo sub2
x = 3.0000000
y = 11.000000
z = 20.000000
v = 100.000000
w = 201.00000
41
Il modulo in F90
In F90 e possibile definire il modulo. Il modulo (module) e un’unita di programma compilata a parte econtiene dichiarazioni e inizializzazioni di variabili e costanti che possono essere condivise da altre unitadi programma.Il modulo inizia con l’istruzione module nomemodulo e termina con l’istruzione end module nomemodulo.Un esempio di modulo e il seguente:
module dati
integer, parameter :: num=50
real, dimension(num) :: v=0,w=0
character(len=10) :: car
end module dati
L’unita di programma che utilizza tutte o in parte le variabili e le costanti allocate e/o inizializzate nelmodulo, specifica, come prima istruzione dichiarativa, che “utilizza” il modulo mediante la parolachiave use ed ha, ad esempio, la forma seguente
program nomep
use dati
...
write(*,*)’inserisci n<’,num
read(*,*)n
do i=1,n
v(i)=...
enddo
...
stop
end program
• il nome del modulo non ha nessuna relazione con il nome del file contenente il modulo;
• scrivere le istruzioni dichiarative nel modulo e come scriverle nell’unita di programma che usa ilmodulo; ovvero la scrittura seguente e equivalente ai due segmenti di programma sopra
program nomep
integer, parameter :: num=50
real, dimension(num) :: v=0,w=0
character(len=10) :: car
...
write(*,*)’inserisci n<’,num
read(*,*)n
do i=1,n
v(i)=...
enddo
...
stop
end program
• e possibile dichiarare variabili allocabili nei moduli; le variabili vengono allocate e deallocate nelleunita di programma che usano i moduli.
42
Un modulo puo contenere anche subroutine e function (procedure di modulo). La parola chiavecontains indica al compilatore che i sottoprogrammi successivi sono procedure di modulo.Ad esempio un modulo puo essere il seguente:
module miesub
contains
subroutine sub1(argomenti separati da virgola)istruzioni dichiarativeistruzioni eseguibiliend subroutine sub1
subroutine sub2(argomenti separati da virgola)istruzioni dichiarativeistruzioni eseguibiliend subroutine sub2
tipo funzione function f(argomenti separati da virgola)istruzioni dichiarativeistruzioni eseguibiliend function
end module miesub
Le unita di programma che utilizzano tutti o alcuni dei sottoprogrammi contenuti nel module miesub
dovranno specificare di “usare” il modulo mediante la parola chiave use. Ad esempio un programmaprincipale che usa il modulo miesub puo avere la forma seguente
program main
use miesub
...
call sub1(...)
...
stop
end program
Il vantaggio dell’uso di un sottoprogramma di modulo e dovuto al fatto che il compilatore controllagli argomenti del sottoprogramma. Vengono controllati, oltre al numero degli argomenti, al tipo e alloscopo (intent) come per i sottoprogrammi “non di modulo”, anche le dimensioni degli array “passati”al sottoprogramma (vedi la sezione Passaggio di array a sottoprogrammi).L’uso dei sottoprogrammi di modulo viene anche detto interfaccia esplicita, mentre per i sottoprogrammi“non di modulo” si parla di interfaccia implicita.
I moduli possono contenere sia dichiarazioni e inizializzazioni che sottoprogrammi. Ad esempio, unmodulo puo avere la forma:
module miesub
dichiarazioni e/o inizializzazionicontains
subroutine sub1(argomenti separati da virgola)istruzioni dichiarativeistruzioni eseguibiliend subroutine sub1
end module miesub
43
Passaggio di array a sottoprogrammi
In Fortran l’uso di array e flessibile. Si pensi ad esempio che, in un programma principale in cui unarray x e dichiarato
real x(10)
e possibile utilizzare componenti di x maggiori di 10. Ad esempio la scrittura
write(*,*)x(12)
e lecita e produce come risultato il numero reale memorizzato sui 32 bit successivi a partire da IND[x(1)]+12 ∗ 32 dove IND[x(1)] e l’indirizzo della prima componente allocata dell’array x.
Supponiamo di avere i seguenti array dichiarati nel programma principale in F77:
parameter(nx=10,ld=10,md=8)
real a(ld,md),x(nx),y(0:nx),z(nx*2)
e in F90:integer,parameter:: nx=10,ld=10,md=8
real,dimension(ld,md) :: a=0
real,dimension(nx) :: x=0
real,dimension(0:nx) :: y=0
real,dimension(nx*2) :: z=0
Supponiamo inoltre di avere le seguenti istruzioni eseguibili in Fortran di assegnazione di valori agliarray
do i=1,3
do j=1,3
a(i,j)=(i-1)*3+j
enddo
enddo
do i=1,3
x(i)=i*10
enddo
do i=0,8
y(i)=(i+1)*5
enddo
Gli array risultano avere questi valori:
a =
1 2 3 0 0 0 0 04 5 6 0 0 0 0 07 8 9 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 0
x =
1020300000000
y =
5101520253035404500
Si consideri una subroutine, chiamata submv2, che calcola il prodotto di una matrice per un vettore a cuiviene sommato un altro vettore di elementi pari al numero di righe della matrice.Ad esempio si vogliono calcolare le seguenti operazioni z(1)
z(2)
z(3)
=
1 2 34 5 67 8 9
102030
+
51015
44
e z(4)
z(5)
z(6)
=
1 2 34 5 67 8 9
102030
+
202530
e z(7)
z(8)
z(9)
=
1 2 34 5 67 8 9
102030
+
354045
In Fortran cio avviene con tre chiamate alla subroutine submv2
call submv2(a,ld,x,y,z,3,3)
call submv2(a,ld,x,y(3),z(4),3,3)
call submv2(a,ld,x,y(6),z(7),3,3)
Nelle tre chiamate alla subroutine, la scrittura del primo argomento a e equivalente alla scrittura a(1,1)
che indica che la chiamata “passa” l’indirizzo della prima componente dell’array.Nella prima chiamata della subroutine, la scrittura degli argomenti x, y, z indicano che la chiamata“passa” l’indirizzo della prima componente x(1), y(0) e z(1) dei rispettivi array; la prima chiamata allasubroutine si puo allora anche scrivere
call submv2(a(1,1),ld,x(1),y(0),z(1),3,3)
Nella seconda e terza chiamata, le scritture degli argomenti y(3), y(6), z(4) e z(7) indicano che lachiamata alla subroutine “passa” gli indirizzi specificati degli array y e z.
Utilizzando la dichiarazione implicita di tipo del Fortran, in F77, la parte dichiarativa della subroutinesubmv2 si puo scrivere in uno dei due modi seguenti
subroutine submv2(as,ls,xs,ys,zs,m,n)
real as(ls,*),xs(*),ys(*),zs(*)
subroutine submv2(as,ls,xs,ys,zs,m,n)
dimension as(ls,*),xs(*),ys(*),zs(*)
e in F90 in uno dei due modi seguenti
subroutine submv2(as,ls,xs,ys,zs,m,n)
real,intent(in),dimension(ls,*):: as
real,intent(in),dimension(*):: xs,ys
real,intent(inout),dimension(*):: zs
subroutine submv2(as,ls,xs,ys,zs,m,n)
real,intent(in):: as(ls,*),xs(*),ys(*)
real,intent(inout):: zs(*)
dove, in queste ultime istruzioni, se si utilizza la dichiarazione implicita di tipo del Fortran la parolachiave real puo essere omessa.In Fortran le istruzioni eseguibili e l’istruzione di fine della subroutine submv2 si scrivono
do i=1,m
zs(i)=0
enddo
do i=1,m
do j=1,n
zs(i)=zs(i)+as(i,j)*xs(j)
enddo
do i=1,m
zs(i)=zs(i)+ys(i)
enddo
return
end
Per quanto concerne il passaggio di array monodimensionali:
45
• il parametro formale xs, in tutte le chiamate della subroutine “legge” il valore memorizzato nelprogramma principale nell’array x a partire da x(1); ovvero xs(1) “legge” x(1), xs(2) “legge”x(2) e cosı via.
Il parametro formale ys, nella prima chiamata della subroutine, “legge” il valore memorizzato nelprogramma principale nell’array y a partire da y(0); ovvero ys(1) “legge” y(0), ys(2) “legge”y(1) e cosı via; nella seconda chiamata ys(1) “legge” y(3), ys(2) “legge” y(4) e cosı via; nellaterza chiamata ys(1) “legge” y(6), ys(2) “legge” y(7) e cosı via.
Il parametro formale zs, nella prima chiamata della subroutine, “legge” il valore memorizzato nelprogramma principale nell’array z a partire da z(1); ovvero zs(1) “legge” z(1), zs(2) “legge”z(2) e cosı via; nella seconda chiamata zs(1) “legge” z(4), zs(2) “legge” z(5) e cosı via; nellaterza chiamata zs(1) “legge” z(7), zs(1) “legge” z(8) e cosı via;
• se ad esempio, per la variabile zs la dichiarazione nella subroutine e
real zs(0:*)
allora nella prima chiamata della subroutine, zs(0) “legge” z(1), zs(1) “legge” z(2) e cosı via;nella seconda chiamata zs(0) “legge” z(4), zs(1) “legge” z(5) e cosı via; nella terza chiamatazs(0) “legge” z(7), zs(1) “legge” z(8) e cosı via;
• il simbolo * (asterisco) nella dichiarazione dell’array monodimensionale e un segnaposto; analoga-mente al posto del simbolo * (asterisco) si puo indicare 1, 2, n o altre costanti o variabili globali.
Per quanto concerne il passaggio di array bidimensionali:
• il parametro formale as in tutte le chiamate della subroutine “legge” il valore memorizzato nelprogramma principale nell’array a a partire da a(1 1); ovvero as(1 1) “legge” a(1 1), as(2 1)
“legge” a(2 1) e cosı via lungo le colonne dell’array a;
• poiche il Fortran memorizza gli elementi di un array bidimensionale “per colonne”, al sottopro-gramma deve essere noto il numero di righe dell’array bidimensionale memorizzato nel programmaprincipale chiamante, ovvero la grandezza leading. In questo modo, come nell’esempio, l’elementoas(1 2) del parametro formale as “legge” il valore memorizzato in a(1 2);
• il simbolo * (asterisco) nella seconda posizione nella dichiarazione dell’array bidimensionale e unsegnaposto; analogamente al posto del simbolo * (asterisco) si puo indicare 1, 2, n o altre costantio variabili globali.
• consideriamo ad esempio, la seguente chiamata alla subroutine
call submv2(a,x,y,z,3,3)
con la seguente parte della subroutine riguardante l’array as
subroutine submv2(as,xs,ys,zs,m,n)
real as(m,n)
allora, in questo caso l’elemento as(1 1) “legge” a(1 1), as(2 1) “legge” a(2 1), as(3 1) “legge”a(3 1), as(1 2) “legge” a(4 1), as(2 2) “legge” a(5 1), e cosı via; ovvero gli elementi di a chevengono utilizzati nella subroutine sono 1 0 0
4 0 07 0 0
Se si vuole che l’elemento as(i,j) “legga” l’elemento a(i,j), questa dichiarazione comporta una“lettura non corretta”;
46
• consideriamo ad esempio, la seguente chiamata alla subroutine
call submv2(a,x,y,z,3,3)
con la seguente parte della subroutine riguardante l’array as
subroutine submv2(as,xs,ys,zs,m,n)
parameter(ns=10)
real as(ns,ns)
in questo caso l’array as “legge correttamente” i corrispondenti elementi dell’array a.
Questa scrittura e fortemente sconsigliata in quanto vincola la “corretta lettura” dell’array bidi-mensionale ad una costante locale (in questo caso ns) che deve essere uguale alla grandezza leadingdell’array bidimensionale memorizzato nel programma principale; una chiamata allo stesso sotto-programma con un altro array con grandezza leading differente provocherebbe una “lettura noncorretta”.
Passaggio di array allocati dinamicamente
Si consideri la subroutine che calcola il prodotto matrice per vettore
subroutine mv(a,v,w,n,m,ld)
real, dimension(ld,*)::a
real, dimension(*)::v,w
do i=1,m
w(i)=0
do j=1,n
w(i)=w(i)+a(i,j)*v(j)
enddo
enddo
return
end
Il programma seguente calcola mediante la subroutine mv il prodotto matrice per vettore; gli arrayutilizzati sono allocati dinamicante.
program arrayallocabili
real,allocatable,dimension(:,:)::a
real,allocatable,dimension(:)::x,y
read(*,*)n
allocate(a(n,n),x(n),y(n))
do i=1,n
read(*,*)(a(i,j),j=1,n)
enddo
read(*,*)(x(i),i=1,n)
call mv(a,x,y,n,n,n)
write(*,*)(y(i),i=1,n)
stop
end
In questo caso il numero di righe dell’array a del programma principale e n e dunque, per avere una“corretta lettura”, la chiamata alla subroutine deve “passare” n come grandezza leading.
47
Operazioni globali e inizializzazioni all’interno di un sottoprogramma
Si consideri il seguente sottoprogramma in F90 che esegue la somma di due array
subroutine sub1(x,y,z,n)
real, dimension(*)::x,y,z
do i=1,n
z(i)=x(i)+y(i)
enddo
return
end
Il simbolo * (asterisco) come segnaposto non permette l’utilizzo delle operazioni globali. Per poter utiliz-zare l’operazione globale z=x+y per sommare le prime n componenti di x e y, si modifica il sottoprogrammain
subroutine sub1(x,y,z,n)
real, dimension(n)::x,y,z
z=x+y
return
end
Analogamente se si vuole inizilizzare un array all’interno di un sottoprogramma in F90, non si deveutilizzare il simbolo * (asterisco) come segnaposto. Ad esempio il seguente segmento di parte dichiarativadi un sottoprogramma
subroutine sub1(a,ld,v,w,n)
real,intent(out),dimension(ld,n)::a=0
real,intent(out),dimension(n)::w=0
real,intent(in),dimension(*)::v
inizializza a zero le variabili di uscita a e w rispettivamente nelle componenti a(i,j), i=1,ld, j=1,n ew(i), i=1,n.
Variabili mute (dummy)
Le variabili semplici locali di un sottoprogramma sono usualmente contatori di cicli, indici di componentidi array globali o variabili di “appoggio” per operazioni come lo scambio (swap).L’utilizzo di array locali e fortemente sconsigliato. Ad esempio, supponiamo di avere il seguente segmentodi programma principale in cui gli array sono allocati staticamente
program prova
real v(1000)
...
n=200
do i=1,n
v(i)=1/(i+1)
enddo
...
call sub1(v,n,...)
...
end
e di avere il segmento di subroutine sub1 in cui si ha necessita di salvare i valori di v in un array locale
subroutine sub1(x,m,...)
real x(*),w(100)
...
do i=1,m
w(i)=x(i)
enddo
...
end
48
Poiche il parametro formale m “legge” il valore 200, il ciclo dentro la subroutine viene eseguito ma nonc’ e controllo dove sono stati memorizzati i valori letti da x(101),...,x(200). E preferibile rendere mutol’array w considerandolo globale. Ovvero si modifica il programma principale e la subroutine nel modoseguente
program prova
real v(1000),work(1000)
...
n=200
do i=1,n
v(i)=1/(i+1)
enddo
...
call sub1(v,n,work...)
...
end
subroutine sub1(x,m,w,...)
real x(*),w(*)
...
do i=1,m
w(i)=x(i)
enddo
...
end
Tutte le considerazioni viste su passaggi di array a sottoprogrammi valgono ovviamente anche se i sotto-programmi sono function oppure procedure di modulo.
Alternativamente, in F90 si puo allocare dinamicamente l’array w scrivendo il codice nel modo seguente
subroutine sub1(x,m,w,...)
real, allocatable, dimension(:):: w
real x(*)
...
allocate(w(m))
do i=1,m
w(i)=x(i)
enddo
...
deallocate(w)
end
Passaggio di array con dimensioni diverse
Si consideri la subroutine mv che calcola il prodotto matrice per vettore vista in precedenza. Utilizziamoquesta subroutine per calcolare il prodotto scalare tra due vettori e per calcolare il prodotto matrice permatrice.Per la scrittura di un programma principale che calcola il prodotto scalare tra vettori, sia la partedichiarativa di due array monodimensionali scritta come segue
paramter(ix=100)
real x(ix),y(ix)
Supponendo che il programma principale legga o calcoli due vettori di lunghezza n memorizzati negliarray x e y, la chiamata
call mv(x,y,s,n,1,1)
49
restituisce nella variabile reale s il valore del prodotto scalare tra i due vettori.Per la scrittura di un programma principale che calcola il prodotto tra due matrici, sia la parte dichiarativadi tre array bidimensionali scritta come segue
paramter(ix=100,jx=50)
real a(ix,jx),b(ix,jx),c(ix,jx)
Supponendo che il programma principale legga o calcoli due matrici quadrate di ordine n memorizzatenegli array a e b, le chiamate
do j=1,n
call mv(a,b(1,j),c(1,j),n,n,ix)
enddo
restituiscono nell’array c il prodotto tra le due matrici memorizzate in a e b. Si nota che la matriceottenuta dal prodotto di due matrici ha per colonne i vettori risultanti dal prodotto della prima matriceper le rispettive colonne della seconda.Si osserva che, in entrambi i casi, non c’ e corrispondenza delle dimensioni degli array tra gli argomentidella chiamata e i parametri formali della subroutine. Ad esempio, nell’ultimo caso il secondo argomentodella chiamata e l’indirizzo di un array bidimensionale che viene “letto” da un parametro formale con unsolo indice.Questi passaggi di array non corrispondenti di dimensione possono anche essere effettuati a sottopro-grammi function ma non si possono eseguire se il sottoprogramma e una procedura di modulo.
50