Installazione di un compilatore Per installare un compilatore Fortran

Transcript

Installazione di un compilatore Per installare un compilatore Fortran
Installazione di un compilatore
Per installare un compilatore Fortran, ad esempio il compilatore gfortran, si procede come segue.
Sui computer su cui è 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 alle
sezioni MacOS e GNU/Linux.
Ad esempio, per il sistema operativo MacOS scegliere una delle versioni del compilatore in base alla
versione del sistema operativo. Per le versioni più recenti scegliere Yosemite.
Perché il compilatore possa essere eseguito è necessario che sul computer sia presente l’applicazione
Xcode. Se non è presente (o se non sono installati i command line tools), “cliccare” su detailed
instructions 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” su
install).
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 è a 64 o
a 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 .f
Il 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 che
viene 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, dal
direttorio dove è 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 linguaggio
inclusa) 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 è scritto un codice che contiene il programma
principale ed alcuni sottoprogrammi chiamati dal programma principale stesso e, in un altro file, che si
chiama file2.f sono scritti altri sottoprogrammi richiamati comunque dal programma principale (che è
scritto in file1.f), allora la compilazione deve creare un unico file eseguibile contenente le traduzioni in
linguaggio 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 è presente un modulo (sia di dati o di sottoprogrammi o di dati e di sottoprogrammi insieme) che
è stato salvato nel file denominato miomodulo.f, si deve prima compilare il modulo con l’opzione -c
mediante 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 il
modulo memorizzato nel file miomodulo.f. Ad esempio se il file fileXX.f usa il modulo memorizzato
nel 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, ad
esempio:
• 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, Milano, 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 Scientifico.
• Versioni Fortran: Fortran I (1957), Fortran II e Fortran III (1958), Fortran IV (1961), Fortran
66 (1966), Fortran 77 (1977), Fortran 90 (1990), Fortran 95 (1995), Fortran 2003 (2003), Fortran
2008 (2008).
• Programma Fortran composto da un programma principale (detto Main) e da uno o più sottoprogrammi (Function e/o Subroutine).
• Il programma principale e ciascun sottoprogramma è detto unità di programma.
• Il programma principale con (o senza) i sottoprogrammi richiamati dal programma principale, è
contenuto in un file identificato da un nome.estensione.
• il compilatore Fortran riconosce come file scritti in linguaggio Fortran (e dunque da tradurre in
linguaggio macchina) quelli con una particolare estensione. Generalmente i compilatori Fortran
riconoscono, 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 un
file Fortran che viene compilato insieme al file Fortran che contiene il programma principale per
creare 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 tutte
o alcune istruzioni scritte in Fortran 77.
Nel seguito si indica con Fortran le regole e le istruzioni comuni alle versioni Fortran 77 e Fortran
90/95/2003; con F77 le istruzioni solo per la versione Fortran 77 e con F90 le istruzioni solo per le
versioni Fortran 90/95/2003.
Due testi di riferimento per il linguaggio Fortran, rispettivamente nelle versioni 77 e 90/95 sono, ad
esempio:
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, Milano, 2004.
4
Struttura di un programma
Un programma principale in Fortran è strutturato come segue:
program nome
istruzioni dichiarative di variabili e costanti
istruzioni eseguibili (statements)
end
• program ed end sono parole chiave;
• end è l’istruzione di fine; è obbligatoria e deve essere presente una sola volta in ogni unità di
programma come ultima istruzione;
• program nome è l’istruzione che assegna al programma un nome simbolico:
– il nome del programma non ha nessuna relazione con il nome del file contenente il programma
stesso;
– il nome del programma deve essere diverso dal nome delle variabili, delle costanti e delle
function presenti nel programma;
– l’istruzione program nome è opzionale;
– in F90: l’istruzione end può essere sostituita dall’istruzione
end program
oppure da
end 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) è identificata da una a cinque cifre scritte consecutivamente, la prima diversa
da 0 (ovvero sono numeri interi da 1 a 99999):
– l’etichetta si ha solo per le istruzioni eseguibili;
– non si possono avere più istruzioni con la stessa etichetta;
– più 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 può essere etichettata
con 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 come
lo stesso carattere), le cifre (da 0 a 9) e il carattere (sottolineatura); le lettere e le cifre si
chiamano anche caratteri alfanumerici e versioni non recenti di compilatori F77 riconoscono i
nomi solo costituiti dai caratteri alfanumerici;
– devono iniziare con una lettera;
5
– non possono essere più lunghi di 31 caratteri (versioni non recenti di compilatori F77 riconoscono solo nomi con al massimo 6 caratteri);
– non possono essere uguali a parole chiave;
• nelle istruzioni, non vi è distinzione tra lettere maiuscole e minuscole;
• il carattere di spaziatura (blank) può essere usato per migliorare la leggibilità di un programma; il
compilatore ignora il carattere di spaziatura.1
In F77 ogni riga in un’unità di programma deve essere conforme alle seguenti regole di posizione della
colonna:
• colonne 1–5: riservate alle etichette;
• colonna 1: la presenza dei caratteri c, C oppure * indica che la riga è una riga di commento; questa
riga non viene processata dal compilatore;
• colonna 6: la presenza di un carattere (eccetto 0 e la spaziatura) indica che sulla riga c’è la continuazione dell’istruzione della riga precedente. Ovvero la linea di codice è scritta su due righe. Si
può 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 numerare
le linee di codice.
In F90:
• l’istruzione può iniziare da colonna 1 (in poi);
• le etichette possono iniziare da colonna 1 (in poi) e l’istruzione sottointesa dall’etichetta può iniziare
dal 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, ciò che è scritto dal carattere ! in poi viene ignorato dal compilatore; in generale, da
! in poi si scrivono i commenti (questa regola viene anche riconosciuta nei più recenti compilatori
F77);
• nelle istruzioni dichiarative ed eseguibili il carattere ; (punto e virgola) separa istruzioni scritte
sulla stessa riga.
1 Ovviamente il carattere di spaziatura non viene ignorato dal compilatore, che anzi segnala errore, se esso è posizionato
internamente 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 è 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 è i,j,k,l,m,n, ovvero tutte le lettere
dell’alfabeto inglese dalla a alla h e dalla o alla z, sono implicitamente dichiarate reali in precisione
semplice.
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, complesso), 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 è riservata al segno (opzionale se positivo) e le altre all’esponente del
numero (espresso in base 10) che per i numeri in precisione semplice, ovvero memorizzati su 32 bit, al
massimo è 38 mentre per i numeri in precisione doppia, ovvero memorizzati su 64 bit è 308.
In Fortran, nella stringa ’il valore e’’=’, il terzo apice, scritto subito dopo il secondo apice, serve
ad indicare che il secondo apice non è il carattere di fine stringa ma è un carattere da scivere; il quarto
apice è il carattere di fine stringa. Il risultato delle stringa è
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 e
di 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 ::
parameter ::
pi=3.1415, ic=200
eps=1.e-7
Si osserva che in F77 le istruzioni
parameter(pi=3.1415)
real pi
non sono corrette, in quanto viene assegnato il valore 3.1415 alla variabile pi che viene implicitamente
dichiarata intera e, con l’istruzione di dichiarazione successiva, la costante pi viene dichiarata esplicitamente. Il compilatore segnala una doppia dichiarazione.
In Fortran è possibile assegnare il valore ad una costante mediante espressioni aritmetiche, designatori
di funzioni matematiche elementari e mediante l’utilizzo di costanti assegnate in precedenza. Ad esempio
sono possibili le istruzioni, rispettivamente in F77 e F90
parameter(pi=4*atan(1))
parameter ::
parameter(pi2=2*pi)
parameter ::
parameter(nx=100,nx2=nx*2) parameter ::
pi=4*atan(1)
pi2=2*pi
nx=100,nx2=nx*2
Variabili semplici
In Fortran le variabili semplici si dichiarano implicitamente (come specificato all’inizio) oppure esplicitamente. Per la dichiarazione esplicita si usano le 6 parole chiave di tipo e si elencano i nomi delle variabili
separate da una virgola.
Ad esempio in F77 e F90 rispettivamente, in una unità di programma, si possono avere le seguenti
istruzioni dichiarative:
real a,b
real c
integer d,it
double precision r1
complex z
logical z1
character iniziale
character*10 prima
character ultima*10
character*15 id
real*4 :: a,b
real :: c
integer :: d,it
real*8 r1
complex :: z
logical :: z1
character :: iniziale
character(len=10) :: prima, ultima
character(15) :: id
• In F90 per le variabili di tipo reale in precisione semplice si usa indistintamente la parola chiave
real o real*4 (4 sta per 4 byte). La parola chiave real*4 è comunque riconosciuta anche dai più
recenti 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 è comunque riconosciuta anche dai più recenti compilatori F77.
• In F90 è possibile assegnare variabili intere su 16 bit (2 byte) con l’istruzione dichiarativa2
integer*2 ::
x,y
2 In F90 è anche possibile impostare la precisione in modo indipendente dal processore mediante le istruzioni kind e
select 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) composta da un carattere (8 bit), due variabili carattere (di nome prima e ultima) composte da 10
caratteri ciascuna e una variabile (di nome id) di 15 caratteri.
• len è una parola chiave che sta per length (lunghezza).
• Nell’esempio, utilizzando la dichiarazione implicita del Fortran, le istruzioni di dichiarazioni delle
variabili 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 più di una parola chiave per tipo in un’unità di programma. Nell’esempio
le parole chiave real e character sono ripetute per dichiarare variabili diverse.
In F90 si può assegnare il valore (iniziale) di una variabile nell’istruzione di dichiarazione (esplicita). Ad
esempio 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 è possibile rendere inattiva la dichiarazione implicita inserendo, come prima istruzione dichiarativa, l’istruzione
implcit none
In tal caso ogni variabile (semplice o con indice) e costante con nome dovrà essere dichiarata esplicitamente.
L’istruzione implicit può essere usata per dichiarare implicitamente alcune variabili. Ad esempio, le
istruzioni in F77 e F90 rispettivamente
implicit integer(a)
real a1
implicit, integer ::
real :: a1
a
producono il risultato che, sono intere tutte le variabili (semplici o con indice) che iniziano per a, ad
eccezione della variabile semplice a1 che è dichiarata reale in precisione semplice.
Ad esempio, per dichiarare implicitamente in doppia precisione il tipo di tutte le variabili (semplici o con
indice) che iniziano per le lettere dell’alfabeto inglese dalla a alla d e dalla o alla z e con la lettera g, le
istruzioni 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 double precision(g)
3 È
implicit, real*8 ::a-d,o-z
implicit, real*8 ::g
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 e
sono definite mediante la dichiarazione di tipo e di dimensione.
• Quando si dichiara una variabile strutturata il compilatore assegna lo spazio sufficiente per memorizzarne tutte le componenti.
• L’allocazione in memoria delle componenti dell’array crea un insieme di locazioni contigue, il cui
numero è definito dalle dichiarazioni di tipo e di dimensione.
La dichiarazione completa (tipo e dimensione) degli array in un programma principale prevede la specifica
del 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 dichiarazione
di variabili con indice si scrive rispettivamente
tipo1 nome1
tipo2 nome2
dimension nome1(e1:e2),nome2(e3:e4,e5:e6)
tipo1, dimension(e1 : e2) :: nome1
tipo2, dimension(e3 : e4, e5 : e6) :: nome2
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 più variabili dello stesso tipo (in F77) o dello stesso tipo e stessa dimensione (in F90), queste
possono essere elencate nella stessa istruzione dichiarativa separate da virgola.
Si riportano alcuni esempi di specifica di tipo e di dimensione che possono presentarsi nelle istruzioni
dichiarative di un programma principale:
integer imax
parameter(imax=70)
real a, b, x, a1
real b1
integer c
character*4 car
dimension a(100),x(0:50),c(imax),a1(0:imax-1,imax)
dimension b(100),b1(10,10),car(-10:10)
integer,parameter::imax=70
real,dimension(100)::a,b
real,dimension(0:50)::x
real,dimension(0:imax-1,imax)::a1
real,dimension(10,10)::b1
integer,dimension(imax)::c
character(len=4),dimension(-10,10)::car
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)
dimension a(100),x(0:50),a1(0:imax-1,imax)
character*4 car
dimension b(100),b1(10,10),car(-10:10)
dimension ic(imax)
parameter::imax=70
dimension(100)::a,b
dimension(0:50)::x
dimension(0:imax-1,imax)::a1
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 dichiarazione
di tipo, la dimensione della variabile nel nome. Dunque, queste ultime istruzioni si scrivono
parameter(imax=70)
real a(100),x(0:50), a1(0:imax-1,imax)
character*4 car(−10 : 10)
real b(100),b1(10,10)
integer ic(imax)
parameter::imax=70
real::a(100),b(100),x(0:50),b1(10,10)
real::a1(0:imax-1,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 volta
sola.
• In Fortran, come per le variabili semplici, si possono avere più di una parola chiave per tipo in
un’unità di programma (la parola chiave real nell’esempio).
• In F77 la sequenza di istruzioni
dimension a(100)
real a
non è corretta; il compilatore segnala una doppia dichiarazione.
• In F90, come per le variabili semplici, per l’assegnazione di variabili con indice, i caratteri :: (due
volte due punti) sono opzionali.
• In F90, come per le variabili semplici, è possibile assegnare valori alle variabili (inizializzare) nelle
istruzioni 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 una
dimensione a e b vengono asssegnati i valori 0 per le componenti a(i) di a con i=1,...,100, e i valori
0,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 è specificata come segue:
1. si indichi con tipo una parola chiave di specifica di tipo (e.g., real, integer,...), e con l il numero
di bit necessari per un valore di tipo (e.g. l = 32 se tipo è integer o real*4, l = 64 se tipo è
real*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 con
IN D[v(i0)]
e
IN D[a(i0,j0)]
gli indirizzi in memoria della prima componente, rispettivamente dell’array v e a, allora gli indirizzi in
memoria delle componenti v(i) e a(i,j) sono
IN D[v(i)] =
IN D[a(i,j)] =
IN D[v(i0)] + (i-i0) ∗ l
IN D[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), quelli
della terza (j=3) sono “sotto” quelli della seconda (j=2) e cosı̀ via. Ovvero, il Fortran, memorizza i
dati di un array per colonna. Il valore LD è detto leading.
4 In
F90 non si può 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 memoria
bisogna 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 modo
da essere “sufficientemente grande” per risolvere il problema corrente. In tal modo non c’è spreco di
memoria e consente che il programma sia eseguito da calcolatori che hanno poca o molta memoria di
RAM indistintamente.
Un array che utilizza la memoria in modo dinamico viene dichiarato allocabile e viene allocato, mediante
un’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 due
dimensioni, ad esempio reali, è la seguente
real, allocatable, dimension(:):: x,y
real, allocatable, dimension(:,:):: a
• i due punti : sono dei segnaposto; non si conosce quanto è grande l’array;5
• array allocabili non possono essere inizializzati ad un valore nell’istruzione dichiarativa;
• un array dichiarato con i due punti : è detto array a forma differita; per contro un array le cui
dimensioni sono dichiarate esplicitamente in un’istruzione di dichiarazione è detto array di forma
esplicita.
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’array
a 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 da
allocare, 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’istruzione
eseguibile. Essi possono essere costanti intere con o senza nome, variabili intere di cui è noto il valore al
momento 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, oppure
un valore intero positivo (dipende dal compilatore) se l’allocazione non ha avuto successo, ovvero
si richiede troppa memoria rispetto a quella messa a disposizione dal compilatore quando abbiamo
dichiarato l’array allocabile.
Alla fine del processo in cui si usano array allocabili si “rilascia” la memoria con l’istruzione di “deallocazione”; ad esempio se si “dealloca” l’array a, l’istruzione è
deallocate(a,stat=info)
e se la variabile intera info è uguale a zero, allora la “deallocazione” di a ha avuto successo. Se non è
presente l’istruzione di “deallocazione”, essa avviene quando si esegue l’istruzione di fine (end).
5 Il
compilatore riserva un’area di memoria la cui grandezza è sconosciuta al programmatore.
12
Funzioni intrinseche
In Fortran esistono più di 40 funzioni intrinseche. Sono funzioni intrinseche le funzioni matematiche
elementari e le funzioni di conversioni di tipo. Le funzioni intrinseche si scrivono con un designatore di
funzione 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 argomenti.
Per abbreviazione, si indica in tabella con I, R, D, C, Z rispettivamente il tipo intero, reale in precisione
semplice, reale in precisione doppia, carattere e complesso dell’argomento x e del risultato. Ad esempio
tra le funzioni matematiche elementari vi sono
funzione
tipo dell’argomento
tipo del risultato
definizione
abs(x)
sqrt(x)
mod(x,y)
sign(x)
exp(x)
log(x)
log10(x)
sin(x)
cos(x)
tan(x)
asin(x)
acos(x)
atan(x)
sinh(x)
cosh(x)
tanh(x)
IRDZ
RDZ
I
IRD
RDZ
RDZ
RD
RDZ
RDZ
RD
RD
RD
RD
RD
RD
RD
IRDR
RDZ
I
I
RDZ
RDZ
RD
RDZ
RDZ
RD
RD
RD
RD
RD
RD
RD
|x|
√
x
resto di x/y
segno di x
ex
loge x
log10 x
sin x
cos x
tan x
arcsin x
arccos x
arctan x
sinh x
cosh x
tanh x
Le funzioni di conversione di tipo sono:
funzione
tipo dell’argomento
tipo del risultato
int(x)
real(x)
dble(x)
ichar(x)
char(x)
IRD
IRD
IRD
C
I
I
R
D
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 ASCII
dell’argomento carattere e nel carattere ASCII del corrispondente valore intero dell’argomento.
In Fortran l’argomento di una funzione può essere una costante, una variabile, un’espressione o anche il
risultato di un’altra funzione. Ad esempio sono valide le seguenti istruzioni di assegnazione alla variabile
y 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 del
segno 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 è un’espressione aritmetica, rispettivamente IRDZ;
2. ogni costante, con o senza nome, IRDZ è un’espressione aritmetica, rispettivamente IRDZ;
3. ogni funzione intrinseca con risultato IRDZ è un’espressione aritmetica rispettivamente
IRDZ;
4. se X è un’espressione aritmetica, anche (X) è un’espressione aritmetica;
5. se X ed Y sono due espressioni aritmetiche, anche X + Y , X − Y , X ∗ Y , X/Y e X ∗ ∗Y
sono espressioni aritmetiche;
6. se applichiamo un numero finito di volte le regole 1–5 si ottiene un’espressione aritmetica;
– priorità: parentesi più interne fino alle più esterne, valutazione di funzioni, elevamento a
potenza, divisione/moltiplicazione, addizione/sottrazione. A parità di livello di parentesi, le
operazioni si svolgono da sinistra verso destra tranne l’elevamento a potenza che si svolge da
destra verso sinistra;
– espressione aritmetica tra operandi di tipo diverso7
x
y
x⊗y
I I I
I R D
I R D
R R
R D
R D
D
D
D
Si osservi il risultato delle seguenti istruzioni, supponendo di usare la dichiarazione implicita
di variabili:
i=2/3
risultato: i=0
i=2./3
risultato: i=0
x=2/3
risultato: x=0
x=2./3
risultato: x=0.6
i=2; j=3; x=i/j
risultato: x=0
i=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 è un valore logico.
6 Per abbreviazione, si indica con I, R, D, Z rispettivamente il tipo intero, reale in precisione semplice, reale in precisione
doppia e complesso.
7 Con 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 è un’espressione logica;
2. ogni costante con o senza nome di tipo logico è un’espressione logica;
3. ogni espressione relazionale è un’espressione logica;
4. se X è un’espressione logica, anche (X) è un’espressione logica;
5. se X ed Y sono due espressioni logiche, anche X opl Y è un’espressione logica;
6. se applichiamo un numero finito di volte le regole 1–5 si ottiene un’espressione logica.
– priorità: parentesi più interne fino alle più 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 oppure
goto 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 è presente l’istruzione di salto condizionato altrimento detta di if aritmetico. Questa
istruzione 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 è minore o
uguale a 0.
◦ Se l1 = l2 = l3, l’istruzione è 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 di
salto condizionato è 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 va
confusa con l’istruzione di fine programma (end) che non è un’istruzione eseguibile. Ci possono essere più
istruzioni eseguibili di arresto stop ma, per ogni unità di programma ci deve essere una sola istruzione
di fine programma end.
Se un’istruzione di arresto non è presente nel programma, il programma si arresta quando trova l’istruzione
di fine programma end.
8 Si
indica con opl un qualsiasi operatore logico.
15
Istruzione di condizione
In Fortran è prevista l’istruzione di condizione o di if logico. Se si indica con C un’espressione logica
l’istruzione di condizione ha la forma
if (C) then
istruzione/i
endif
oppure
if (C) then
istruzione/i 1
else
istruzione/i 2
endif
Nel primo caso (costrutto if–then) si eseguono le istruzioni se l’espressione logica C è vera, nel secondo
caso (scelta dicotomica o costrutto if–then–else) si eseguono le istruzioni 1 se l’espressione logica
C è vera e le istruzioni 2 se l’espressione logica C è falsa.
Nel caso in cui ci sia una sola istruzione da eseguire se l’espressione logica C è vera, in Fortran si prevede
anche la scrittura dell’istruzione di condizione in un’unica riga (istruzione di if)
if (C) istruzione
In Fortran vi è anche il costrutto elseif che si presenta nella seguente forma9
if (C1) then
istruzione/i 1
elseif (C2) then
istruzione/i 2
else
istruzione/i 3
endif
Il risultato è l’esecuzione dell’istruzione/i 1 se C1 è vera, dell’istruzione/i 2 se C1 è falsa e C2 è vera e
dell’istruzione/i 3 se C1 e C2 sono entrambe false.
Il costrutto si può ampliare introducendo altre condizione di elseif. Ad esempio
if (C1) then
istruzione/i 1
elseif (C2) then
istruzione/i 2
elseif (C3) then
istruzione/i 3
else
istruzione/i 4
endif
In tal caso l’istruzione/i 1 è eseguita se C1 è vera, l’istruzione/i 2 è eseguita se C1 è falsa e C2 è vera,
l’istruzione/i 3 è eseguita se C1 e C2 sono false e C3 è vera e l’istruzione/i 4 è eseguita se C1, C2 e C3
sono false.
Le parole if, then, else, elseif e endif sono parole chiave.
9 Si
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 sequenzialmente
l’esecuzione del programma.
Si può verificare che il costrutto if–then–else può essere ottenuto mediante le istruzioni if, goto e
continue.
continue è una parola chiave.
Il ciclo do
Il ciclo do (do–loops) è il costrutto del linguaggio Fortran per eseguire una o più istruzioni (nucleo del
ciclo) 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,
l
c = e1, e2, e3
istruzione/i
continue
Il ciclo do in F90 ha la seguente forma (costrutto do–enddo)
do c = e1, e2, e3
istruzione/i
enddo
dove, in Fortran:
• do e enddo sono parole chiave;
• c è la variabile contatore, preferibilmente intera;
• e1 è una variabile, una costante o, in generale, un’espressione aritmetica, preferibilmente intera,
che indica il valore di inizio ciclo ed è il primo valore che assume il contatore c;
• e2 è una variabile, una costante o, in generale, un’espressione aritmetica, preferibilmente intera,
che indica il valore di fine ciclo;
• e3 è una variabile, una costante o, in generale, un’espressione aritmetica, preferibilmente intera e
comunque non nulla, che indica il valore del passo del ciclo. È 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 è positivo, le istruzioni che costituiscono il nucleo del ciclo sono eseguite se e2≥e1.
◦ Se e3 è negativo (ciclo a ritroso), le istruzioni che costituiscono il nucleo del ciclo sono eseguite se
e1≥e2.
Per quanto concerne le regole del ciclo sopra descritto:
• non è possibile modificare il valore della variabile contatore c o di e1 o di e2 o di e3 mediante
un’istruzione del nucleo del ciclo;
• non è possibile “saltare dentro al ciclo” ad un’istruzione etichettata del nucleo del ciclo mediante
l’istruzione (fuori dal ciclo) di salto incondizionato goto;
17
• è possibile “uscire” dal ciclo mediante un’istruzione di condizione e di salto incondizionato (o di
arresto) presenti nel nucleo del ciclo (ciclo incompleto).
In F77:
• la virgola dopo l’etichetta l è opzionale;
• è possibile omettere l’istruzione continue, mettendo l’etichetta l sull’ultima istruzione del ciclo:
do l, c = e1, e2, e3
istruzione 1
..
.
l
istruzione k
• l’etichetta l non può stare su una linea di codice di do, goto, if, elseif, endif, return, stop e
end;
• vi sono casi in cui è necessaria l’istruzione continue. Ad esempio, se C è un’espressione logica,
do l, c = e1, e2, e3
istruzione 1
..
.
if (C)
..
.
l
goto l
istruzione k
continue
non è infatti possibile scrivere il ciclo nel modo seguente
do l, c = e1, e2, e3
istruzione 1
..
.
if (C)
..
.
l
continue
istruzione k
continue
Deve presentarsi una sola istruzione continue per ogni do;
• i compilatori più recenti del F77 riconoscono il ciclo do con il costrutto do–enddo.
In Fortran c’è la possibilità di fare cicli annidati (nested) a due o più indici. Ad esempio in F90 un
ciclo annidato a due indici ha la forma
do i = i1, i2, i3
istruzione/i 1
do j = j1, j2, j3
istruzione/i 2
enddo
enddo
In F77 un ciclo annidato può avere la seguente forma
do 10, i = i1, i2, i3
istruzione/i 1
do 20, j = j1, j2, j3
istruzione/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 del
ciclo j rispettivamente.
• È errato “chiudere” prima il ciclo esterno di quello interno; ovvero non è corretto
do 10, i = i1, i2, i3
istruzione/i 1
do 20, j = j1, j2, j3
istruzione/i 2
10 continue
20 continue
Questo errore è evitato se si usa il costrutto do–enddo.
• Se, come in questo esempio, non vi sono istruzioni tra le due istruzioni continue che chiudono i
due cicli interno ed esterno, allora si può scrivere
do 10, i = i1, i2, i3
istruzione/i 1
do 10, j = j1, j2, j3
istruzione/i 2
10 continue
oppure
do 10, i = i1, i2, i3
istruzione/i 1
do 10, j = j1, j2, j3
istruzione/i 2
10 ultima istruzione 2
Il ciclo while
Il ciclo while (while–loops),
mentre la condizione è vera esegui le istruzioni
è un ciclo in cui non è noto a priori quante volte si devono eseguire una o più istruzioni.
In Fortran il ciclo while si può “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/i
goto l
endif
Il ciclo until
Il ciclo until (until–loops),
ripeti le istruzioni finché la condizione non diventa vera
è un ciclo in cui non è noto a priori quante volte si devono eseguire una o più 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 istruzione
altra/e istruzione/i
if (.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 seguite
dalle variabili o dalle costanti o in generale dalle espressioni, separate da virgola, che si vogliono scrivere
e leggere.
Le istruzioni di lettura e di scrittura si scrivono rispettivamente
read(*,*)
write(*,*)
• il primo asterisco * specifica che l’unità di ingresso (lettura) o di uscita (lettura) è quella di default;
cioè la tastiera per unità di ingresso e il video per unità di uscita;
• il secondo asterisco * indica che il formato per leggere o per scrivere utilizzato è quello di default,
ovvero il formato libero.
Il do implicito
In Fortran è possibile per la lettura o la scrittura di array il do implicito.
Ad esempio si suppone di dover scrivere l’array
 
1
x= 2 
3
la scrittura, ad esempio in F90,
do i=1,3
write(*,*) x(i)
enddo
1
2
3
visualizza
mentre la scrittura Fortran
visualizza
write(*,*) (x(i),i=1,3)
Se si suppone di dover scrivere l’array bidimensionale

1 2
a= 4 5
7 8
1
2
3

3
6 
9
La scrittura, ad esempio in F90,
do i=1,3
do j=1,3
write(*,*) a(i,j)
enddo
enddo
1
2
3
4
5
6
7
8
9
visualizza
mentre la scrittura, ad esempio in F90,
do i=1,3
write(*,*)(a(i,j),j=1,3)
enddo
1 2
4 5
7 8
visualizza
3
6
9
ed ancora la scrittura in Fortran
visualizza
write(*,*) ((a(i,j),j=1,3),i=1,3)
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 i
dati sono introdotti direttamente da tastiera, può essere premuto il tasto invio (tasto enter) opzionalmente
dopo l’ingresso di ogni dato.
20
Il ridirezionamento dei dati in ingresso e in uscita
In Fortran è possibile ridirezionare i dati in lettura e in scrittura, quando questi sono letti dall’unità di
default mediante i sistemi operativi windows dal prompt dei comandi o unix/linux dalla linea di comando
del terminale.
Ad esempio se il file eseguibile esempio è il file compilato del file Fortran esempio.f in cui sono presenti
le seguenti istruzioni di lettura e di scritura da e su l’unità 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 in
questo modo e con questi valori
3
1 0 2
e produce un file di dati che abbiamo chiamato out in cui c’è scritto
matrice da vettore
1 0 2
0 0 0
2 0 4
Se il file di dati in non è stato creato, l’esecuzione di esempio non può avvenire.
È 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
10 Ovviamente
il nome del file di ingresso dati e del file di uscita dati è scelto dal programmatore.
21
Lettura e scrittura mediante file
In Fortran è possibile leggere e scrivere dati da e su file con istruzioni eseguibili dell’unità di programma
e non soltanto da sistema operativo. È necessario in questo caso “aprire il file” e questo avviene con
l’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 unità
di ingresso dati e write(6,*) e write(*,*) indicano la stessa unità 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 è una variabile carattere, ad esempio in F90
character(len=10)::dati
allora
file=dati
• status=’old’ se il file specificato dal nome esiste già;
status=’new’ se il file specificato dal nome non esiste11 ;
status=’unknown’ se non è noto se esiste il file specificato dal nome12 ; se non è specificato lo stato
del 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 file
esiste, 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 è formattato (leggibile) altrimenti la clausola è 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 è formattato o meno, il file viene considerato formattato.
• action=’read’ se il file è di sola lettura;
action=’write’ se il file è di sola scrittura;
action=’readwrite’ se il file è di lettura e scrittura. Se non è specificato se il file è di lettura o
scrittura si considera sia di lettura che di scrittura.
• access=’sequential’ se il file viene esaminato sequenzialmente (questa è anche la procedura se
non è specificato diversamente nella clausola di accesso al file); access=’direct’ se l’accesso al file
è diretto.
11 Ovviamente si intende un file non esistente nel direttorio in cui si esegue il file eseguibile. Se il file specificato dal nome
esiste allora viene segnalato errore in esecuzione.
12 Se il file esiste allora status=’unknown’ è come status=’old’, se il file non esiste è come status=’new’.
13 Utile quando si vogliono salvare risultati intermedi ma non per registare dati che devono essere salvati alla fine del
programma.
14 Si suppone, ad esempio, che nell’istruzione open si sia posto unit=8.
22
• iostat=variabile intera; il valore della variabile intera è 0 se l’apertura del file ha avuto successo,
altrimenti la variabile assume un valore diverso da zero15 .
L’istruzione di chiusura del file è
close(...)
dove al posto dei puntini c’è il numero intero positivo specificato nella clausola unit=.
Se l’istruzione close non è presente, il file si chiude quando trova l’istruzione di fine programma end.
Si possono aprire contemporaneamente più file, purché 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 che
chiamiamo out. Il file in ha, ad esempio, questa disposizione di valori
3
1 0
2
Nel punto dell’unità di programma Fortran in cui si vuole leggere i dati si “apre” il file in e si scrivono
le 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, allora
si 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 essere
matrice da vettore
1 0 2
0 0 0
2 0 4
15 Il
valore diverso da zero dipende dal compilatore.
23
L’istruzione format
In Fortran, la lettura o la scrittura dei dati con formato può essere fatta mediante la specifica di formato
nell’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 implicita del Fortran.
read(*,’2I6’)i,j
read(*,’3I6’)i1,12,i3
read(*,’2I6’)ip,jp
read(*,100)i,j
read(*,200)i1,12,i3
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 meno
di 6 caratteri, esso viene scritto da destra lasciando spazi bianchi per il completamento dei caratteri.
Si osserva che il numero -123456 non può essere letto con tale formato. Analogamente se si usa
l’istruzione write.
• I numeri reali possono essere letti o scritti sia in forma posizionale (fixed) che esponenziale.
10
20
read(*,10)x,y
read(*,20)u,v
format(F7.1,F6.3)
format(E9.1,E103)
I numeri reali x e y sono scritti in “forma fissa” ed occupano rispettivamente 7 caratteri (incluso il
segno16 e il punto radice) di cui 1 per la cifra dopo il punto radice e sei caratteri (incluso il segno e
il 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 perché uno spazio ciascuno si deve riservare
al punto radice e all’eventuale segno. La scrittura F.j indica che non si specificano caratteri per
valori 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 di
cui 1 per una cifra dopo il punto radice e 10 caratteri di cui 3 per tre cifre dopo il punto radice. Tra
i 9 e i 10 caratteri si deve tenere conto dell’eventuale segno e dei 4 caratteri della parte esponenziale
eSXX dove S indica il carattere riservato al segno e XX sono due cifre da 0 a 38. Ad esempio valori
di 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, ad
esempio, 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 da
leggere o da scrivere elencate successivamente all’istruzione stessa sono dello stesso tipo e soggette
allo stesso formato.
16 Se
positivo è 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, oppure
un numero naturale dopo il carattere X, e.g., 1X o 10X che indica che deve essere saltato un certo
numero 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 può trovarsi in qualsiasi punto dell’programma. In generale tutte le
istruzioni format sono posizionate in fondo al programma prima dell’istruzione di fine programma end.
25
Operazioni globali su array in F90
In F90 è possibile eseguire operazioni su variabili con indice come se fossero operazioni su variabili
semplici.
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 avere
lo 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
è equivalente a
do i=1,nx
y(i)=s*x(i)
enddo
y=s+x
è equivalente a
do i=1,nx
y(i)=s+x(i)
enddo
è equivalente a
do i=1,na
do j=1,na
b(i,j)=s*a(i,j)
enddo
enddo
b=s+a
è equivalente a
do i=1,na
do j=1,na
b(i,j)=s+a(i,j)
enddo
enddo
z=x+y
è equivalente a
do i=1,nx
z(i)=x(i)+y(i)
enddo
b=s*a
c=a+b
do i=1,na
do j=1,na
c(i,j)=a(i,j)+b(i,j)
enddo
enddo
è equivalente a
In F90 molte funzioni intrinseche che sono utilizzate con valori scalari accettano anche gli array come
argomenti di ingresso e restituiscono un array in uscita.
Ad esempio, se x è un array, allora sin(x) restituisce un array delle dimensioni di x avente per componenti
il valore della funzione seno calcolata nella corrispondente componente dell’array x; i.e., se x è un array
ad una dimensione, la i–esima componente dell’array sin(x) è sin(x(i)).
Si nota che la scrittura write(*,*)x o write(*,*)a, dove si suppone che la variabile x sia un array
ad una dimensione e a sia un array a due dimensioni, comporta la stampa “per colonna” di tutti gli
elementi 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 è possibile indicare le componenti di un array17 ad una dimensione non
soltanto 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 componenti 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 seconda
scrittura.
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)
x(i1:i2)
x(i1:)
x(i1::i3)
x(:i2)
x(:i2:i3)
x(:)
x(::i3)
17 Sia
indica che si considerano le componenti con indice da i1 a i2 con passo i3
indica che si considerano le componenti con indice da i1 a i2 con passo 1
indica che si considerano le componenti con indice da i1 a nx
indica che si considerano le componenti con indice da i1 a nx con passo i3
indica che si considerano le componenti con indice da 1 a i2 con passo 1
indica che si considerano le componenti con indice da 1 a i2 con passo i3
indica che si considerano le componenti con indice da 1 a nx con passo 1
indica che si considerano le componenti con indice da 1 a nx con passo i3
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 di
programma.
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
1
2
4
5
fine 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
1
2
fine ciclo
• L’istruzione exit all’interno di un ciclo do arresta il ciclo; da non confondere con l’istruzione di
arresto stop che invece arresta l’intero programma.
28
L’istruzione select case
In F90 è presente il costrutto di select case. Il costrutto ha la seguente forma:
nome: select case(E)
case (selettore1)
istruzioni 1
case (selettore2)
istruzioni 2
...
case default
altre istruzioni
end select case nome
• Con E si indica un’espressione aritmetica.
• Se il valore dell’espressione aritmetica E è compreso nell’intervallo del selettore 1 allora si eseguono
le istruzioni 1, se è compreso nell’intervallo del selettore 2 allora si eseguono le istruzioni 2 e cosı̀
via; se il valore di E non è con è compreso in nessun intervallo specificato dai selettori allora è il
“caso default” e si eseguono le altre istruzioni.
• Il blocco
case default
altre istruzioni
è opzionale; se il valore dell’espressione aritmetica E non è compreso in nessun intervallo specificato
dai selettori e non è presente il “blocco di default” allora il costrutto select case non viene
eseguito.
• Il nome del costrutto select case è opzionale.
Esempio 1 (si usa la dichiarazione di tipo implicita del Fortran):
select case(itemp)
case (:-1)
write(*,*)’valore ’’temp’’
case (0)
write(*,*)’valore ’’temp’’
case (1:20)
write(*,*)’valore ’’temp’’
case (21:)
write(*,*)’valore ’’temp’’
end select case
minore di -1 ’
nullo ’
da 1 a 20 ’
maggiore di 21 ’
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’è la possibilità di assegnare un nome al ciclo do inserendo il nome seguito da : (due punti) prima
della parola chiave do e dopo la parola chiave enddo. Con un esempio di un segmento di programma se
ne vede l’utilità.
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
2
2
3
3
1
3
1
3
1
3
1
3
2
6
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 di
1 1
2 1
3 1
30
1
2
3
Il ciclo while/until in F90
In F90 è possibile scrivere il ciclo while o il ciclo di until utilizzando l’istruzione exit nel blocco di
istruzioni comprese tra do ed enddo nel modo seguente:
do
istruzioni 1
if(E) exit
istruzioni 2
enddo
dove E è un’espressione logica. Le istruzioni 1 e le istruzioni 2 vengono eseguite finché l’espressione E è
falsa. Se, dopo l’esecuzione delle istruzioni 1, l’espressione logica E diventa vera, allora si esegue, come
istruzione successiva, quella scritta sotto enddo.
Il costrutto do while
In F90 è possibile utilizzare il costrutto do while per la costruzione del ciclo while. Il costrutto do while
ha la seguente forma:
do while (E)
istruzione 1
...
istruzione k
enddo
Se l’espressione logica E è vera, le istruzioni (istruzione 1,..., istruzione k) vengono eseguite; dopo
l’istruzione enddo si esegue l’istruzione do while e se l’espressione logica E è ancora vera, vengono
eseguite nuovamente le istruzioni (istruzione 1,..., istruzione k). Questo processo viene eseguito fino a
quando l’espressione logica E diventa falsa; in tal caso la successiva istruzione da eseguire è quella scritta
nella riga sotto enddo.
Questo costrutto è 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 è possibile assegnare dei valori ad un array mediante una maschera. Ad esempio, siano a e b due
array 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 calcolare
l’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 segmento
di 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 1
elsewhere(E2) nome
istruzioni 2
...
elsewhere nome
altre istruzioni
end where nome
• E1, E2, ... sono array logici della stessa dimensione dell’array da “manipolare”;
• il nome del costrutto è opzionale.
Nell’esempio, il costrutto where si scrive
where(a>0)
b=a
elsewhere
b=0
end where
Se nell’esempio l’array b è “inizializzato” a zero (ad esempio nell’istruzione dichiarativa), il costrutto
where può essere sostituito dall’istruzione where nel modo seguente
where(a>0) b=a
32
Il costrutto forall
In F90 è possibile il costrutto forall cosı̀ definito:
nome: forall (i1=n1:m1:l1, i2=n2:m2:l2, ..., E)
istruzione 1
...
istruzione k
end 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,... con
passo l1, l2,...; i passi sono opzionali se valgono 1.
• E è un’espressione logica; l’espressione logica può 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 sovrascrivere sull’elemento a(i,j) con valore diverso da zero, il suo valore reciproco. Questo calcolo si può eseguire
con 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 può 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 costrutto
forall elebora gli elementi nell’ordine selezionato dal processore. Ad esempio, siano a e b due array
bidimensionali 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 il
primo elemento b(1,1).
I puntatori
In F90 è possibile definire un puntatore, ovvero una variabile contenente nessun dato ma indirizzi di
memoria di un’altra variabile dove sono memorizzati i dati. Si veda per una trattazione delle variabili
puntatori 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 è 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 dichiarative
istruzione eseguibile 1
...
istruzione eseguibile k
funz=espressione
return
end
Supponiamo che la funzione funz sia di tipo reale e che gli argomenti della funzione funz siano le variabili
x, 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’unità di programma) si avvale della function funz mediante
un’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 variabile a, l’argomento y della function funz “legge” il valore memorizzato nel programma principale dalla
variabile s e l’argomento z della function funz “legge” il valore memorizzato nel programma principale
dalla 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 eventualmente
modificano 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 può essere chiamato dall’unita di programma chiamante
piu 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 regole della dichiarazioni di variabili semplici nel programma principale; vale ovviamente la dichiarazione
implicita di tipo del Fortran;
• gli argomenti della function sono variabili di ingresso, l’unica variabile di uscita è il nome della
function;
• è possibile modificare i valori degli argomenti all’interno della function; ovviamente la modifica si
ha anche a livello dell’unità 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 sono
di ingresso, quali di uscita e quali di ingresso e uscita.
Nell’esempio della function funz, la dichiarazione delle variabili globali (che si suppone siano
reali) x, y e z in F90 può 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 come
x=... provoca una segnalazione di errore in fase di compilazione;
• in F90 l’istruzione di fine, end, può scriversi anche nei modi
end function
end function nome funzione
• in ogni function, l’istruzione end è presente una sola volta;
• l’istruzione eseguibile return è l’istruzione di arresto di un sottoprogramma che significa “ritornare”
al programma chiamante. Ci possono essere più di una istruzione return all’interno di un sottoprogramma. L’istruzione stop all’interno di un sottoprogramma provoca l’arresto dell’intero processo.
Se l’istruzione return non è presente nel sottoprogramma o non viene mai eseguita, il “ritorno” al
programma 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 la
dichiarazione implicita di tipo del Fortran. La variabile contatore i è una variabile locale.
function ifatt(n)
ifatt=1
do i=2,n
ifatt=ifatt*i
enddo
return
end
In Fortran, una function può avere la lista degli argomenti vuota. Ad esempio, la funzione che calcola
la 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 dichiarative
istruzione eseguibile 1
...
istruzione eseguibile k
return
end
Supponiamo che gli argomenti della subroutine siano, nell’ordine, le variabili reali x, y e z. Il programma
principale (in generale un’unità di programma) si avvale della subroutine sub1 mediante un’istruzione
eseguibile 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 variabile a, l’argomento y della subroutine sub1 “legge” il valore memorizzato nel programma principale
dalla variabile s e l’argomento z della subroutine sub1 “legge” il valore memorizzato nel programma
principale 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 eventualmente
modificano 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 può essere chiamato dall’unita di programma chiamante
piu 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 le
stesse regole della dichiarazioni di variabili semplici nel programma principale; vale ovviamente
la dichiarazione implicita di tipo del Fortran;
• gli argomenti della subroutine sono variabili di ingresso e di uscita. Se un argomento non viene
modificato all’interno della subroutine allora quell’argomento può essere visto come una variabile
di solo ingresso; il F90 ha un’istruzione opzionale di specifica per indicare quali variabili sono di
ingresso, quali di uscita e quali di ingresso e uscita. Ad esempio se x è di ingresso, y è di uscita e
z è 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 dichiarazione
implicita di tipo del Fortran.
36
• in F90 l’istruzione di fine, end, può scriversi anche nei modi
end subroutine
end subroutine nome subroutine
• in ogni subroutine, l’istruzione end è presente una sola volta;
• l’istruzione eseguibile return è l’istruzione di arresto di un sottoprogramma che significa “ritornare”
al programma chiamante. Ci possono essere più di una istruzione return all’interno di un sottoprogramma. L’istruzione stop all’interno di un sottoprogramma provoca l’arresto dell’intero processo.
Se l’istruzione return non è presente nel sottoprogramma o non viene mai eseguita, il “ritorno” al
programma chiamante avviene quando si incontra l’istruzione di fine sottoprogramma end;
• ogni function può essere scritta come una subroutine.
37
L’istruzione external
Nella scrittura di un programma principale può capitare di passare una o più function come argomento
di un sottoprogramma, senza che questa o queste function siano chiamate direttamente dal programma
principale in altri punti del codice.
In questo caso la function, passata come argomento a un sottoprogramma, nel programma principale
deve essere dichiarata esterna. La stessa dichiarazione deve essere fatta nel sottoprogramma che legge e
chiama direttamente la function.
Nell’istruzione dichiarativa, la parola chiave per dichiarare esterna una funzione è 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 della
subroutine; ovvero nel programma principale si hanno le istruzioni dichiarative ed eseguibili
program nome programma
external 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 è più external.
38
Ad esempio si può avere la situazione
program nome programma
external 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 quelle
passate come argomenti sono trattate come in un sottoprogramma “non contenuto” nel programma
principale.
• In un sottoprogramma “contenuto” nel programma principale, le variabili non passate come argomenti sono: locali se dichiarate esplicitamente nel sottoprogramma oppure globali se non dichiarate
esplicitamente 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 risultati
stampa 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 è possibile definire il modulo. Il modulo (module) è un’unità di programma compilata a parte e
contiene dichiarazioni e inizializzazioni di variabili e costanti che possono essere condivise da altre unità
di programma.
Il modulo inizia con l’istruzione module nomemodulo e termina con l’istruzione end module nomemodulo.
Un esempio di modulo è il seguente:
module dati
integer, parameter :: num=50
real, dimension(num) :: v=0,w=0
character(len=10) :: car
end module dati
L’unità di programma che utilizza tutte o in parte le variabili e le costanti allocate e/o inizializzate nel
modulo, specifica, come prima istruzione dichiarativa, che “utilizza” il modulo mediante la parola
chiave 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 è come scriverle nell’unità di programma che usa il
modulo; ovvero la scrittura seguente è 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
• è possibile dichiarare variabili allocabili nei moduli; le variabili vengono allocate e deallocate nelle
unità di programma che usano i moduli.
42
Un modulo può contenere anche subroutine e function (procedure di modulo). La parola chiave
contains indica al compilatore che i sottoprogrammi successivi sono procedure di modulo.
Ad esempio un modulo può essere il seguente:
module miesub
contains
subroutine sub1(argomenti separati da virgola)
istruzioni dichiarative
istruzioni eseguibili
end subroutine sub1
subroutine sub2(argomenti separati da virgola)
istruzioni dichiarative
istruzioni eseguibili
end subroutine sub2
tipo funzione function f(argomenti separati da virgola)
istruzioni dichiarative
istruzioni eseguibili
end function
end module miesub
Le unità 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 programma
principale che usa il modulo miesub può avere la forma seguente
program main
use miesub
...
call sub1(...)
...
stop
end program
Il vantaggio dell’uso di un sottoprogramma di modulo è dovuto al fatto che il compilatore controlla
gli argomenti del sottoprogramma. Vengono controllati, oltre al numero degli argomenti, al tipo e allo
scopo (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, un
modulo può avere la forma:
module miesub
dichiarazioni e/o inizializzazioni
contains
subroutine sub1(argomenti separati da virgola)
istruzioni dichiarative
istruzioni eseguibili
end subroutine sub1
end module miesub
43
Passaggio di array a sottoprogrammi
In Fortran l’uso di array è flessibile. Si pensi ad esempio che, in un programma principale in cui un
array x è dichiarato
real x(10)
è possibile utilizzare componenti di x maggiori di 10. Ad esempio la scrittura
write(*,*)x(12)
è lecita e produce come risultato il numero reale memorizzato sui 32 bit successivi a partire da IN D[x(1)]+
12 ∗ 32 dove IN D[x(1)] è 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 agli
array
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
4
7
0
0
0
0
0
0
0
2
5
8
0
0
0
0
0
0
0
3
6
9
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
























x=







10
20
30
0
0
0
0
0
0
0

























y=








5
10
15
20
25
30
35
40
45
0
0


















Si consideri una subroutine, chiamata submv2, che calcola il prodotto di una matrice per un vettore a cui
viene sommato un altro vettore di elementi pari al numero di righe della matrice.
Ad esempio si vogliono calcolare le seguenti operazioni

 
z(1)
1
 z(2)  =  4
z(3)
7
2
5
8

 

3
10
5
6   20  +  10 
9
30
15
44
e
e

 
z(4)
1
 z(5)  =  4
z(6)
7

 
z(7)
1
 z(8)  =  4
z(9)
7
2
5
8

 

3
10
20
6   20  +  25 
9
30
30
2
5
8

 

3
10
35
6   20  +  40 
9
30
45
In Fortran ciò 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 è 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 alla
subroutine si può 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 la
chiamata 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 subroutine
submv2 si può 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 parola
chiave real può 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 nel
programma 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 nel
programma 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; nella
terza 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 nel
programma 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; nella
terza 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 è
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 chiamata
zs(0) “legge” z(7), zs(1) “legge” z(8) e cosı̀ via;
• il simbolo * (asterisco) nella dichiarazione dell’array monodimensionale è un segnaposto; analogamente al posto del simbolo * (asterisco) si può 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 nel
programma 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;
• poiché il Fortran memorizza gli elementi di un array bidimensionale “per colonne”, al sottoprogramma deve essere noto il numero di righe dell’array bidimensionale memorizzato nel programma
principale chiamante, ovvero la grandezza leading. In questo modo, come nell’esempio, l’elemento
as(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 è un
segnaposto; analogamente al posto del simbolo * (asterisco) si può indicare 1, 2, n o altre costanti
o 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 che
vengono utilizzati nella subroutine sono


1 0 0
 4 0 0 
7 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 è fortemente sconsigliata in quanto vincola la “corretta lettura” dell’array bidimensionale ad una costante locale (in questo caso ns) che deve essere uguale alla grandezza leading
dell’array bidimensionale memorizzato nel programma principale; una chiamata allo stesso sottoprogramma con un altro array con grandezza leading differente provocherebbe una “lettura non
corretta”.
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 array
utilizzati 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 è 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 utilizzare l’operazione globale z=x+y per sommare le prime n componenti di x e y, si modifica il sottoprogramma
in
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 deve
utilizzare il simbolo * (asterisco) come segnaposto. Ad esempio il seguente segmento di parte dichiarativa
di 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 e
w(i), i=1,n.
Variabili mute (dummy)
Le variabili semplici locali di un sottoprogramma sono usualmente contatori di cicli, indici di componenti
di array globali o variabili di “appoggio” per operazioni come lo scambio (swap).
L’utilizzo di array locali è fortemente sconsigliato. Ad esempio, supponiamo di avere il seguente segmento
di 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 necessità 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
Poiché il parametro formale m “legge” il valore 200, il ciclo dentro la subroutine viene eseguito ma non
c’ è controllo dove sono stati memorizzati i valori letti da x(101),...,x(200). È preferibile rendere muto
l’array w considerandolo globale. Ovvero si modifica il programma principale e la subroutine nel modo
seguente
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 sottoprogrammi sono function oppure procedure di modulo.
Alternativamente, in F90 si può allocare dinamicamente l’array w scrivendo il codice nel modo seguente
subroutine sub1(x,m,w,...)
real, allocatable, dimension(:)::
real x(*)
...
allocate(w(m))
do i=1,m
w(i)=x(i)
enddo
...
deallocate(w)
end
w
Passaggio di array con dimensioni diverse
Si consideri la subroutine mv che calcola il prodotto matrice per vettore vista in precedenza. Utilizziamo
questa subroutine per calcolare il prodotto scalare tra due vettori e per calcolare il prodotto matrice per
matrice.
Per la scrittura di un programma principale che calcola il prodotto scalare tra vettori, sia la parte
dichiarativa 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 negli
array 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 dichiarativa
di 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 memorizzate
negli 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 matrice
ottenuta dal prodotto di due matrici ha per colonne i vettori risultanti dal prodotto della prima matrice
per le rispettive colonne della seconda.
Si osserva che, in entrambi i casi, non c’ è corrispondenza delle dimensioni degli array tra gli argomenti
della chiamata e i parametri formali della subroutine. Ad esempio, nell’ultimo caso il secondo argomento
della chiamata è l’indirizzo di un array bidimensionale che viene “letto” da un parametro formale con un
solo indice.
Questi passaggi di array non corrispondenti di dimensione possono anche essere effettuati a sottoprogrammi function ma non si possono eseguire se il sottoprogramma è una procedura di modulo.
50