Home Page

Tips page

University Page

Programming

Debian & Linux

Some works

About me

Del.icio.us Bookmarks

BOINC Combined Statistics

Site Statistics

Contact me sending an e-mail (antispam defense activated)

debian

hacker emblem

blogger

GeoURL

View Sandro Tosi's profile on LinkedIn

This is my Google PageRank

Title: Appunti Fortran
Author: Sandro Tosi
Last modified: 12/02/2004

Cerchero'  qui di elencare  alcune `informazioni'  utili per  chi deve
iniziare a programmare in ForTran: Formula Translator.

Magari,  una  conoscenza di  altri  linguaggi  di programmazione  puo'
aiutare a capire meglio questo documento...

***Introduzione

Quelle  che  seguono  sono  le  informazioni che  ho  raccolto  mentre
imparavo Fortran  per preparare la tesi  di laurea. Non  mi sono posto
l'obiettivo di essere completo o esatto e per questo ogni correzione o
suggerimento e' ben accetto. Quello  che si trovera' in questi appunti
sono alcune nozioni  di base, che certo non  escludono uno studio piu'
approfondito  del linguaggio  su un  manuale, che  invito  vivamente a
leggere per  tutte le  particolarita' che non  ho affrontato  e quindi
neanche riportato, ma che possono essere molto utili.

Fortran  e'  utilizzato  principalmente  per elaborazioni  di  calcolo
numerico, dove  l'efficienza e la  velocita' di esecuzione  che offre,
sono  ritenute   piu'  importanti   rispetto  ad  altri   aspetti  del
linguaggio.

***Informazioni generali

Fortran non e' case sensitive.
La  memorizzazione delle matrici  avviene per  colonne.  L'allocazione
della  memoria  e'  statica;  al  momento  della  dichiarazione  delle
variabili.

Fortran  _non_ e'  un liguaggio  ricorsivo, quindi  sottoprogrammi non
potranno richiamare se stessi.

Un consiglio che e' valido per qualunque linguaggio di programmazione:
COMMENTATE IL  CODICE!! In  questo modo si  rendera' chiaro  cosa deve
fare  il  codice che  stiamo  scrivendo,  consentira'  una sua  futura
modifica in modo  puntuale ed, inoltre, una sua  comprensione da parte
di altre persone oltre a chi scrive il codice.

***Perche' usare Fortran?

Iniziamo  con  le  note  dolenti:  rispetto  ad  altri  linguaggio  di
programmazione, Fortran risulta piu' essenziale, ad esempio per la sua
gestione  completamente  statica delle  risorse,  prima  tra tutte  le
memoria; inoltre, offre  ben pochi strumenti per la  tipizzazione e la
strutturazione  dei dati ed  aspetti della  programmazione strutturata
non sono ancora diffusi nel linguaggio.

Tuttavia,  Fortran presenta  molti  punti a  suo  favore: consente  di
utilizzare numeri reali con  un elevato numero di cifre significative,
la  possibilita'   di  utilizzare  numeri   ed  aritmetica  complessi,
l'esistenza  di  un  gran  numero  di librerie  altamente  testate  ed
efficienti  ed  anche  la  possibilita' di  richiamare  sottoprogrammi
scritti in linguaggi diversi dal Fortran.

Queste proprieta' lo rendono molto adatto al calcolo scientifico.

***Le colonne

Le colonne in  cui viene scritto il codice  sorgente, in Fortran, sono
molto importanti: uno schema potrebbe essere il seguente...

12345 6 7............72
|---| ^ |-------------|
label |     codice
      |
 continuazione 
della riga prec.

Nelle prime  5 colonne e'  possibile inserire delle label  (vedremo in
seguito   cosa  significa),  sulla   sesta,  inserendo   un  qualsiasi
carattere,  e' possibile  continuare la  riga precendente  (un esempio
potrebbe  essere  quello della  dichiarazione  di  un  gran numero  di
variabili);  fra  la settima  e  la  72-esima  si devono  inserire  le
istruzioni: e'  consigliato non oltrepassare  la colonna 72,  anche se
alcuni  compilatori  si  dimostrano  abbastanza duttili  da  tollerare
questa "scorrettezza".

Inoltre, se  si inserisce una `c',  `C' oppure un  asterisco `*' nella
prima  colonna, tutto  il testo  sulla stessa  riga  viene considerato
commento (quindi  non valgono le impostazioni per  le colonne). Esiste
anche  la  possibilita'  di  inserire  un punto  esclamativo  `!'  che
indichera'  di ignorare  tutti i  caratteri alla  sua  destra: risulta
utile per commentare una riga di codice, dove si scrive l'istruzione e
di seguito si aggiunge il commento.

Una  label   e'  un'etichetta  unica  all'interno   del  programma  (i
sottoprogrammi sono programmi  a se, sotto questo punto  di vista) che
identifica una linea di codice  a cui si puo' fare riferimento tramite
l'istruzione di salto incondizionato `goto'.

Per chi  si chiedesse come  mai e' necessaria una  formattazione cosi'
rigorosa, va detto che la  sintassi e' infatti rimasta molto vincolata
al  periodo delle  schede  perforate,  la cui  lunghezza  di riga  era
limitata e suddivisa nel modo appena descritto.

***Struttura di un programma Fortran

Potremmo schematizzare un generico programma Fortran in 3 sezioni:





***Intestazione

In questa sezione si dichiara cosa andremo a scrivere:

1. un programma principale: `program'
2. un sottoprogramma: `subroutine'
3. una funzione: `function'

(1)Una intestazione per un programma principale e' della forma:

program 

Anche se e'  opzionale come dichiarazione, e' sempre  bene metterla in
modo  da evitare  possibili errori  difficili poi  da  individuare; le
regole che deve soddisfare  sono:

1. deve iniziare con una lettera
2. deve contenere solo lettere o cifre
3. non deve essere piu' lungo di 6 caratteri

(2)Una intestazione per un sottoprogramma ha questa forma:

subroutine ()

Nella  lista  di  parametri  sono  presenti sia  quelli  di  input  (i
parametri  necessari per  l'esecuzione dell'algoritmo)  sia  quelli di
output (quelli in cui andranno messi i risultati).

Fra  i  parametri e'  possibile  mettere  anche  un nome  di  un'altra
subroutine o di una  funzione, che dovra' essere dichiarata `external'
all'interno del sottoprogramma.

Inoltre una subroutine deve essere terminata dalle istruzioni

return
end

(3)Una intestazione per una funzione ha questa forma:

 function ()

Il funzionamento e' molto simile a quanto visto per le subroutine, con
l'unica differenza che la lista  dei parametri contiene solo quelli di
input, in quanto il valore di ritorno e' la funzione stessa.

All'interno  del  corpo della  funzione  deve  quindi essere  presente
un'assegnamento al  nome della funzione, che costituisce  il valore di
ritorno.

Anche `function' deve essere terminata con la coppia di istruzioni

return
end

***Informazioni generali su sottoprogrammi

E'  utile sapere  che ogni  `parte' del  programma e'  a se  stante: a
differenza  del   Pascal,  per  esempio,  nel   Fortran  il  programma
principale non  contiene le  subroutine che verranno  utilizzate: ogni
programma e' indipendente, e ci si rifa ad esso tramite l'istruzione

external 

che  associa a   una  subroutine o  una funzione  che  potra', a
questo punto, essere utilizzata nel  codice corrente (nel caso sia una
funzione,  e' necessario anche  definire il  tipo della  funzione, che
viene fatto nello stesso modo in cui si dichiara una variabile).

Inoltre, Fortran  considera i  sottoprogrammi come separati  dal corpo
del  programma  principale  e  quindi  li  compilera'  anche  in  modo
indipendente.

Si noti, inoltre, che nel Fortran e' assente la ricorsione, quindi gli
algoritmi dovranno essere scritti tenendo presente questa mancanza.

Non  esistono  variabili  globali,  quindi  lo  scambio  di  dati  tra
programma  chiamante e  programma chiamato  puo' avvenire  solo  con i
parametri  (o meglio,  esiste  anche l'istruzione  Common,  ma non  la
vedremo). Inoltre, non esistono i parametri per valore.

Un'altra nota  e' da farsi riguardo alla  dichiarazione dei parametri:
essi  devono essere dichiarati  sia nel  programma principale  sia nel
sottoprogramma, ed in  particolar modo per i vettori,  che devo essere
dimensionati in  entrambe le  parti, ma _soltanto_  alla dichiarazione
all'interno  del   programma  principale  corrisponde   una  effettiva
allocazione di memoria.

***Dichiarative

In  questa sezione  sono  presenti le  dichiarazioni delle  variabili,
delle funzioni esterne e delle costanti.

Fortran  ha la  caratteristica di  considerare, in  via  normale, come
reali le  variabili che  iniziano con  la lettera A..H  e O..Z  e come
intere le variabili che iniziano  con le restanti lettere; e' comunque
possibile  ridefinire questo  comportamento  tramite l'utilizzo  della
direttiva

implicit (), (<...>)

indicando  il tipo  delle variabili  che inizieranno  con la  lista di
lettere che  segue (una  serie di lettere  consecutive si  indica come
A-H, per esempio le lettere da A ad H comprese).

E' bene, pero', eliminare questa caratteristica, tramite la direttiva

Implicit None

che  disattiva   l'opzione  dell'autotipo;  questa   dichiarazione  va
indicata in ogni parte del programma (diciamo nella parte dichiarativa
del  programma  principale, dei  sottoprogrammi  e  delle funzioni)  e
quindi dichiarare _esplicitamente_ il tipo delle variabili che andremo
ad utilizzare.

L'uso di  dichiarazioni implicite rende il programma  meno leggibile e
consente  di  introdurre  errori  non  individuabili  dal  compilatore
poiche' una variabile  non dichiarata esplicitamente viene considerata
reale  o  intera sulla  base  della  lettera  iniziale; si  consiglia,
quindi,  di  utilizzare   sempre  una  dichiarazione  esplicita  delle
variabili, in modo da essere sicuri di quello che verra' eseguito.

***Variabili

Di seguito troviamo un elenco dei tipo di variabili maggiormente
utilizzati in fortran:

Integer			con segno			4 byte
Real			singola precisione		4 byte
Double precision	doppia precisione		8 byte
Complex			complessi a singola precisione
Double complex		complessi a doppia precisione
Boolean			valori booleani
Character*n		stringa di n caratteri

Il nome di  una variabile e' una sequenza al piu'  di 31 caratteri che
possono essere lettere, numeri e  caratteri speciali come `$' e `_' ma
non  puo' iniziare  con un  numero; va  inoltre notato  che  su alcune
versioni non sono riconosciuti nomi piu' lunghi di 6 caratteri.

Cerchiamo di esaminare piu' in attenzione questi tipi:

-Integer

sono   i   classici   numeri   interni  degli   altri   linguaggi   di
programmazione.

-Real

sono i numeri reali in singola precisione, che si possono indicare sia
in virgola mobile  che in virgola fissa, ed  in quest'ultima notazione
sono ammessi  numeri senza  cifre prima o  dopo il punto  decimale. E'
ammessa anche  la lettera `D' al  posto della lettera  `E' nella parte
dell'esponente.

-Complessi

sono rappresentati  come coppie  di numeri reali  (o interi),  dove il
primo  elemento   rappresenta  la  parte  reale,   mentre  la  seconda
componente rappresenta la parte immaginaria del numero complesso.

***Costanti

per definire una costante si usa l'istruzione

Parameter(=)

che associa ad un nome simbolico  un valore; il tipo della costante e'
definito  se    e'  il  nome di  una  variabile  precedentemente
dichiarata, altimenti  si usano  le regole di  dichiarazione implicita
delle variabili:

1 e' costante intera
1., 1E0 e' una costante reale
1D0 e' una costante reale in doppia precisione

Il  nome  di  una  costante  ha  associato un  valore  che  non  sara'
modificabile in futuro.

Una  volta dichiarata una  costante, e'  possibile utilizzarla  per la
definizione di altre costanti:

parameter(n=5)
parameter(n2=n*n)

ed  n2  contiene il  quadrato  di  n: nel  nostro  caso  sara' 25,  ma
cambiando il  valore ad n,  automaticamente cambiera' anche  quello di
n2...

***Dichirazione di variabili

Cerchiamo  ora  di  elencare  alcune dichiarazioni  di  variabili  per
mostrare come farlo all'interno della sezione di dichiarazione:

Integer i,j

dichiara due  variabili `i' e  `j' intere: quindi, per  dichiarare una
variabile  di  un  certo  ,   si  pone  prima  il  tipo  della/e
variabile/i  e dopo il  nome di  questa/e in  modo unico  (non possono
esistere variabili, anche di tipo diverso, ma con nome uguale):

 

***Vettori e matrici

Vediamo la dichiarazione di vettori e matrici come avviene:

integer v(24)
dichiara il vettore `v' di 24 elementi interi, l'offset parte da 1

integer a(10,10)
dichiara la matrice `a' di interi con 10 righe e 10 colonne

integer v(n)
dichiare il vettore `v' di interi con un numero di elementi dipendenti
da un parametro definito in precedenza, `n'

integer vec(*)

Come detto l'allocazione della memoria e' statica, ma e' cmq possibile
definire un vettore di interi  di dimensione non fissata, che contiene
gli  elementi necessari; questa  pratica e'  _vivamente sconsigliata_,
soprattutto per i calcoli numerici.

Le  dimensioni  devono essere  degli  interi,  ed  e' anche  possibile
specificare  estremo  inferiore e  superiore  di  ogni dimensione  del
vettore scrivendo  due costanti  intere separate da  `:' (naturalmente
l'estremo  inferiore  deve  essere numericamente  minore  dell'estremo
superiore).

Agli elementi del vettore si accede tramite il meccanismo dell'indice:
si fa riferimento ad un  determinato elemento del vettore indicando il
nome  del vettore  seguito dalla  specifica dell'indice  racchiusa tra
parentesi tonde.

***Variabili in precisione multipla

Dal  momento  che  Fortran  e' particolarmente  orientato  ai  calcoli
numerici,  si  consiglia  di  utilizzare le  variabili  in  precisione
multipla (quando merita  ed e' possibile) in quanto,  a scapito di una
esecuzione  piu'  lenta,  forniscono  dei  risultati  nettamente  piu'
precisi  dei  numeri  in  singola precisione.  Sono  disponibili,  sia
variabili reali che intere definite in questo modo:

Integer*8 
Real*8 

e proprio il  nome sta ad indicare l'utilizzo  del doppio dello spazio
di memoria normalmente utilizzato per variabili in singola precisione.

Per ragioni di compatibilita',  e possibile dichiarare variabili reali
in doppia prezione tramite le parole chiave `double precision' seguite
dal  nome  della  variabile.   Le  costanti,  invece,  possono  essere
dichiarate  in  due modi:  il  primo,  senza  esponente, ma  le  cifre
significative devo  superare la precisione dei  reali, altrimenti sono
considerate in singola precisione; il secondo, con esponente, mettendo
al posto della `E' che  caratterizza le costanti in singola precisione
una `D'.

Le funzioni di  libreria per i numeri reali  in doppia precisione sono
le  stesse  che  si  trovano  per  i  numeri  in  precisione  singola,
eventualmente precedute da una `d'.

***Numeri complessi

Al  contrario di  molti  altri linguaggio  di programmazione,  Fortran
consente di operare su numeri  complessi in modo nativo. Per Fortran i
complessi sono rappresentati  da una coppia di numeri  reali: la parte
reale e  la parte  immaginaria; dal momento  che sono  disponibili sia
reali in  singola che doppia  precisione, cosi' avremo anche  i numeri
complessi   in  singola  (`complex')   e  doppia   (`double  complex')
precisione.

Le costanti sono definite in questo modo:

(, )

dove  sia  che   sono  costranti reali:  una dichiarazione
come (1.0,2.0) e' corretta mentre NON lo e' (1,2).

Per  ottenere un  numero complesso  da interi  oppure  utilizzando per
comporre   un  complesso   risultati  di   alcune  funzioni,   si  usa
l'istruzione  `cmplx'  che  prende   due  argomenti  e  resituisce  un
complesso.

Dal  momento che  il supporto  ai  numeri complessi  e' `built-in'  in
Fortran,  tutte  le  operazioni   di  somma,  sottrazione,  etc.  sono
disponibili  anche  per  questo  insieme  di  numeri;  inoltre  alcune
funzioni che possono risultare utili sono:

real(x)         restituisce la parte reale di x
imag(x)		restituisce la parte immaginaria di x 
cabs(x) 	restituisce il modulo di x

e le varianti per i double complex.

Infine,  un numero  complesso  NON puo'  essere  elevato ad  esponenti
reali, ma solo a potenze intere.

Si  consiglia vivamente,  nel caso  si debba  scrivere del  codice che
utilizza  numeri  complessi, di  consultare  dei  testi che  spieghino
l'aritmetica complessa, leggermente differente da quella ordinaria.

***L'istruzione DATA

Risulta spesso utile assegnare  dei valori iniziali a delle variabili,
anche come test dell'algoritmo,  senza poi dover rispettare il vincolo
di non-modificabilita' delle costanti;  per fare questo, Fortran mette
a disposizione l'istruzione DATA che effettua l'assegnazione di valori
iniziali a variabili.
L'istruzione assume questa forma:

data //,.. //

ad esempio

data k/0/

data a,b,c/1,2,3/, z/(3.3)/

e'  inoltre possibile  assegnare  a piu'  variabili  lo stesso  valore
inziale, specificando la molteplicta' di detto valore:

data m,n,o,p,q/5*0/

Naturalmente,   l'istruzione   DATA   deve   seguire   le   istruzioni
dichiarative (infatti le variabili sono specificate senza il tipo, che
quindi deve essere dichiarato  in precedenza) e solitamente precede le
istruzioni eseguibili.

***Codice eseguibile

La terza  ed ultima  parte di  un programma Fortran  e' quella  in cui
viene  effettivamente   scritto  il  codice  che   dovra'  essere  poi
compilato. Le istruzioni  sono simili a quelle presenti  in ogni altro
linguaggio di  programmazione e, naturalmente,  l'ordine di esecuzione
delle istruzioni e' sequenziale.

***Assegnamento

=

dove si  associa ad un identificativo  di una variabile  (il suo nome)
l'espressione  alla destra dell'uguale;  la variabile  e l'espressione
devono essere dello stesso  tipo; sono pero' concesse alcune eccezioni
che prevedono  una conversione di tipo  dell'espressione per adattarlo
alla variabile (se   e' reale e   e' intera si considera
solo la parte intera dell'espressione).

***Operazioni aritmetiche

Le operazioni sono quelle usuali:

+     somma
-     sottrazione
*     moltiplicazione
/     divisione
**    elevamento a potenza (2**3 indica due alla terza)
sqrt  radice quadrata
etc.

Le  operazioni  hanno  la  stessa  precedenza che  in  aritmetica;  e'
possibile  raggruppare  espressioni tra  parentesi  tonde  in modo  da
apportare la precedenza dei calcoli come meglio si crede.

***Operazioni di confronto

Sono operazioni  leggermente differenti dall'usuale:  in generale sono
della forma

A.op.B

dove `.op.' e' l'operatore di confronto ed `A' e `B' sono gli elementi
da confrontare.
Le operazioni di confronto sono:

.ge. maggiore uguale
.gt. maggiore stretto
.le. minore uguale
.lt. minore stretto
.eq. uguale
.ne. diverso
.not. NOT logico
.and. AND logico
.or. OR logico

e l'ordine degli operatori logici  e' dal basso verso l'alto: il `not'
ha  precedenza sugli altri,  e l'`and'  ha precedenza  sull'`or'. Sono
inoltre disponibili due costanti logiche, true e false:

.true. TRUE logico
.false. FALSE logico

E' anche possibile eseguire delle operazioni durante i confronti:

(n+1).eq.(3*k)

e' un confronto valido.

***Particolarita' di espressioni ed operatori aritmetici

Come detto,  le operazioni hanno la  priorita' solita dell'aritmetica,
quindi l'elevamento a potenza precede moltiplicazione e divisione che,
a loro  volta, precedono somma e sottrazione;  inoltre, operazioni con
lo  stesso ordine  di  priorita' vengono  eseguite  da sinistra  verso
destra eccetto nel caso di elevamento a potenza.

Si noti che, in Fortran, non c'e' distinzione tra divisione fra interi
e divisione fra reali: quando  gli operandi di "/" sono numeri interi,
il risultato sara' un intero.

L'esecuzione  di  espressioni  con  operatori eterogenei  rispetta  la
seguente tabella di priorita' (dall'alto verso il basso):

operatori aritmetici
operatori relazionali
operatori logici

Nel  caso in  cui compaiano  termini non  omogenei  nelle espressioni,
Fortran  esegue  una  conversione  di  tipo verso  il  piu'  generico,
seguendo questo schema:

interi < reali < complessi

il quale  vuole significare che se  ci sono valori interi  e reali, il
risultato sara' reale, mentre, ad  esempio, complessi e reali danno un
risultato  complesso.  Le  regole  di conversione  avvengono  seguendo
l'ordine di esecuzione dell'espressione.

***Selezioni e cicli

Secondo il  teorema di Boehm-Jacopini, tutto il  codice e' esprimibile
tramite  assegnamenti, selezioni  e  cicli: allora  non possono  certo
mancare   neanche   in   Fortran   quest'ultime   due   primitive   di
programmazione.

***Selezione

E' il classico costrutto if..then..else:

if () then
	...
	...
elseif () then
	...
	...

else (un solo ramo else)
	...
	...
endif

Come evidenziato sopra, possono esistere piu' rami `elseif' ma un solo
ramo `else'. E' bene notare  che le parentesi esterne ad 
sono necessarie; naturalmente, se  non sono necessari, i rami `elseif'
ed `else' possono essere omessi.

Se l'istruzione  da eseguire nel caso sia  verificata  e'
una sola, possiamo usare un costrutto alternativo e piu' compatto:

if () 

esistono pero' delle limitazioni sull'istruzione da eseguire.

***Salti incondizionati

E' presente  anche l'istruzione `goto', a volte  indispensabile, ma se
ne _sconsiglia_ vivamente il suo  utilizzo; esso e' tollerato solo per
uscire da cicli o selezioni, ma ESCLUSIVAMENTE se il salto da compiere
e' in avanti.

Si ricorda che le label  sono definibili in ogni posizione delle prime
5 colonne.

***Cicli

In  Fortran sono presenti  i cicli  iterativi (diciamo  i `for')  ed i
cicli condizionati (i classici `while'):

do i=n1,n2{,k}
...
...
enddo

dove n1 ed n2 rapprensentano l'intervallo dove l'indice del ciclo deve
variare,  con  la  possibilita'  di  specificare  anche  il  passo  di
incremento k:  nel caso non  venga specificato, l'incremento  e' posto
pari ad 1.  Da notare che  l'indice del ciclo assume il valore n2+k al
termine dell'iterazione e che il  controllo di fine loop avviene prima
dell'esecuzione del blocco di istruzioni all'interno.

do while()
...
...
enddo

si tenga presente che l'istruzione `while' non e' disponibile su tutti
i compilatori.

Il primo tipo di ciclo  e' nella forma che andrebbe sempre utilizzata,
ma e' concesso anche una  formulazione equivalente nel caso in cui non
sia disponibile il `while' e che contiene salti al suo interno:

do