appunti di fortran 77

89
Appunti di FORTRAN 77 Maria Grazia Gasparo Aprile 2011 i

Upload: lydiep

Post on 05-Jan-2017

267 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Appunti di FORTRAN 77

Appunti di FORTRAN 77

Maria Grazia Gasparo

Aprile 2011

i

Page 2: Appunti di FORTRAN 77

ii

Page 3: Appunti di FORTRAN 77

Indice

1 Linguaggio macchina e assembly 1

2 Linguaggi interpretati e compilati 3

3 Storia del FORTRAN 5

4 Perche insegnare il FORTRAN 77? 7

5 Realizzazione di un programma FORTRAN 85.1 Compilazione . . . . . . . . . . . . . . . . . . . . . . . . . . . 95.2 Collegamento . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

6 Elementi di base del FORTRAN 126.1 Alfabeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126.2 Struttura delle linee . . . . . . . . . . . . . . . . . . . . . . . 126.3 Struttura delle unita di programma . . . . . . . . . . . . . . . 136.4 Costanti, variabili e loro tipo . . . . . . . . . . . . . . . . . . 146.5 Variabili dimensionate (arrays) . . . . . . . . . . . . . . . . . 18

7 Espressioni e istruzione di assegnazione 227.1 Espressioni aritmetiche . . . . . . . . . . . . . . . . . . . . . . 227.2 Assegnazione aritmetica . . . . . . . . . . . . . . . . . . . . . 257.3 Fortran 90: operazioni fra arrays . . . . . . . . . . . . . . . . 25

8 Controllo del flusso di esecuzione 268.1 Istruzione GO TO . . . . . . . . . . . . . . . . . . . . . . . . 278.2 Istruzioni IF . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

8.2.1 IF logico . . . . . . . . . . . . . . . . . . . . . . . . . . 288.2.2 IF–THEN–ENDIF. . . . . . . . . . . . . . . . . . . . . 288.2.3 IF–THEN–ELSE–ENDIF . . . . . . . . . . . . . . . . 308.2.4 IF concatenati. . . . . . . . . . . . . . . . . . . . . . . 32

8.3 Fortran 90: istruzione SELECT CASE. . . . . . . . . . . . . 348.4 Istruzione DO . . . . . . . . . . . . . . . . . . . . . . . . . . . 348.5 DO impliciti . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388.6 Fortran 90: DO illimitato e DO WHILE . . . . . . . . . . . . 39

9 Esempi riassuntivi 409.1 Esempio 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409.2 Esempio 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419.3 Esempio 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

iii

Page 4: Appunti di FORTRAN 77

10 L’istruzione WRITE(u,f) 4310.1 Scrivere su un file. . . . . . . . . . . . . . . . . . . . . . . . . 4410.2 Scegliere il formato di scrittura. . . . . . . . . . . . . . . . . . 4510.3 Alcuni esempi . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

11 Sottoprogrammi 4811.1 Sottoprogrammi FUNCTION . . . . . . . . . . . . . . . . . . 4911.2 Sottoprogrammi SUBROUTINE . . . . . . . . . . . . . . . . 5411.3 Associazione fra argomenti muti e argomenti attuali . . . . . 5611.4 Argomenti muti dimensionati . . . . . . . . . . . . . . . . . . 5811.5 Dimensionamento variabile e indefinito per vettori . . . . . . 6011.6 Dimensionamento variabile e indefinito per matrici . . . . . . 62

12 Alcune regole di buona programmazione 6512.1 Istruzioni di scrittura nei sottoprogrammi . . . . . . . . . . . 6512.2 Istruzioni STOP e RETURN . . . . . . . . . . . . . . . . . . 6712.3 Arrays di lavoro . . . . . . . . . . . . . . . . . . . . . . . . . . 67

13 Esempi di programmi con sottoprogrammi 7013.1 Esempio 1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7013.2 Esempio 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7213.3 Esempio 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7513.4 Esempio 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

14 Istruzione EXTERNAL 81

15 Istruzione COMMON 82

Bibliografia 85

iv

Page 5: Appunti di FORTRAN 77

1 Linguaggio macchina e assemblyassembly

Un linguaggio di programmazione e un linguaggio utilizzabile per scriverealgoritmi che il computer puo capire (direttamente o tramite una traduzione)e eseguire. Nell’accezione piu semplice, che in questo momento ci basta, unprogramma e un algoritmo scritto in un linguaggio di programmazione.

Il fatto che tutte le informazioni debbano essere memorizzate su un com-puter come sequenze di bits implica che anche le istruzioni di un algoritmo,per poter essere direttamente eseguite dal computer, devono essere scritte inun linguaggio il cui alfabeto e composto soltanto dai simboli “0” e “1”. Nonsolo, ma la sintassi di questo linguaggio e strettamente dipendente dall’ar-chitettura della macchina ed e quindi diversa per ogni processore, o famigliadi processori. Data questa dipendenza, ci si riferisce a questo linguaggiocon l’espressione generica linguaggio macchina. In un linguaggio di questotipo, ad ogni operazione elementare (aritmetica, logica, di assegnazione, disalto, etc...) corrisponde un codice operativo e ogni operando e identificatotramite l’indirizzo della locazione in cui e memorizzato1. Codici operativi eindirizzi sono sequenze di 0 e 1 di lunghezza prefissata.

Scrivere o leggere un programma in linguaggio macchina e estremamentedifficile: si tratta in generale di programmi molto lunghi e complessi, incom-prensibili per i non addetti ai lavori. Il primo passo per superare questadifficolta fu la definizione dei cosiddetti linguaggi assembly, che nacqueropraticamente insieme ai primi computers negli anni ’40. Questi sono ancoralinguaggi dipendenti dall’hardware della macchina per cui sono progettati,perche le istruzioni sono in corrispondenza biunivoca con quelle del lin-guaggio macchina; d’altra parte sono linguaggi simbolici e il loro utilizzo edecisamente piu facile. Con l’espressione “linguaggio simbolico” si intendeche i codici operativi binari sono sostituiti da codici alfanumerici mnemonicidetti parole chiave (es: ADD per l’addizione, STO per la memorizzazione) ei riferimenti alle locazioni di memoria avvengono attraverso nomi simbolici,o identificatori, scelti dall’utente rispettando le regole stabilite dal linguag-gio. Per poter essere eseguito, un programma assembly deve essere tradottoin linguaggio macchina da un opportuno programma detto assembler. Eimportante aver presente che i linguaggi assembly non sono nient’altro cheversioni simboliche dei linguaggi macchina e non sono quindi portabili, nelsenso che un programma scritto per un computer non puo essere eseguitosu un altro computer con un processore diverso.

Il vero salto di qualita, dal punto di vista della portabilita dei programmie della facilita di programmazione, si ebbe negli anni ’50, quando nacqueroi primi linguaggi di programmazione ad alto livello. L’idea di fondo eradefinire dei linguaggi la cui sintassi prescindesse dall’architettura di un par-

1Un dato puo essere anche un’istruzione del programma stesso. Si pensi ad esempioa un’istruzione di salto “Vai all’istruzione tal dei tali”, nella quale l’operazione e espressadalla parola “Vai” e l’operando e l’istruzione tal dei tali.

1

Page 6: Appunti di FORTRAN 77

ticolare computer e fosse invece vicina al linguaggio “parlato” usato perdescrivere gli algoritmi. Siccome il tipo di algoritmi e di conseguenza il lin-guaggio comune utilizzato per descriverli era diverso a seconda degli ambitiapplicativi in cui un programmatore si trovava a lavorare, furono creati di-versi linguaggi ad alto livello destinati a settori diversi. I primi linguaggifurono :

–FORTRAN (FORtran TRANslation), destinato ad algoritmi di naturamatematico/computazionale e sviluppato intorno al 1955 in ambiente IBMda un gruppo di lavoro guidato da J. Backus.

–LISP (LISt Processing), per applicazioni nell’ambito dell’intelligenza arti-ficiale, sviluppato intorno al 1958 al Massachussets Institute of Technologyda J. McCarthy e collaboratori.

–COBOL (COmmon Business Oriented Language), finalizzato alla stesuradi programmi in ambito commerciale e imprenditoriale, sviluppato nel 1959da un comitato pubblico-privato noto come Short Range Committee.

–ALGOL 60 (ALGOrithmic Language), nato nel 1958 come IAL (Interna-tional Algorithmic Language) grazie agli sforzi congiunti di una organiz-zazione europea (GAMM) e una statunitense (ACM) per creare un linguag-gio universale di descrizione degli algoritmi, non orientato a una particolareclasse di problemi. IAL fu successivamente modificato fino a dar luogo aALGOL 60, che e stato molto importante non tanto come linguaggio in sestesso (le versioni commerciali non hanno avuto successo) quanto come pri-mo esempio di linguaggio indipendente dalla macchina e dal problema, concostrutti sofisticati (scelte, cicli) non ancora previsti dagli altri linguaggi dialto livello.

–BASIC (Beginners All-purpose Symbolic Instruction Code), sviluppato nel1964 al Darthmouth College da J. Kemeny e T. Kurtz come linguaggiodidattico, che facilitava l’avvicinamento alla programmazione di studenti diqualunque provenienza e formazione culturale.

Con l’evolversi della tecnologia e delle architetture dei computers, i lin-guaggi di programmazione si sono evoluti, spesso dando luogo a numerosidialetti anche molto diversi dal linguaggio originale, e molti altri linguag-gi sono nati. ALGOL 60 influenzo in molti casi l’ evoluzione dei linguaggipreesistenti e la definizione di quelli nuovi. Ad esempio, un discendente di-retto di ALGOL e il PASCAL, sviluppato negli anni 1971-73 da N. Wirthcome linguaggio per insegnare i principi della programmazione nello spiritodi ALGOL, e molto diffuso nelle scuole statunitensi ed europee negli anni’70-’80. Negli stessi anni nacque il linguaggio C, ad opera di D.M. Richtie eK. Thompson, come linguaggio per la programmazione di sistema nell’am-bito dello sviluppo del nascente sistema operativo Unix. La fortuna del C

2

Page 7: Appunti di FORTRAN 77

e la sua evoluzione sono dovute al fatto che, pur essendo un linguaggio dialto livello, permette di accedere ad aspetti di basso livello del computer,come fanno i linguaggi assembly. Negli anni ’80, con l’affermarsi dei Person-al computers e delle interfacce grafiche, si sono sviluppati linguaggi orientatiagli oggetti, come C++ (un discendente del C sviluppato intorno al 1979 daB. Straustrup) e Java (1995, J. Gosling). Vogliamo infine citare MATLAB(MATrix LABoratory), un linguaggio, o meglio dire un ambiente di program-mazione, attualmente molto usato nell’insegnamento dell’analisi numerica edell’algebra lineare anche teorica. Il progetto MATLAB partı verso la finedegli anni ’70 ad opera di C. Moler per permettere ai suoi studenti di usarele librerie FORTRAN per l’algebra lineare senza dover imparare il linguag-gio FORTRAN. Visto il successo dell’operazione, negli anni ’80 la proprietafu acquisita dal gruppo Mathworks, che da allora ha curato lo sviluppo e lavendita di MATLAB. Piu o meno negli anni in cui MATLAB diventava unlinguaggio di proprieta, nasceva il linguaggio GNU Octave, che ha molto incomune con MATLAB ed e open-source.

2 Linguaggi interpretati e compilati

Come gia detto per i programmi assembly, anche i programmi scritti in unlinguaggio di programmazione ad alto livello devono essere tradotti nel loroequivalente in linguaggio macchina per poter essere eseguiti. La traduzione emolto piu onerosa che per i programmi assembly dal momento che i linguaggiad alto livello prevedono l’utilizzo di costrutti e istruzioni che non hannouna controparte diretta nei linguaggi macchina. Ad esempio, la sempliceistruzione di assegnazione

Assegna a c il valore di a+b,

che in un linguaggio piu algoritmico potremmo esprimere come

Poni c = a + b,

oppurec← a + b,

ha una traduzione immediata del tipo

c = a + b (1) assegnazione

in tutti i linguaggi ad alto livello, ma non nel contesto di un linguaggiomacchina, dove ad essa corrisponde una sequenza di piu operazioni di bas-so livello. Per chiarire meglio questo punto, ricordiamo che l’operazione diassegnazione si divide in due fasi: il calcolo del valore dell’espressione alladestra del segno di “=” e la memorizzazione del risultato nella locazione as-sociata al nome simbolico indicato a sinistra del segno di “=”. Ricordiamo

3

Page 8: Appunti di FORTRAN 77

anche che per eseguire le operazioni aritmetiche i processori utilizzano lo-cazioni speciali chiamate registri, con un numero di bits piu alto che nellenormali locazioni adibite alla memorizzazione dei numeri floating point (adesempio, 80 bits contro i 32 o 64 dei numeri reali in precisione semplice odoppia). Lo scopo di questa maggiore lunghezza e ovviamente quello di ac-cumulare un risultato piu preciso, la cui mantissa verra poi approssimata perarrotondamento al momento della memorizzazione in una normale locazionefloating point. Supponiamo per semplicita di lavorare su un computer conun solo registro, dove viene copiato un operando, mentre l’altro resta nellasua locazione (situazioni piu realistiche, nelle quali i processori usano piu diun registro, sono descritte nel libro

Overton[3]). Allora, l’istruzione (

assegnazione1) viene spez-

zata in una sequenza di tre operazioni di un livello sufficientemente bassoda avere una codifica in linguaggio macchina:

1. Copia nel registro il contenuto della locazione corrispondente all’identifi-catore a;

2. Somma al contenuto del registro il contenuto della locazione individuatadal nome b, memorizzando il risultato nel registro stesso;

3. Trasferisci il contenuto del registro nella locazione corrispondente all’i-dentificatore c.

Esistono due modalita per la traduzione di un programma in linguaggiomacchina: l’interpretazione e la compilazione. Nel primo caso la traduzione el’esecuzione vanno di pari passo: un interprete traduce un’istruzione per vol-ta e, in assenza di errori di sintassi, la esegue immediatamente; le istruzioniin linguaggio macchina non vengono conservate in memoria. Nel secondocaso un compilatore traduce tutto il programma, generando un programmain linguaggio macchina equivalente a quello originale, che puo essere con-servato in memoria. La compilazione talvolta prevede due passaggi: primail programma viene tradotto in linguaggio assembly e poi l’assembler tra-duce in linguaggio macchina. Sia gli interpreti che i compilatori sono a lorovolta programmi, spesso originariamente scritti in un linguaggio di program-mazione, tradotti in linguaggio macchina e definitivamente memorizzati sulcomputer.

In linea di principio, dato un qualsiasi linguaggio L e un qualsiasi pro-cessore P, si potrebbe progettare sia un interprete che un compilatore pertradurre programmi scritti in L nel linguaggio macchina di P. In prati-ca, alcuni linguaggi vengono tipicamente tradotti mediante interpretazione(linguaggi interpretati) e altri mediante compilazione (linguaggi compilati).Ad esempio MATLAB e la sua controparte GNU Octave sono interpretati,mentre FORTRAN, C e C++ sono compilati. In realta, molti informaticiritengono superata questa classificazione perche oggigiorno le due modalitadi traduzione spesso sono mescolate; ad esempio, il compilatore traduce ilprogramma in un linguaggio intermedio fra quello originale e l’assembly, e

4

Page 9: Appunti di FORTRAN 77

poi la traduzione in linguaggio macchina viene affidata a un interprete.

3 Storia del FORTRAN

Come gia accennato, il FORTRAN fu sviluppato, primo fra i linguaggi diprogrammazione ad alto livello, intorno al 1955 all’IBM, destinato all’alloranuovo computer IBM-704. Il primo compilatore fu elaborato nel 1957. Ilsuccesso di questo linguaggio rivoluzionario, che permetteva ai programma-tori di scrivere istruzioni piu vicine al linguaggio matematico (e inglese) cheal linguaggio macchina, fu tale che negli anni immediatamente successivicominciarono a proliferare dialetti, e corrispondenti compilatori, destinati aidiversi computers allora disponibili. L’esistenza di dialetti diversi impedivala portabilita dei programmi, vanificando in larga misura il fatto dell’essersiaffrancati dalla sintassi del linguaggio macchina. Si comincio allora a pro-gettare uno standard del linguaggio, ovvero un insieme di regole sintatticheche avrebbero dovuto essere riconosciute da tutti i compilatori: un program-ma scritto rispettando rigorosamente quelle regole sarebbe stato traducibileda qualunque compilatore che si adeguasse ad esse, e quindi estremamenteportabile. Nel 1962 fu fondata a tale scopo una commissione nell’ambitodell’ANSI2 che lavoro fino al 1966, quando vide la luce il primo FORTRANstandard, noto come FORTRAN 66. Era un linguaggio ancora molto roz-zo rispetto ai linguaggi attuali. Basti pensare che non prevedeva istruzioniper descrivere in modo immediato situazioni di scelta fra piu percorsi al-ternativi, ma soltanto un’istruzione tramite la quale si esegue o meno unasingola azione, in base al verificarsi o meno di una determinata condizione(cfr. paragrafo

iflogico8.2.1). Per intendersi, un costrutto del tipo

Se a > b, allora:max = a

altrimenti:max = b

Fine scelta

non aveva un’immediata traduzione in FORTRAN 66; per ottenere il risulta-to desiderato si doveva concepire l’algoritmo nel seguente modo, equivalenteal precedente ma molto piu complicato:

2L’ANSI (American National Standard Institute) e un’organizzazione fondata nel 1918con il nome American Engineering Standards Committee allo scopo di sviluppare stan-dards per prodotti, servizi, procedure, etc.. in diversi settori dell’ingegneria. Il nome subıdiverse variazioni negli anni, fino a diventare quello attuale nel 1969. Oggi nell’ANSI sonorappresentate alcune agenzie governative statunitensi, corporations, universita e soggettiprivati.

5

Page 10: Appunti di FORTRAN 77

Se a ≤ b, vai all’istruzione 10max = avai all’istruzione 20

10 max = b20 ......

Nel 1969 fu deciso di por mano alla definizione di un nuovo standardper tener conto delle tante importanti estensioni del FORTRAN 66 fioritein quegli anni e anche del fatto che nel frattempo erano nati altri linguaggi,fra cui il C, che erano decisamente avanti rispetto al FORTRAN 66, ed eraimperativo adeguarsi se non si voleva che il linguaggio morisse. Il nuovo stan-dard, noto come FORTRAN 77, fu pubblicato nel 1978. Le novita rispettoalla precedente versione erano moltissime. Fra queste ricordiamo l’intro-duzione di istruzioni di scelta articolate e la possibilita di gestire abbastanzaagevolmente stringhe di caratteri. Il FORTRAN 77 e stato il FORTRANper molti anni, e per certi aspetti lo e ancora, in quanto molti programmidi pubblico dominio sono scritti in FORTRAN 77 e molti programmatoricontinuano a usarlo anche se nel frattempo il linguaggio si e ulteriormenteevoluto.

Il successivo standard, noto come Fortran 90, fu pubblicato nel 1992.Ancora una volta, per stare al passo con altri linguaggi saliti prepotente-mente alla ribalta, quali il C++ e il MATLAB, furono introdotte innovazionisostanziali: gli autori del nuovo standard hanno voluto cambiare la sigla daFORTRAN a Fortran, probabilmente per evidenziare che il nuovo standarde talmente diverso dal precedente da poter essere quasi considerato un nuo-vo linguaggio. Fra le principali innovazioni ricordiamo: le operazioni sugliarray (variabili dimensionate quali vettori, matrici, etc.) o sezioni di ar-ray (ad esempio gruppi di righe e/o colonne di una matrice) che possonosnellire la stesura dei programmi e migliorarne l’efficienza su computers conadeguate architetture; la gestione dinamica della memoria contrapposta aquella statica del FORTRAN 773; i tipi di dati definiti dall’utente; i punta-tori. Gli estensori del Fortran 90 hanno comunque mantenuto il FORTRAN77 come sottinsieme del nuovo standard, per ovvii motivi di compatibilita:una scelta diversa avrebbe significato dover buttare alle ortiche o tradurretutto il (tanto) software scritto in FORTRAN 77, il che avrebbe probabil-mente provocato la rivolta degli utilizzatori. In alcuni ambienti si parla diFortran 90/95 invece che Fortran 90. Questo e dovuto al fatto che negli anniimmediatamente successivi al 1992 il Fortan 90 subı un primo aggiustamen-to, mirato essenzialmente ad eliminare alcune ambiguita che complicavanola costruzione dei compilatori e rischiavano di compromettere la portabilita

3Con gestione statica della memoria si intende che la memoria per le variabili coinvoltein un programma viene allocata dal compilatore, prima dell’esecuzione. Questo implica fral’altro che il programmatore deve decidere in fase di stesura del programma le dimensionidi tutte le variabili dimensionate coinvolte. Con la gestione dinamica invece la memoriaper le variabili viene allocata durante l’esecuzione, via via che si rende necessaria.

6

Page 11: Appunti di FORTRAN 77

dei programmi. Si arrivo cosı al nuovo standard Fortran 95, in cui comunquenon ci sono novita di rilievo rispetto al Fortran 90.

Concludiamo questo excursus citando gli aggiornamenti piu recenti: ilFortran 2003, che ha introdotto alcuni elementi di programmazione a oggetti,e il Fortran 2008 che ne aggiusta le ambiguita.

4 Perche insegnare il FORTRAN 77?

Queste dispense raccolgono gli elementi essenziali di FORTRAN 77, anchese talvolta verranno indicate delle alternative proprie del Fortran 90 ormaiaccettate da molti compilatori oggi in uso. Per tutti i dettagli che qui nonvengono discussi, gli studenti possono ricorrere ai libri

AGM[1] e

MR[2] citati in

bibliografia, o al numeroso materiale reperibile in rete (da prendersi conmolto spirito critico, come tutte le informazioni diffuse in Internet).

Per quanto riguarda i compilatori FORTRAN, faremo spesso riferimentoin queste dispense a due di essi, entrambi liberamente scaricabili da Internet,che presumibilmente saranno usati dagli studenti a cui questi appunti sonodestinati: il compilatore Open WATCOM, che e utilizzabile in ambienteWindows e realizza un FORTRAN 77 stretto, e il compilatore gfortran,che e utilizzabile in ambiente Linux e realizza il Fortran 90/95.

Perche continuare a insegnare uno standard ormai “vecchio” come ilFORTRAN 77? Ci sono diverse risposte a questa domanda.

1) Molte importanti librerie matematiche, prima fra tutte LAPACK perl’algebra lineare, sono scritte in FORTRAN 77 e, per poterle usare bene,occorre conoscere questo linguaggio.

2) La gestione statica della memoria prevista dal FORTRAN 77 talvoltacomplica un po’ la stesura dei programmi perche il programmatore deve de-cidere fin dall’inizio le dimensioni di tutte le variabili dimensionate coinvoltenel programma. Questa necessita fu eliminata nel Fortran 90 introducendola possibilita di gestire dinamicamente la memoria, gia prevista da altri lin-guaggi come il C++ e il MATLAB. D’altra parte, la gestione dinamica haun potenziale svantaggio pratico, tristemente noto a molti programmatoriche ne hanno fatto esperienza: la quantita di memoria richiesta per l’ese-cuzione di un programma e spesso decisamente maggiore di quella richiestain regime statico, con il risultato che su macchine con risorse limitate (adesempio un normale Personal Computer) diventa impossibile far eseguire ilprogramma.

3) Alcuni compilatori open-source oggi molto usati, come gfortran, con-sentono l’allocazione dinamica della memoria ma non la realizzano bene.Il risultato e che l’esecuzione di un programma puo essere interrotta dalsistema per violazioni della memoria anche se non contiene errori.

7

Page 12: Appunti di FORTRAN 77

4) Una volta che si conosce bene un linguaggio di programmazione “rigido”come il FORTRAN 77, diventa assolutamente facile imparare il Fortran 90.

5 Realizzazione di un programma FORTRANrealizza

Con il termine realizzazione, o implementazione, di un programma scrittoin FORTRAN si intende la sequenza di operazioni da fare per arrivare al-l’esecuzione del programma. Per i linguaggi compilati come il FORTRANle operazioni sono due: compilazione e collegamento. Per spiegare in cosaconsistono queste due operazioni, faremo riferimento al seguente sempliceprogramma:

PROGRAM ERONEC Programma che calcola l’area di uno o piu triangoliC usando la formula di Erone

REAL A,B,C,SP,AREAINTEGER LEGGI

10 PRINT∗, ’immettere le lunghezze dei lati’READ∗, A,B,CSP=(A+B+C)/2.AREA=SQRT(SP∗(SP-A)∗(SP-B)∗(SP-C))PRINT∗,’area= ’, AREAPRINT∗,’ancora? (1/0= si/no)’READ∗,LEGGIIF(LEGGI.EQ.1) GOTO 10STOPEND

Lo scopo del programma e calcolare e stampare l’area di uno o piu triangolicon la formula di Erone secondo la quale, ricordiamolo, l’area e data da

s(s− a)(s− b)(s − c),

dove a, b, e c sono le lunghezze dei lati e s e il semiperimetro. Nel programmausiamo i nomi A,B e C per a, b e c e SP per s. Senza entrare nei dettagli,diamo un cenno al significato di tutte le istruzioni contenute nel programma:

– L’istruzione PROGRAM ERONE da un nome al programma;

– Le istruzioni REAL A,B,C,SP,AREA e INTEGER LEGGI mettono in evi-denza che A,B,C,SP e AREA rappresentano grandezze a valori reali, mentreLEGGI identifica una grandezza a valori interi;

– Le istruzioni caratterizzate dalla parola chiave PRINT∗, sono istruzionidi scrittura sul video: le stringhe racchiuse fra apici (come ‘immettere lelunghezze dei lati’) vengono riprodotte pari pari, mentre delle variabili comeAREA viene stampato il valore;

8

Page 13: Appunti di FORTRAN 77

– Le istruzioni caratterizzate dalla parola chiave READ∗, sono istruzionidi lettura: i dati vengono scritti sulla tastiera separati da virgole o spazibianchi, su una o piu righe;

– L’istruzione IF(LEGGI.EQ.1) GOTO 10 realizza una situazione di scelta:se il valore della variabile LEGGI e uguale a 1, viene eseguita l’istruzioneGOTO 10, per effetto della quale l’esecuzione del programma riprende dal-l’istruzione 10 PRINT∗, ’immettere le lunghezze dei lati’; altrimenti l’ese-cuzione prosegue con la successiva istruzione STOP che fa fermare il pro-gramma. Questo significa che il numero di triangoli non e fissato in anticipo:dopo aver calcolato l’area di un triangolo, il programma chiede se si devecontinuare; in caso affermativo, si leggono le lunghezze dei lati di un nuovotriangolo, altrimenti ci si ferma4.

– L’istruzione END che indica la fine del programma.

5.1 Compilazionecompila

La compilazione consiste nella traduzione del programma FORTRAN, det-to programma sorgente, nel suo equivalente in linguaggio macchina, dettoprogramma oggetto. La traduzione e un’operazione complessa perche coin-volge l’analisi lessicale, sintattica e semantica del programma sorgente. Ilcompilatore ha anche il compito di allocare la memoria per il programma.Per semplificare, possiamo sintetizzare la compilazione nel modo seguente.

Il compilatore effettua una prima scansione del programma, durante laquale vengono distinti gli identificatori scelti dal programmatore dalle parolechiave e simboli di operazioni aritmetiche/logiche. Durante questa scansioneviene creata la tavola dei simboli nella quale vengono elencati gli identi-ficatori, ciascuno con i suoi attributi (informazioni utili a interpretarne ilsignificato nelle fasi successive) e l’indirizzo di memoria assegnatogli.

Osserviamo il programma ERONE, scorrendo il quale il compilatore trova iseguenti identificatori:

– il nome simbolico ERONE, che identifica il programma;

– i nomi simbolici A, B, C, SP e AREA, che il programmatore ha sceltoper identificare le grandezze variabili su cui il programma opera; il compila-tore inserisce nella tavola dei simboli tutti questi identificatori e per ognunoindica la dimensione (scalare), il tipo (reale) e l’indirizzo della locazione dimemoria che gli viene associata;

4Dal punto di vista algoritmico, questo si configura come un ciclo while, in cui ilproseguimento o l’interruzione delle ripetizioni dipendono dal verificarsi o meno di unadeterminata condizione. Il FORTRAN 77 non prevede un’istruzione che realizzi questotipo di ciclo, che pertanto viene realizzato tramite l’istruzione di scelta IF e quella di salto

GOTO. Il Fortran 90 ha invece introdotto un’apposita istruzione.

9

Page 14: Appunti di FORTRAN 77

– il nome simbolico LEGGI, scelto dal programmatore per gestire l’inter-ruzione del programma; il compilatore lo inserisce nella tavola dei simboliindicando la dimensione (scalare), il tipo (intero) e l’indirizzo della locazionedi memoria che gli viene associata.

– il numero 10 che precede l’istruzione PRINT∗, ...; il compilatore classifi-ca questo identificatore come etichetta (in inglese, label) e lo inserisce nellatavola dei simboli insieme all’indirizzo in memoria dell’istruzione corrispon-dente;

– il numero 2. nell’istruzione SP=(A+B+C)/2.; il compilatore lo classificacome identificatore di una costante reale e lo inserisce nella tavola insiemeall’indirizzo della locazione di memoria in cui tale valore e memorizzato;

– il nome simbolico SQRT, che identifica una procedura, piu precisamenteuna funzione intrinseca, per il calcolo della radice quadrata di un numeroreale5; il compilatore lo inserisce nella tavola insieme alle indicazioni utiliper l’aggancio alla procedura nella successiva fase di collegamento;

Dopo aver costruito la tavola dei simboli, il compilatore scandisce nuo-vamente il programma per effettuare la traduzione vera e propria: le parolechiave e i simboli di operazioni aritmetiche e logiche vengono sostituiti dalloro equivalente in linguaggio macchina e gli identificatori vengono sostituitidagli indirizzi delle locazioni di memoria ad essi associati durante la pri-ma scansione. Il risultato e il programma oggetto. La traduzione non puoovviamente essere portata a termine se una o piu istruzioni non sono sintat-ticamente corrette. In questo caso, al posto del programma oggetto vienegenerato un’elenco degli errori di sintassi presenti nel programma e delleistruzioni in cui tali errori si trovano (diagnostico). Usando questo elenco,il programmatore puo correggere gli errori e risottoporre il programma alcompilatore, fino a quando tutti gli errori non siano stati eliminati. La for-ma in cui il diagnostico viene presentato e il livello di dettaglio variano dacompilatore a compilatore.

Alcuni compilatori prevedono anche la segnalazione, attraverso messag-gi di avvertimento (Warning), della presenza nel programma di eventualisituazioni sospette, che non sono classificabili come errori di sintassi mapotrebbero nascondere qualche svista del programmatore; ad esempio, senello scrivere l’istruzione

PRINT∗,’area= ’, AREA

nel programma ERONE si facesse un errore di battitura e l’istruzione risul-tasse

PRINT∗,’area= ’, ARRA

5Ogni compilatore e accompagnato da un insieme di procedure, dette funzioniintrinseche, che realizzano funzioni matematiche (e non solo) di interesse comune.

10

Page 15: Appunti di FORTRAN 77

qualche compilatore avvertirebbe la variabile ARRA viene usata senza chele sia stato attribuito alcun valore in precedenza (uninitialized variable). Lapresenza di situazioni anomale come questa non impedisce la traduzione delprogramma e la creazione del programma oggetto; d’altra parte, i messaggidi Warnings sono molto utili per individuare veri e propri errori, di battiturao di altra natura. Per quanto riguarda i due compilatori di riferimento, ilgfortran segnala i messaggi di Warning soltanto se usato con l’opzione–Wall (che raccomandiamo vivamente di usare sempre), mentre l’ OpenWATCOM li segnala automaticamente.

Come impareremo piu avanti, un programma FORTRAN e spesso com-posto da piu unita di programma, o moduli sorgenti, ciascuno dei quali e latraduzione in FORTRAN di un algoritmo. Ad esempio, se dobbiamo scrivereun programma che prevede la risoluzione di un certo numero di equazionidi secondo grado, possiamo organizzarlo in due unita di programma: unache, dati i coefficienti a, b e c di un’equazione, ne calcola le soluzioni; l’altrache legge i coefficienti di tutte le equazioni, le risolve ad una ad una usandola prima unita, ed eventualmente stampa i risultati. Il secondo modulo e ilprogramma principale, quello che gestisce le operazioni; il primo modulo siconfigura invece come un sottoprogramma, che non “agisce” autonomamentema solo quando chiamato in causa dal programma principale. L’unione deidue moduli sorgenti forma il programma sorgente. Ebbene, in presenza di unprogramma costituito da piu unita di programma, il compilatore le traduceseparatamente e indipendentemente l’una dall’altra, creando per ciascuna diesse una tavola dei simboli e un modulo oggetto (o un diagnostico in presen-za di errori di sintassi). Quando tutti i moduli sorgenti sono privi di errori,l’unione dei moduli oggetto corrispondenti forma il programma oggetto.

5.2 Collegamentolink

Pur essendo scritto in linguaggio macchina, il programma oggetto non e an-cora eseguibile. Infatti, il compilatore non e in grado di stabilire a priori lerichieste di memoria di un’unita di programma, e tantomeno del program-ma nel suo complesso; segue da questo che gli indirizzi memorizzati nellatavola dei simboli relativa a un’unita di programma sono virtuali, in quantofanno riferimento all’indirizzo “0” in cui si considera memorizzata la pri-ma istruzione dell’unita di programma stessa. Trasformare questi indirizzivirtuali in indirizzi effettivi e il compito principale del linker (il “collega-tore”), il quale assolve a questo incarico essenzialmente tramite le seguentioperazioni:

1) crea una tabella dei moduli oggetto che compongono il programma;

2) assegna un indirizzo effettivo di inizio ad ogni modulo;

11

Page 16: Appunti di FORTRAN 77

3) modifica di conseguenza gli indirizzi virtuali all’interno di ogni modulo;

4) cerca in tutti i moduli le istruzioni che fanno riferimento ad altri modulie vi inserisce l’indirizzo di inizio dei moduli richiamati.

Se il programma fa riferimento a moduli inesistenti, o se occupa trop-pa memoria, il linker segnala la situazione di errore, altrimenti genera ilprogramma eseguibile. A questo punto si puo dare avvio all’esecuzione.

6 Elementi di base del FORTRAN

6.1 Alfabeto

L’insieme dei caratteri utilizzabili in un programma FORTRAN e il seguente:

26 lettere maiuscole: A, B, C, ..., W, Z

26 lettere minuscole: a, b, c, ..., w, z

10 cifre: 0, 1, ..., 9

12 caratteri speciali: = + - ∗/ ( ) . , ’ $ :

Alcuni altri caratteri speciali, fra cui ! , < e >, sono stati aggiunti all’alfa-beto nel Fortran 90.

Dal punto di vista della scrittura dei programmi, due cose sono importanti:

– I compilatori FORTRAN non fanno distinzione fra lettere maiuscole e mi-nuscole (si dice che il linguaggio e case-insensitive): le parole chiave possonoessere scritte con caratteri maiuscoli o minuscoli indifferentemente e nomisimbolici come “ANNA”, “Anna” o “anna” sono la stessa cosa;

– Esattamente come quando si scrive in italiano, nello scrivere un program-ma FORTRAN si devono separare le parole, intese come parole chiave eidentificatori, tramite spazi bianchi, a meno che non ci sia gia un simbolo(ad esempio una virgola o una parentesi aperta o chiusa) che funge da sepa-ratore. Durante la prima scansione del programma, il compilatore analizzale istruzioni in modo da distinguere le parole chiave dai separatori e dagliidentificatori. A questo fine, gli spazi bianchi in eccesso vengono ignorati(“GOTO 10” o “GOTO 10” sono considerati la stessa cosa); d’altraparte, l’assenza di uno spazio bianco necessario puo causare malintesi, percui nella scrittura “GOTO10” il compilatore non riesce a separare la paro-la chiave dall’identificatore e registra GOTO10 come un identificatore dainserire nella tavola dei simboli.

6.2 Struttura delle linee

Un programma FORTRAN e una successione di linee su cui sono scritte leistruzioni (in inglese, statements). Non e prevista punteggiatura per separare

12

Page 17: Appunti di FORTRAN 77

un’istruzione dalla successiva: la regola e che, finita un’istruzione, si va acapo e si inizia a scrivere la successiva.

Le istruzioni vanno scritte sulle linee rispettando il cosiddetto formatofisso, ereditato dall’epoca in cui non esistevano terminali e tastiere e i pro-grammi venivano scritti usando le schede perforate6 ; questo formato, che estato poi abbandonato dal Fortran 90, prescrive le seguenti regole per l’usodelle colonne:

Colonne da 1 a 5: sono riservate alle eventuali etichette delle istruzioni (cfr.l’istruzione “10 PRINT∗, ...“ del programma ERONE). Un’etichetta puoessere un qualunque numero naturale da 1 a 99999 e puo essere collocatadovunque in queste colonne.

Colonna 6: abitualmente e vuota; se contiene un (qualsiasi) carattere, lalinea viene considerata dal compilatore una continuazione di quella prece-dente.

Colonne da 7 a 72: in queste colonne vengono scritte le istruzioni. In virtudi quanto detto sull’utilizzo degli spazi, un’istruzione puo iniziare in qualsiasicolonna dalla 7 in poi. Se l’istruzione e troppo lunga e va oltre la colonna72, puo essere continuata sulla linea successiva.

Colonne da 73 in poi: sono ignorate dal compilatore.

Ogni programmatore sa che per rendere piu comprensibile un programmae buona regola inserire dei commenti che ne spieghino lo scopo e il flusso. InFORTRAN 77 questo scopo e raggiunto inserendo delle linee di commento,ovvero linee che contengono un carattere C o ∗ a colonna 1. In Fortran 90e considerato commento anche qualunque carattere scritto dopo un puntoesclamativo, in qualunque punto di una linea. I commenti sono ignorati dalcompilatore.

6.3 Struttura delle unita di programmastruttura

Le istruzioni FORTRAN si dividono in due categorie: le istruzioni eseguibilidescrivono azioni che dovranno essere compiute durante l’esecuzione delprogramma e vengono tradotte dal compilatore nelle equivalenti istruzionidel linguaggio macchina; le istruzioni non eseguibili invece forniscono infor-mazioni di cui il compilatore deve tener conto durante la traduzione, ma nonvengono tradotte di per se (sono istruzioni di questa natura, ad esempio, leintestazioni delle unita di programma come PROGRAM ERONE e le speci-ficazioni di tipo, come REAL A,B,C,SP,AREA e INTEGER LEGGI). Leistruzioni non eseguibili diverse da un’intestazione di unita di programma e

6Ogni scheda serviva a scrivere un’istruzione e aveva 80 colonne, su ciascuna delle qualiveniva perforato un carattere. Le ultime 8 colonne non venivano usate per le istruzioni delprogramma, ma per numerare le schede, in modo da poterle rimettere nell’ordine giustose per un motivo qualsiasi venivano mescolate.

13

Page 18: Appunti di FORTRAN 77

dalle FORMAT (di cui parleremo nel paragrafowrite10) sono chiamate istruzioni

di specificazione o dichiarative. Tenendo conto di questa classificazione, ogniunita di programma e divisa in quattro parti:

– l’intestazione, che e la prima istruzione nella quale si specifica se l’unita diprogramma e un programma principale o un sottoprogramma e, in questocaso, di quale tipo di sottoprogramma si tratta (cfr. paragrafo

sottoprog11). L’in-

testazione e facoltativa in un programma principale e obbligatoria in unsottoprogramma;

– la sezione dichiarativa, che raccoglie tutte le eventuali istruzioni dichiara-tive relative a nomi simbolici usati nell’unita di programma;

– la sezione esecutiva, che raccoglie tutte le istruzioni eseguibili;

– la fine dell’unita di programma, rappresentata dall’istruzione END.

Le istruzioni FORMAT possono comparire in qualsiasi punto dell’unita diprogramma. Queste regole sono schematizzate qui sotto, con riferimento inparticolare al programma ERONE.

intestazione PROGRAM ERONE

sezione dichiarativa INTEGER LEGGIREAL A,B,C,SP,AREA

sezione esecutiva 10 PRINT∗, ’immettere le lunghezze dei lati’...

STOP

fine END

Per ERONE, l’intestazione potrebbe non esserci perche si tratta di un pro-gramma principale. Notiamo inoltre che la sezione esecutiva del programmafinisce con l’istruzione STOP, e subito dopo viene l’istruzione END. A questoproposito, e importante puntualizzare la differenza fra STOP e END.

L’istruzione STOP e un’istruzione eseguibile che corrisponde all’azione“ferma l’esecuzione del programma”, e puo comparire in qualunque puntodell’unitas di programma (eventualmente anche in piu punti), dovunquel’algoritmo richieda di fermarsi. L’istruzione END rappresenta invece lafine fisica dell’unita di programma e compare sempre e soltanto alla fine;essa non corrisponde a nessuna azione, ma dice al compilatore che l’unitadi programma finisce in questo punto, e qualunque cosa sia scritta dopo laEND non ne fa parte. Un’istruzione STOP che preceda immediatamente laEND puo essere omessa.

6.4 Costanti, variabili e loro tipo

Le grandezze su cui un programma opera possono essere costanti o variabili.Una costante e una grandezza il cui valore e definito prima dell’esecuzione e

14

Page 19: Appunti di FORTRAN 77

non puo cambiare durante l’esecuzione. Una variabile e invece una grandezzail cui valore viene definito in fase di esecuzione e puo variare nel corso dellastessa. Il compilatore assegna una locazione di memoria sia alle costanti chealle variabili; la differenza sta nel fatto che nella locazione di una costanteviene subito memorizzato il valore, mentre in quella destinata a una variabilenon viene memorizzato alcun valore 7.

Sia le costanti che le variabili hanno un tipo che puo essere: intero, realein precisione semplice (o, semplicemente, reale), reale in precisione doppia(o, semplicemente, doppia precisione), complesso, logico, carattere.

Costanti. La forma in cui una costante e scritta ne determina tipo e valore.

Una costante intera e un numero senza punti o virgole decimali, eventual-mente preceduto da un segno. Sono esempi validi i seguenti:

0 999 –1325 34 +7 12459

mentre non lo sono –1.000 o 1,345 perche contengono il punto o la virgola.

Una costante reale e un numero in cui compare un punto decimale, eventual-mente preceduto da un segno. Essa puo essere scritta in forma esponenziale onon esponenziale; nel primo caso l’esponente consiste nella lettera E seguitada un intero positivo o negativo. Sono esempi validi i seguenti:

10. –8.05 1.45E–3 25.89E+1 –0.15E0 1.E–6 1.E6

mentre non sono validi 1,04 (perche contiene la virgola invece del punto) e-12.3E0.5 (perche l’esponente e un numero reale).

Nel formato esponenziale si puo evitare il punto decimale; ad esem-pio 5E3 e un’alternativa valida a 5.E3. Questa possibilita non esisteva inFORTRAN 66 ed e stata eliminata in Fortran 90.

Una costante doppia precisione si presenta come una costante reale in for-mato esponenziale, con la lettera D al posto di E. La differenza sta nelmodo in cui il valore viene convertito in binario e memorizzato. Ad esem-pio, su una macchina a 32 bits la costante 0.1D–4, che corrisponde al valore0.1 × 10−4, viene memorizzata su 64 bits, di cui 52 dedicati alla mantissae 11 alla caratteristica, mentre la costante 0.1E–4, che corrisponde al solitovalore, viene memorizzata su 32 bits, di cui 23 per la mantissa e 8 per lacaratteristica.

Una costante complessa e data da una coppia di costanti reali separate dauna virgola e racchiuse fra parentesi tonde: la prima costante rappresentala parte reale del numero e la seconda la parte immaginaria. Ad esempio,la costante (–0.1, 2.5E–2) identifica il numero complesso –0.1+0.025i. Il

7Alcuni compilatori, ma non tutti, inseriscono il valore 0 (zero) nelle locazioni destinatealle variabili.

15

Page 20: Appunti di FORTRAN 77

compilatore riserva a una costante di questo tipo due locazioni di memoriaconsecutive atte a contenere la rappresentazione floating point di un numeroreale8.

Una costante logica puo assumere solo due valori, “vero” e “falso”, che inFORTRAN sono scritti rispettivamente come .TRUE. e .FALSE.

Una costante carattere e una stringa di caratteri racchiusa fra apici. Sonoesempi di costanti carattere le stringhe ’immettere le lunghezze dei lati’,’area= ’ e ’ancora? (1/0= si/no)’ che compaiono nel programma ERONEdel paragrafo

realizza5.

Talvolta e utile identificare una costante con un nome simbolico, pursenza cambiarne la natura di costante. Immaginiamo di aver scritto unprogramma in cui compare molte volte la costante reale 1.E–3, e di volerlocambiare in modo che tutte le grandezze reali siano in doppia precisione.Allora tutte le occorrenze di 1.E–3 devono essere cambiate in 1.D–3 e dob-biamo usare a questo scopo la funzionalita “sostituisci” degli editori di testo.Un’alternativa e quella di scrivere il programma usando un nome simbolico,ad esempio COST, al posto della costante 1.E–3 e associare il nome allacostante tramite l’istruzione dichiarativa PARAMETER che ha in questocaso la forma

PARAMETER(COST=1.E–3)

Se organizziamo cosı il programma, per cambiare il tipo della costante sarasufficiente intervenire sull’istruzione PARAMETER, facendola diventare

PARAMETER(COST=1.D–3)

Il fatto che COST, pur essendo un nome simbolico, identifichi una costanteimplica che qualunque istruzione che tenti di cambiarne il valore provocherauna situazione di errore in fase di compilazione (nel qual caso il modulooggetto non viene creato) o in fase di esecuzione (nel qual caso l’esecuzionedel programma viene bloccata dal sistema).

Variabili. Una variabile e identificata da un nome simbolico che puo con-tenere solo lettere e cifre per un massimo di 6 caratteri e deve iniziare conuna lettera. I nomi

A1 B somma WORK n2p1 Norma2

sono validi, mentre

1c Norma 2 Spaziolavoro n2&1

8Alcuni compilatori accettano anche costanti di tipo complesso-doppia precisione, comead esempio (1.D2, –5.1D0), a cui vengono riservate due locazioni per numeri floating pointdoppia precisione.

16

Page 21: Appunti di FORTRAN 77

non lo sono. Alcune restrizioni sono state allentate nei dialetti nati dalFORTRAN 77 e le estensioni sono state poi recepite in Fortran 90; cosımolti compilatori accettano oggi nomi con un massimo di 31 caratteri econtenenti il carattere “underscore” ( ).

Cosa dire del tipo di una variabile? Se si vuole che essa sia consideratadal compilatore intera o reale, si puo sfruttare la regola di default seguente,in base alla quale l’iniziale del nome determina il tipo:

– iniziale da A a H : tipo reale

– iniziale I,J, K, L, M o N : tipo intero

– iniziale da O a Z : tipo reale.

Cosı, in assenza di altre indicazioni, il compilatore classifica come reali levariabili A1, WORK, FLAG, e come intere le variabili NORMA, L, MAX. Daquesto punto di vista, le istruzioni di specificazione REAL A,B,C,SP,AREAe INTEGER LEGGI nel programma ERONE del paragrafo

realizza5 sono inutili,

perche i tipi delle variabili coinvolte sarebbero per default quelli specificati.A questo proposito i programmatori FORTRAN si dividono grosso mo-

do in due categorie. Ci sono quelli che rispettano rigorosamente la regoladi default nella scelta dei nomi delle variabili intere e reali e di conseguen-za non hanno bisogno di istruzione dichiarative al riguardo. Al contrario,ci sono alcuni che, indipendentemente dal rispetto della regola di default,preferiscono dichiarare il tipo di tutte le variabili; questa scelta di solito haun carattere puramente “estetico”, ma acquista maggiore utilita se si utiliz-za l’istruzione dichiarativa (che non fa parte della standard FORTRAN 77,ed e invece standard per il Fortran 90)

IMPLICIT NONE

il cui effetto e annullare la regola di default, costringendo quindi a dichiarareesplicitamente il tipo di tutte le variabili. Siccome in questa situazione ilcompilatore segnala un errore se il tipo di una variabile non e specificato,si ha un controllo immediato sulla presenza di eventuali “errori di battitu-ra” nei nomi simbolici nella sezione esecutiva del programma. L’istruzioneIMPLICIT NONE deve precedere tutte le altre istruzioni dichiarative.

La regola di default contempla soltanto i tipi intero e reale. Per qualunquealtro tipo bisogna ricorrere a un’istruzione di specificazione di tipo usandoil dichiaratore che ci interessa fra

DOUBLE PRECISION, COMPLEX, LOGICAL e CHARACTER.

Le istruzioni in questione vanno inserite nella sezione dichiarativa dell’unitadi programma a cui si riferiscono e sono formate dalla parola chiave, ovveroil dichiaratore, seguito dall’elenco delle variabili a cui si vuole attribuire queltipo. Consideriamo alcuni esempi:

17

Page 22: Appunti di FORTRAN 77

DOUBLE PRECISION A, W1, W2, NORMA

COMPLEX RAD

LOGICAL CONDIZ, IND

CHARACTER∗10 NOME

Le prime tre frasi non hanno bisogno di spiegazione. L’ultima dice cheNOME identifica una variabile di tipo carattere di lunghezza 10, e pertantoi valori che NOME puo assumere sono stringhe di al piu 10 caratteri. Nonci dilungheremo oltre sulle variabili di tipo carattere, rimandando a

AGM[1] o

MR[2]

per ulteriori dettagli.Un altro strumento utilizzabile per specificare il tipo delle variabili e

l’istruzione IMPLICIT, che permette di associare un tipo particolare allevariabili il cui nome inizia con una particolare lettera dell’alfabeto o con unalettera appartenente ad un particolare gruppo. Per esempio, le istruzioni

IMPLICIT DOUBLE PRECISION D

IMPLICIT REAL M,N

dicono al compilatore che tutti i nomi simbolici che iniziano per D iden-tificano variabili di tipo doppia precisione e quelli che iniziano per M o Ncorrispondono a variabili reali; l’istruzione

IMPLICIT INTEGER (A-C)

attribuisce tipo reale a tutte le variabili il cui nome inizia per A, B o C;infine l’istruzione

IMPLICIT DOUBLE PRECISION (A-H,O-Z)

dichiara di tipo doppia precisione tutte le variabili il cui nome comincia peruna lettera fra A e H oppure fra O e Z (in pratica tutte le variabili che laregola di default definirebbe come reali).

6.5 Variabili dimensionate (arrays)arrays

Finora abbiamo parlato delle variabili FORTRAN come di grandezze scalari,a cui il compilatore associa una locazione di memoria. In realta capitamolto spesso di dover tradurre in FORTRAN algoritmi che operano anchesu vettori e matrici e, piu raramente, su variabili a tre o piu dimensioni(il massimo numero di dimensioni consentito in FORTRAN 77 e 7). Aquesto proposito, dobbiamo imparare due cose: come avvertire il compi-latore che un nome simbolico corrisponde a una variabile dimensionata (iltermine tecnico e array) e come tradurre in FORTRAN l’usuale notazionevettoriale con gli indici. Per quanto riguarda la prima questione, si puousare un’apposita istruzione dichiarativa, caratterizzata dalla parola chiave

18

Page 23: Appunti di FORTRAN 77

DIMENSION, tramite la quale si danno al compilatore tutte le informazioniche gli occorrono per allocare la memoria e tradurre poi nel modo correttole istruzioni eseguibili che coinvolgono elementi dell’array. Consideriamo adesempio l’istruzione

DIMENSION X(3), M(4,2)

Essa dice al compilatore che X e un vettore composto da 3 elementi e M euna matrice di 4 righe e 2 colonne. Il compilatore assegna a X tre locazionidi memoria consecutive in cui sono memorizzati gli elementi di X: nellaprima c’e l’elemento di indice 1, nella seconda quello di indice 2, e nellaterza quello di indice 3. Per la matrice M il compilatore riserva invece8 locazioni di memoria consecutive, nelle quali dobbiamo immaginare lamatrice memorizzata per colonne, come descritto nello schema seguente:

locazione: 1 2 3 4 5 6 7 8indici: (1,1) (2,1) (3,1) (4,1) (1,2) (2,2) (3,2) (4,2)

Esattamente come una variabile scalare, cosı anche una variabile dimen-sionata ha un tipo che viene attribuito dal compilatore in base alle stesseregole viste per le variabili scalari. Ad esempio, in assenza di dichiarazioni,X e un vettore reale e M e una matrice intera, con il che si intende che tuttigli elementi di X sono reali e tutti gli elementi di M sono interi.

Per informare il compilatore che una variabile e dimensionata, si possonousare anche istruzioni dichiarative diverse dalla DIMENSION; ad esempiol’istruzione

DOUBLE PRECISION VET1(20)

e equivalente alla coppia di istruzioni

DOUBLE PRECISION VET1DIMENSION VET1(20)

Negli esempi precedenti gli indici degli elementi dell’array vanno da 1fino alla dimensione stabilita nella dichiarazione dell’array. D’altra parte,talvolta puo essere comodo poter usare indici che variano fra estremi diversi.Ad esempio, spesso in matematica si usano scritture del tipo x0, x1, . . . , xn

per indicare i primi elementi di una successione, che possono essere assimilatiagli elementi di un vettore x di n + 1 elementi, in cui gli indici partono da0 e arrivano a n. Oppure, se si deve creare un vettore in cui memorizzarequanti abitanti di un paese sono nati negli anni dal 1991 al 2010, puo esserecomodo usare gli indici da 1991 a 2010 invece che da 1 a 20. In FORTRANe possibile dire al compilatore che gli indici non partono da 1, esprimendoesplicitamente nella dichiarazione dell’array il primo e l’ultimo valore chel’indice puo assumere. Nel primo dei due esempi precedenti, supponendon ≤ 10 si potrebbe usare la dichiarazione

19

Page 24: Appunti di FORTRAN 77

DIMENSION X(0:10)

e nel secondo esempio

INTEGER ABIT(1991:2010)

Di fronte a dichiarazioni come queste, il compilatore e comunque in gradodi contare il numero di elementi dell’array e allocare la memoria necessaria.

Un elemento di array puo essere usato in un programma alla stregua diuna variabile scalare, perche ad esso corrisponde una locazione di memoriail cui indirizzo e univocamente associato all’indice (o agli indici) che lo con-traddistingue. Per fare riferimento a un elemento di array si usa il nomedell’array seguito da tanti indici quante sono le dimensioni dell’array sep-arati da virgole e racchiusi fra parentesi. Un indice e una costante, unavariabile o un’espressione di tipo intero (parleremo nel prossimo paragrafodelle espressioni aritmetiche e del loro tipo). Dati un vettore V e una matriceA, sono ad esempio sintatticamente corretti i seguenti nomi di elementi:

V(1) A(I,J) V(I+1) A(1,J) V(K) A(K,K-1) M(V(1),1)

purche I,J e K siano variabili intere e il vettore V sia anch’esso intero (questaipotesi serve perche V(1) e usato come indice in M(V(1),1)). Consideriamo ilseguente programma MEDIE, che calcola e stampa la media dei voti riportatida un certo numero di studenti in un corso di laurea il cui regolamentoprevede 15 esami.

PROGRAM MEDIE∗ Programma che calcola la media dei voti riportati da uno o piu∗ studenti per un numero massimo di esami pari a 15

PARAMETER (NM=15)INTEGER V(NM)

10 PRINT∗, ’immettere il numero N di esami superati’PRINT∗, ’Attenzione: N deve essere <=’,NMREAD∗, NPRINT∗, ’immettere i voti’READ∗, (V(I), I=1,N)SMEDIA=0.DO 100 I=1,N

SMEDIA=SMEDIA+V(I)100 CONTINUE

SMEDIA=SMEDIA/NPRINT∗,’media= ’, SMEDIAPRINT∗,’ancora? (1/0= si/no)’READ∗,LEGGIIF(LEGGI.EQ.1) GOTO 10END

20

Page 25: Appunti di FORTRAN 77

Per ogni studente si legge il numero n ≤ 15 di esami superati e i relativivoti, che vengono memorizzati in un vettore V. L’istruzione

READ∗, (V(I), I=1,N)

e la traduzione FORTRAN dell’istruzione “Leggi v1, . . . , vn”, tramite laquale si leggono tutti i voti di uno studente. Osserviamo che se scrivessimosemplicemente

READ∗, V

la macchina si aspetterebbe in fase di esecuzione 15 dati, indipendentementeda N, perche la lunghezza di V e NM=15. Le istruzioni

DO 100 I=1,NSMEDIA=SMEDIA+V(I)

100 CONTINUE

sono la traduzione FORTRAN del ciclo

Per i = 1, . . . , nPoni media = media + vi.

Nelle istruzioni PRINT che precedono la lettura di N abbiamo fatto in mo-do che il valore (15) della costante NM venga visualizzato sullo schermoprima che l’utente inserisca il valore di N. Cosa succederebbe infatti se ilprogramma venisse usato senza tenere conto della limitazione su N, ad es-empio per fare le medie per un corso di laurea dove sono previsti 20 esa-mi? E facile immaginare che si creerebbe una situazione anomala perchein fase di esecuzione il programma si troverebbe ad operare con elementidi V con indice maggiore di 15, laddove dalla dichiarazione risulta che gliindici per V possono andare da 1 a 15 (in gergo, staremmo usando indiciout-of-bounds). All’atto pratico questo significherebbe fare riferimento connomi V(16), V(17), etc.. a locazioni di memoria che il compilatore non haallocato per il vettore V. La gestione di queste situazioni varia da macchinaa macchina. Dal punto di vista teorico sarebbe possibile per qualunque com-pilatore inserire nel programma oggetto un controllo sugli indici usati neiriferimenti a elementi di arrays, con la possibilita di bloccare l’esecuzione incaso di indici fuori dai limiti. Ma questo controllo renderebbe l’esecuzionedel programma molto lenta, e pertanto nessun compilatore lo prevede, sal-vo in alcuni casi prevedere un’opzione per attivarlo9. In assenza di questocontrollo, il programma “fa finta di niente” e va alla locazione di memoriacitata nel riferimento come se effettivamente questa facesse parte dell’array.Per esempio, nel programma precedente il riferimento a V(16) porterebbe ad

9L’opzione per il compilatore gfortran e –fbounds–check, e puo essere molto utile infase di messa a punto dei programmi. Se in un programma e presente un vettore Xdi lunghezza 3, e si fa riferimento all’elemento X(4), il programma viene fermato con ilseguente messaggio di errore: “At line ... of file ... Fortran runtime error: Array referenceout of bounds for array ’x’, upper bound of dimension 1 exceeded (4 > 3)”.

21

Page 26: Appunti di FORTRAN 77

agire sulla locazione di memoria consecutiva a quella riservata all’elementoV(15), senza tener conto del fatto che essa non e riservata al vettore V. Leconseguenze di questo modo di procedere sono diverse a seconda dell’uso chela macchina sta facendo della locazione abusivamente occupata e di quelloche ne fa il programma. Spesso succede una delle tre cose seguenti:

– la locazione e inutilizzata ⇒ il programma va avanti e da risultati corretti,come se niente di strano fosse accaduto;

– la locazione e riservata a un’altra variabile usata nel programma stesso ⇒il programma va avanti, ma da sicuramente risultati sbagliati 10;

– la locazione e riservata a software diverso dal programma e protetta ⇒l’esecuzione del programma viene bloccata, con una segnalazione di erroredel tipo segmentation fault.

7 Espressioni e istruzione di assegnazione

Un’istruzione di assegnazione ha la forma generale

v = e (2) istr_ass

dove v e un nome di variabile o di un elemento di array e e e un’espressione.A seconda della natura delle grandezze coinvolte, si parla di assegnazionenumerica, logica o carattere. Noi ci occuperemo soltanto del caso numeri-co. Piu in particolare, ci concentreremo su istruzioni di assegnazione checoinvolgono costanti e variabili intere, reali e doppia precisione; per il casocomplesso rimandiamo ai testi in biliografia.

7.1 Espressioni aritmetiche

Cominciamo con lo specificare come si costruiscono le espressioni aritmetichee come ne viene calcolato il valore. Le espressioni aritmetiche si formanolegando fra loro costanti o variabili di tipo numerico tramite operatori arit-metici (per variabili, da qui in avanti intendiamo anche elementi di arrays).Gli operatori aritmetici sono i seguenti:

+ addizione- sottrazione∗ moltiplicazione/ divisione∗∗ elevamento a potenza

10Questa situazione puo rivelarsi particolarmente tragica quando il valore contenutonella locazione usata “abusivamente” viene cambiato: in questo caso infatti viene di fattocambiato, a nostra insaputa, il valore della variabile memorizzata in quella locazione.

22

Page 27: Appunti di FORTRAN 77

Se necessario, si possono usare parentesi tonde e riferimenti a funzioni in-trinseche del FORTRAN. Un elenco completo di queste funzioni e reperibilein

AGM[1]; qui riportiamo alcune delle piu comunemente usate:

ABS I,R,Dp valore assolutoSQRT R,Dp radice quadrataEXP R,Dp esponenzialeLOG, LOG10 R,Dp logaritmo naturale e logaritmo in base 10SIN, COS, TAN R,Dp seno, coseno e tangenteASIN, ACOS, ATAN R,Dp arcoseno, arcocoseno e arcotangenteSINH, COSH, TANH R,Dp seno , coseno e tangente iperboliciMAX, MIN I, R,Dp massimo e minimo fra due o piu valori

Nella colonna centrale indichiamo i tipi di argomenti che le funzioni ac-cettano; il risultato e dello stesso tipo dell’argomento (o degli argomenti nelcaso di MIN e MAX). Esempi di espressioni valide sono i seguenti:

X+Y x + y1.25∗SQRT(X) 1.25

√x

(1.+X(I))/(3∗M) 1+xi

3m

ABS(B∗∗2-4∗A∗C) |b2 − 4ac|COS(A+B) cos(a + b)EXP(–0.1∗X) e−0.1x

2.∗SIN(X)∗∗2 2sin2(x)MAX(A(1,1),B,2.∗X–1.)∗∗(–2) max(a11, b, 2x − 1)−2

Per quanto riguarda l’ordine in cui le operazioni vengono eseguite, valgonole regole standard dell’aritmetica.

L’esecuzione di un’operazione elementare (addizione, sottrazione, molti-plicazione e divisione) richiede che gli operandi siano dello stesso tipo. Ilrisultato e anch’esso dello stesso tipo. Consideriamo ad esempio l’espres-sione N2∗N1; se N1 e N2 sono variabili intere, il risultato e intero e vienememorizzato secondo le regole di memorizzazione dei numeri interi, mentrese le due variabili sono reali il risultato viene memorizzato in forma float-ing point normalizzata. Cosı, se i valori di N1 e N2 fossero dell’ordine di106 e 107 rispettivamente, la memorizzazione del risultato provocherebbe unoverflow nel primo caso (su una macchina a 32 bits), ma non nel secondo.

A proposito di operazioni fra numeri interi, e importante sottolineareche la divisione fra interi da come risultato il quoziente fra i due numeri,nell’accezione del termine usata alle scuole elementari. Cosı il risultato del-l’espressione 3/4 e 0 e, se N e una variabile intera, il valore di N/2∗2 e ugualea N se e solo se il valore di N e pari.

A dispetto del fatto che un’operazione avviene sempre fra operandi dellostesso tipo, il FORTRAN consente di scrivere espressioni miste, in cui com-

23

Page 28: Appunti di FORTRAN 77

paiono operazioni fra operandi di tipo diverso. In questo caso la macchinaopera una conversione implicita di uno dei due operandi da un tipo all’altro,in modo da poter fare l’operazione fra numeri con la stessa rappresentazione.Piu precisamente, l’operando di tipo piu “debole” viene convertito al tipopiu “forte”, secondo la gerarchia seguente:

1) Intero piu debole2) Reale ↓3) Doppia precisione piu forte

Abbiamo usato l’espressione “conversione implicita” perche la conversioneavviene a livello di registri aritmetici, senza cambiare il tipo dell’operando.La conversione da intero a reale consiste nel trasformare il valore intero inun numero equivalente in rappresentazione floating point; la conversione dareale a doppia precisione consiste invece nel cambiare la rappresentazionedel numero da floating point precisione semplice a floating point doppiaprecisione (le cifre in piu di mantissa vengono tipicamente poste uguali azero).

Data un’espressione mista, si definisce tipo dell’espressione il tipo delrisultato, che coincide con il tipo piu forte presente nell’espressione stessa.Consideriamo alcuni esempi.

Sia R una variabile reale; allora 2+R e un’espressione mista reale e lamacchina esegue l’addizione convertendo il dato intero 2 a tipo reale, inmodo da calcolare la somma fra due numeri floating point. Il risultato ot-tenuto e un valore reale. Si potrebbe evitare il costo (in termini di tempodi esecuzione) della conversione, scrivendo l’espressione nella forma 2.0+R,dove la costante e in forma reale. Se R fosse una variabile in doppia preci-sione, il calcolo di 2+R richiederebbe una doppia conversione, da intero areale e poi da reale a doppia precisione; tutto questo viene evitato scrivendol’espressione nella forma 2.D0+R.

Se I e J sono due variabili intere con valori ≥ 1, l’espressione 1/(I+J)da come risultato il numero intero zero, perche viene eseguita in aritmeticaintera, mentre l’espressione mista 1.0/(I+J) viene calcolata in aritmeticareale e da pertanto un risultato reale diverso da zero.

Talvolta, i programmatori preferiscono evitare espressioni miste usandole funzioni intrinseche di conversione, di cui riportiamo qui sotto l’elenco:

INT I,R,Dp Conversione a intero per troncamentoNINT I,R,Dp Conversione a intero per arrotondamentoREAL I,R,Dp Conversione a realeDBLE I,R,Dp conversione a doppia precisione

Ad esempio, l’espressione 1.0/REAL(I+J) e un’alternativa a 1.0/(I+J) incui la conversione e esplicitata.

24

Page 29: Appunti di FORTRAN 77

7.2 Assegnazione aritmetica

Possiamo ora tornare a considerare l’istruzione di assegnazione (istr_ass2). L’ese-

cuzione avviene in due fasi:

1) Viene valutata l’espressione e;

2) Il risultato ottenuto valutando e viene memorizzato in v.

Se v e e hanno lo stesso tipo, non c’e altro da dire. In caso contrario,l’istruzione e un’assegnazione mista e la seconda fase coinvolge una con-versione del risultato ottenuto nella prima fase al tipo di v. E importantesottolineare che il tipo di v non influenza in alcun modo il calcolo del valoredi e, e che la conversione suddetta avviene solo dopo che questo valore e sta-to calcolato. Se v e di un tipo piu forte di e, la conversione avviene secondole regole viste prima. D’altra parte, puo succedere che v sia di un tipo piudebole di e, nel qual caso e coinvolta una conversione da un tipo piu fortea uno piu debole. Consideriamo al solito alcuni esempi, supponendo che Nsia una variabile intera, A1 e A2 siano variabili reali, e D1 sia una variabiledoppia precisione.

Nell’istruzione A1=A2+EXP(D1) il risultato dell’espressione e doppiaprecisione e A1 e invece reale; pertanto il risultato dell’espressione viene con-vertito da formato floating point doppia precisione a formato floating pointsemplice precisione: la mantissa viene accorciata (per troncamento o arro-tondamento) e la caratteristica viene memorizzata su un numero inferioredi bits.

Nell’istruzione N=A1∗A2, l’espressione e reale e la variabile N e intera;la conversione da reale a intero consiste nella memorizzazione della parteintera nella locazione destinata a N.

In entrambi questi esempi c’e rischio di overflow nella fase di conversione:nel primo caso la caratteristica potrebbe non rientrare nel range accettabileper la precisione semplice, e nel secondo caso la parte intera del valoredell’espressione potrebbe superare la soglia di overflow degli interi.

7.3 Fortran 90: operazioni fra arrays

A differenza del FORTRAN 77, secondo il quale le espressioni aritmetichee le istruzioni di assegnazione agiscono esclusivamente su grandezze scalari,il Fortran 90 consente di eseguire operazioni aritmetiche e assegnazioni fraarrays o porzioni di arrays. Queste operazioni sono sempre intese comeoperazioni elemento a elemento, e non esistono operatori corrispondenti alprodotto matriciale righe per colonne. Inoltre, lo standard non specifical’ordine in cui le operazioni scalari fra gli elementi coinvolti devono essereeseguite, lasciando la decisione al compilatore che puo creare un programmaoggetto efficiente sfruttando eventualmente la particolare architettura (vet-toriale e/o parallela) della macchina per cui e progettato. Senza entrare nei

25

Page 30: Appunti di FORTRAN 77

dettagli, facciamo alcuni esempi. Supponendo che A e B siano due matricireali 20×20 e V un vettore reale di lunghezza 10, le seguenti sono espressionivalide in Fortran 90 (il risultato di ciascuna di esse e descritto accanto):

A∗B matrice 20× 20 con elementiA(I,J)∗B(I,J) , per I=1,. . .,20 e J=1,. . .,20

3.∗V+1. vettore di lunghezza 10 con elementi3.∗V(I)+1. , per I=1,. . .,10

0.1/V+A(1:10,1) vettore di lunghezza 10 con elementi0.1/V(I)+A(I,1) , per I=1,. . .,10

ABS(V(2:8)) vettore di lunghezza 7 con elementiABS(V(I)) , per I=2,. . .,8

e le seguenti sono istruzioni di assegnazione aritmetica fra array valide:

A=A+2. poni A(I,J) uguale a A(I,J)+2.per I=1,. . .,20 e J=1,. . .,20

B(1:10,J) =V poni B(I,J) uguale a V(I)per I=1,. . .,10

V(2:5)=V(1:4) poni V(I) uguale a V(I-1)per I=2,. . .,5

A(1,11:20)=SQRT(V) poni A(I,J) uguale a SQRT(V(J-10))per J=11,. . .,20

8 Controllo del flusso di esecuzione

L’esecuzione di un’unita di programma avviene sequenzialmente a partiredalla prima istruzione eseguibile fino a che non viene incontrata un’istruzionedi blocco dell’esecuzione (STOP o, come vedremo piu avanti, RETURN) ola END. D’altra parte molti algoritmi prevedono costrutti di scelta o diripetizione che intervengono sul flusso di esecuzione rendendolo da un cer-to punto di vista non piu sequenziale. Abbiamo gia visto nei programmiERONE e MEDIE (paragrafo

realizza5 e

arrays6.5, rispettivamente) alcuni esempi di

queste situazioni realizzati direttamente in FORTRAN. Torniamo ora sulleistruzioni usate in quei programmi per definirne la sintassi.

26

Page 31: Appunti di FORTRAN 77

8.1 Istruzione GO TO

L’istruzione GO TO e chiamata istruzione di salto incondizionato e ha laforma

GO TO l

dove GO TO (con o senza lo spazio fra le due parole) e la parola chiave el e l’etichetta di un’istruzione eseguibile nella stessa unita di programma.L’effetto e di far saltare l’esecuzione all’istruzione di etichetta l, da cui poiil flusso riprende sequenzialmente.

E un’istruzione da usarsi con moderazione, perche un suo uso eccessivopuo rendere il flusso dell’algoritmo cosı contorto da risultare praticamenteincomprensibile11. Come abbiamo a suo tempo osservato, nei due program-mi campione ERONE e MEDIE abbiamo usato le istruzioni GO TO insiemea istruzioni di scelta IF per simulare un ciclo while, costrutto inesistente inFORTRAN 77. D’altra parte, nella maggior parte dei linguaggi di program-mazione, compreso il Fortran 90, c’e la possibilita di tradurre esplicitamentequesto costrutto, e in linea di principio si puo riuscire a scrivere qualunquealgoritmo senza bisogno di ricorrere a salti incondizionati. Cio nonostante,un’istruzione analoga al GO TO e presente in tutti i linguaggi maggiormenteusati12 perche in molte situazioni ricorrervi e un modo per semplificarsi lavita.

8.2 Istruzioni IF

Le istruzioni IF sono tutte le istruzioni di scelta, in cui si controlla se unao piu condizioni sono verificate e in base all’esito del controllo si dirige ilflusso dell’esecuzione per una strada o un’altra. Le condizioni da verificaresono espresse tramite espressioni relazionali o, piu in generale, espressionilogiche.

Un’espressione relazionale e costituita da due espressioni aritmetichelegate da un operatore di relazione (< > ≤ ≥ = 6=). Questi opera-tori sono descritti in FORTRAN 77 mediante acronimi preceduti e seguitida un punto, come descritto nella tabella sottostante:

simbolo matematico FORTRAN 77 Fortran 90< .LT. <> .GT. >≤ .LE. <=≥ .GE. >== .EQ. ==6= .NE. /=

11In passato fu coniato il termine dispregiativo spaghetti code, ovvero programma

spaghetti per indicare un programma con tante istruzioni GO TO da renderne il flussointrecciato e indistricabile come un piatto di spaghetti.

12Per quanto a nostra conoscenza, solo il MATLAB non la prevede.

27

Page 32: Appunti di FORTRAN 77

Il Fortran 90 ha introdotto la possibilita di sostituire gli acronimi con simbolimatematici, e questa convenzione e riconosciuta da molti compilatori oggiin uso. Alcuni esempi di espressioni relazionali sono i seguenti:

A(1)+B(1).LT.0. a1+b1<0B∗∗2 .LE. 4∗A∗C b2 ≤ 4acN.EQ.M+1 n=m+1X.NE.SQRT(Y) x 6= √yABS(X–Y).GE. 1E–6 |x-y| ≥ 10−6

Per descrivere una condizione puo talvolta essere necessario usare anche glioperatori logici AND, OR e NOT, nel qual caso la condizione e formal-izzata come un’espressione logica. Gli operatori logici in FORTRAN sono.AND., .OR. e .NOT. Senza entrare nei dettagli della valutazione del risulta-to di un’espressione logica, riportiamo alcuni esempi qui sotto; nella colonna“oppure...” scriviamo l’espressione con delle parentesi che ne migliorano laleggibilita, pur non essendo richieste dal linguaggio:

Condizione Traduzione FORTRAN oppure...

0 ≤ i ≤ 10 0.LE.I.AND. I.LE.10 (0.LE.I).AND.(I.LE.10)x < 1 o x>3.14 X.LT.1.0.OR.X.GT.3.14 (X.LT.1.0).OR.(X.GT.3.14)j 6= n,m J .NE.N.AND.J.NE.M (J .NE.N).AND.(J.NE.M)

8.2.1 IF logicoiflogico

La forma piu semplice di istruzione IF e il cosiddetto IF logico, che ha laforma

IF(condizione) istruzione eseguibile

e funziona nel seguente modo: se la condizione e vera si esegue l’istruzionespecificata, altrimenti questa istruzione viene ignorata e l’esecuzione del pro-gramma procede con l’istruzione che segue l’IF. Esempi di IF logico sono iseguenti:

IF(X.NE.0.)P=P∗XIF(ABS(A-B).LT.1.E-3)STOP

IF(X(I).GT.AMAX)AMAX=X(I)

IF(N.GE.MM)PRINT∗,’Attenzione’

8.2.2 IF–THEN–ENDIF.

L’evoluzione naturale dell’IF logico e l’istruzione IF–THEN–ENDIF, tramitela quale si puo saltare un intero blocco di istruzioni nel caso che la condizionespecificata non sia vera. La forma dell’istruzione e la seguente:

28

Page 33: Appunti di FORTRAN 77

IF(condizione) THENIstruzione 1Istruzione 2

...

blocco THEN

END IF

dove e obbligatorio andare a capo dopo la frase IF(condizione)THEN e scri-vere su una riga a se stante la frase di chiusura END IF (che puo essere scrittacon o senza lo spazio fra le due parole). Se la condizione e vera, il program-ma esegue le istruzioni comprese fra l’istruzione IF e l’istruzione END IF,che tutte insieme formano il cosiddetto blocco THEN; altrimenti, il bloccoTHEN viene saltato. In ogni caso, l’esecuzione prosegue dall’istruzione chesegue END IF. Ad esempio con le istruzioni seguenti

IF(I/2∗I.EQ.I)THENX(I)= X(I)+1A(I,I)= A(I,I)+I

END IFI=I+1

si modificano l’elemento X(I) del vettore X e l’elemento diagonale A(I,I)della matrice A se l’indice I e pari; se I e dispari, gli elementi suddetti nonvengono modificati. In entrambi i casi, si prosegue incrementando di 1 ilvalori di I.

Consideriamo ora il seguente programma ERONE2.

PROGRAM ERONE2IMPLICIT DOUBLE PRECISION (A-H,O-Z)NT=0

10 PRINT∗, ’immettere le lunghezze dei lati’READ∗, A,B,CIF((A.GT.0.).AND.(B.GT.0.).AND.(C.GT.0.))THEN

SP=(A+B+C)/2.Q=SP∗(SP-A)∗(SP-B)∗(SP-C)IF(Q.GT.0.)THEN

AREA=SQRT(Q)PRINT∗,’area= ’, AREANT=NT+1

END IFEND IFPRINT∗,’ancora? (1/0= si/no)’READ∗,LEGGIIF(LEGGI.EQ.1) GOTO 10PRINT∗,’Numero totale di triangoli: ’,NTEND

Si tratta di una modifica del programma ERONE del paragraforealizza5, ottenuta

29

Page 34: Appunti di FORTRAN 77

inserendo dei controlli per verificare che i dati a, b, c rappresentino effettiva-mente le lunghezze dei lati di un triangolo. Piu precisamente, se uno dei tredati non e positivo, ovviamente non si tratta di lunghezze e il programmasalta all’istruzione PRINT∗,’ancora? (1/0= si/no)’ per leggere eventual-mente una nuova terna di dati. Se i dati sono tutti positivi, puo ancorasuccedere che non rappresentino i lati di un triangolo (basti pensare allaterna di valori 1,3, e 5); di questo ci rendiamo conto dopo aver calcolatoq = s(s − a)(s − b)(s − c). Se infatti q non e positivo, deduciamo che nonesiste un triangolo che possa avere i lati lunghi a, b e c, e si procede di nuovoall’eventuale lettura di nuovi dati; altrimenti, possiamo calcolare e stamparel’area. Tramite la variabile NT, il programma conta i triangoli di cui e statacalcolata l’area.

Il programma contiene un IF–THEN–ENDIF dentro l’altro (o, comesi dice, annidati). Il blocco THEN dell’IF piu esterno va dall’istruzioneSP=(A+B+C)/2. al primo END IF compreso; quello dell’IF piu interno ecostituito dalle tre istruzioni

AREA=SQRT(Q)PRINT∗,’area= ’, AREANT=NT+1

Nello scrivere il programma non abbiamo fatto iniziare tutte le istruzioninello stesso punto della riga, sfruttando la regola che impone di scrivere leistruzioni a partire dalla colonna 7 (e fino alla 72), ma non impedisce di in-iziare a scriverle a una colonna successiva alla 7. Usare la cosiddetta inden-tazione (dall’inglese indentation), ovvero scrivere i blocchi THEN spostati adestra di qualche carattere rispetto all’istruzione iniziale IF(condizione)THENe a quella finale END IF, e una buona abitudine perche rende molto piu leg-gibili i programmi. Pur senza farlo notare, abbiamo gia usato l’indentazionein precedenza, e la useremo d’ora in avanti intensivamente13.

8.2.3 IF–THEN–ELSE–ENDIFELSE

Una situazione che spesso si presenta negli algoritmi e la scelta fra due bloc-chi di istruzioni alternative in base al verificarsi o meno di una data con-dizione. Per tradurre in FORTRAN queste scelte si deve usare l’istruzioneIF–THEN–ELSE–ENDIF, la cui forma generale e:

13L’utilita dell’indentazione e tale che molti editori di testo moderni usati in ambientidi sviluppo integrati (come OPEN Watcom) forniscono una funzione di indentazioneautomatica, che spesso viene applicata per default durante la scrittura dei programmi.

30

Page 35: Appunti di FORTRAN 77

IF(condizione) THENIstruzione 1Istruzione 2

...

blocco THEN

ELSEIstruzione 1Istruzione 2

...

blocco ELSE

END IF

Se la condizione e vera vengono eseguite le istruzioni del blocco THEN,altrimenti quelle del blocco ELSE; in entrambi i casi l’esecuzione proseguecon la prima istruzione dopo END IF. Usando questa istruzione, l’algoritmo

Se m > n, allora:max = m

altrimenti:max = n

Fine scelta

viene tradotto nel modo seguente:

IF(M.GT.N)THENMAX=M

ELSEMAX=N

END IF

Usando l’istruzione IF–THEN–ELSE–ENDIF, possiamo inserire delleistruzioni di stampa nel programma ERONE2 che avvertono se una ternadi dati non corrisponde ad un triangolo.

PROGRAM ERONE3IMPLICIT DOUBLE PRECISION (A-H,O-Z)NT=0

10 PRINT∗, ’immettere le lunghezze dei lati’READ∗, A,B,CIF((A.GT.0.).AND.(B.GT.0.).AND.(C.GT.0.))THEN

SP=(A+B+C)/2.Q=SP∗(SP-A)∗(SP-B)∗(SP-C)IF(Q.GT.0.)THEN

AREA=SQRT(Q)PRINT∗,’area= ’, AREANT=NT+1

ELSEPRINT∗,’Dati non corrispondenti a un triangolo’

END IF

31

Page 36: Appunti di FORTRAN 77

ELSEPRINT∗,’Dati non corrispondenti a un triangolo’

END IFPRINT∗,’ancora? (1/0= si/no)’READ∗,LEGGIIF(LEGGI.EQ.1) GOTO 10PRINT∗,’Numero totale di triangoli: ’,NTEND

8.2.4 IF concatenati.

Supponiamo di dover realizzare in FORTRAN una situazione in cui ci sonopiu di due possibili strade da percorrere, e la scelta dipende da piu condizioniche si escludono a vicenda, come per esempio nel calcolo della funzione

f(a) =

a2 per a < 0a(a− 1) per 0 ≤ a ≤ 1a + 10−3 per a > 1

Per effettuare questo calcolo si puo arricchire l’istruzione IF–THEN–ELSE–ENDIF con la clausola ELSE IF, ottenendo un costrutto in cui una serie di IFdipendenti da condizioni diverse e mutuamente esclusive sono concatenati.La sintassi di quella che rappresenta l’istruzione di scelta piu complessa delFORTRAN e la seguente:

IF(condizione 1) THENIstruzione 1Istruzione 2

...

blocco 1

ELSE IF(condizione 2)THENIstruzione 1Istruzione 2

...

blocco 2

· · · · · · · · ·ELSE IF(condizione n)THEN

Istruzione 1Istruzione 2

...

blocco n

ELSEIstruzione 1Istruzione 2

...

blocco n + 1 ≡ blocco ELSE

END IF

32

Page 37: Appunti di FORTRAN 77

Se la condizione 1 e verificata, si eseguono le istruzioni del blocco 1; altri-menti si va a controllare se la condizione 2 e verificata; in caso positivo sieseguono le istruzioni del blocco 2 e in caso negativo si va a controllare lacondizione 3, e cosı via: se nessuna delle n condizioni e verificata, si vannoad eseguire le istruzioni del blocco ELSE. In ogni caso viene eseguito uno eun solo blocco di istruzioni, dopo di che l’esecuzione procede con l’istruzioneche segue ENDIF. Non esiste limite al numero di clausole ELSEIF che sipossono concatenare; inoltre il blocco ELSE e opzionale e puo non essercinel caso che le n condizioni prevedano gia tutti i possibili casi.

Il calcolo della funzione f(a) puo quindi essere tradotto in FORTRANnel seguente modo:

IF(A.LT.0.) THENF=A∗∗2

ELSE IF(A.LE.1.)THENF=A∗(A–1.)

ELSEF=A+1.E–3

END IF

Osserviamo che nell’istruzione ELSEIF controlliamo soltanto se a ≤ 1 e nonse 0 ≤ a ≤ 1 come scritto nella definizione della funzione; questo e dovutoal fatto che la condizione dell’ELSEIF viene controllata soltanto se la primacondizione (a < 0) non e verificata, ovvero se a ≥ 0.

Un costrutto di IF concatenati rappresenta dal punto di vista del compi-latore un’unica istruzione IF e quindi e prevista una sola istruzione ENDIFdi chiusura. Diversa e la situazione se gli IF sono annidati, nel qual casoognuno di essi deve avere la sua ENDIF. Osserviamo come il calcolo di f(a)cambia se non usiamo la clausola ELSE IF, ma ricorriamo a IF annidati:

IF(A.LT.0.) THENF=A∗∗2

ELSEIF(A.LE.1.)THEN

Y=A∗(A–1.)ELSE

Y=A+1.E–3END IF

END IF

N. B. Il passaggio da IF concatenati a IF annidati e stato effettuato sem-plicemente andando a capo dopo il primo ELSE!!

33

Page 38: Appunti di FORTRAN 77

8.3 Fortran 90: istruzione SELECT CASE.

Le istruzioni di scelta previste dal FORTRAN 77 sono tutte e sole quelle de-scritte finora. Vogliamo in questo paragrafo accennare a un’altra istruzionedi scelta introdotta dal Fortran 90, che puo offrire talvolta una valida alter-nativa agli IF concatenati, quando la scelta dipende dal valore assunto daun’espressione (intera, logica o carattere). Si tratta dell’istruzione SELECT,la cui forma generale e la seguente:

SELECT CASE(espressione)CASE(caso 1)

Istruzione 1Istruzione 2

...

blocco 1

· · · · · · · · ·CASE(caso n)THEN

Istruzione 1Istruzione 2

...

blocco n

CASE DEFAULTIstruzione 1Istruzione 2

...

blocco DEFAULT

END SELECT

In ogni clausola CASE si specifica un possibile insieme di valori che l’espres-sione puo assumere: se l’espressione assume un valore che rientra nell’i-esimocaso, vengono eseguite le istruzioni del blocco i; se invece il valore non ri-entra in nessuno dei casi previsti, vengono eseguite le istruzioni del bloccoDEFAULT. Ovviamente, i casi specificati devono essere mutuamente esclu-sivi come negli IF concatenati e, se essi esauriscono i possibili valori, il bloccoDEFAULT e vuoto e puo essere omesso. Ci sono diversi possibili modi perspecificare un caso. Supponendo ad esempio che l’espressione sia intera,diamo sotto alcuni descrittori di casi con il corrispondente significato:

CASE(1) valore uguale a 1CASE(1,3,5) valore uguale a 1, 3 o 5CASE(:-4) valore minore o uguale di -4CASE(0:) valore maggiore o uguale di 0CASE(10:100) valore compreso fra 10 e 100, estremi inclusi

8.4 Istruzione DO

Nel programma MEDIE del paragrafoarrays6.5 abbiamo usato l’istruzione DO

per realizzare un ciclo, ovvero una struttura ripetitiva nella quale una o piu

34

Page 39: Appunti di FORTRAN 77

istruzioni devono essere eseguite piu volte. Ricordiamo che dal punto divista algoritmico i cicli possono essere di diversi tipi. I primi sono quelli incui il numero di ripetizioni e stabilito a priori e l’esecuzione e controllatada un contatore delle ripetizioni. I secondi sono quelli in cui non si conoscea priori il numero di ripetizioni e l’inizio e fine sono controllati tramite ilverificarsi o meno di una determinata condizione; questi sono a loro voltasuddivisi in due tipi: i cicli while in cui le ripetizioni continuano fintanto chela condizione specificata e vera e i cicli repeat in cui le ripetizioni continu-ano fintanto che la condizione specificata e falsa. Come gia abbiamo avutomodo di osservare, il FORTRAN 77 non prevede un’istruzione che realizzai cicli while; aggiungiamo ora che non e prevista neanche un’istruzione cherealizza i cicli repeat. In sostanza, e prevista soltanto l’istruzione DO, checorrisponde ai cicli del primo tipo. I cicli while e repeat possono essere sim-ulati usando istruzioni IF e GO TO, come abbiamo fatto nel programmaERONE.

Un ciclo DO in FORTRAN 77 ha la forma seguente:

DO n v = e1, e2, e3

Istruzione 1Istruzione 2

...

rango del DO

n CONTINUE

dove:– n e un’etichetta che fa riferimento all’istruzione n CONTINUE, dettaistruzione finale del DO;

– v e una variabile scalare, detta variabile del DO;

– e1, e2 e e3 sono espressioni il cui valore rappresenta il valore iniziale chev deve assumere, il valore finale e l’incremento (o decremento), rispettiva-mente. Se e3 e uguale a 1, puo essere omessa.

Il Fortran 90 ha introdotto una forma leggermente diversa dell’istruzioneDO, nella quale non si deve scegliere un’etichetta per l’istruzione finale;questa forma e

DO v = e1, e2, e3

Istruzione 1Istruzione 2

...

rango del DO

END DO

ed e ormai accettata da molti compilatori.

L’istruzione finale. La parola chiave CONTINUE nell’istruzione finalenon produce alcuna azione particolare, ma dice semplicemente al programma

35

Page 40: Appunti di FORTRAN 77

di “continuare” con quello che sta facendo. Il FORTRAN 77 prevede lapossibilita di chiudere un DO con istruzioni diverse da una CONTINUE(in ogni caso etichettate con l’etichetta n). D’altra parte, ormai e prassiconsolidata usare questa istruzione, tanto che l’uso di istruzioni finali diverseda CONTINUE e END DO e stato dichiarato obsoleto dagli estensori dellostandard Fortran 95, il che lo pone fra le caratteristiche del linguaggio daeliminare in future versioni.

La variabile del DO. Per quanto riguarda la variabile v, lo standard delFORTRAN 77 dice che v, e di conseguenza anche e1, e2 e e3, possono essereintere, reali o doppia precisione. In realta, ogni buon programmatore usasoltanto variabili intere perche la gestione di un DO con variabile reale odoppia precisione puo creare problemi a causa degli errori di arrotondamen-to. Questo e talmente vero che in Fortran 90 la variabile del DO puo esseresoltanto intera, e la possibilita di usare variabili reali o doppia precisione estata dichiarata obsoleta. D’ora in poi daremo quindi per scontato che v,e1, e2 e e3 sono intere.

Il rango del DO. Il rango di un DO puo contenere qualsiasi istruzioneFORTRAN, compresi altri cicli DO (si parla in questo caso di cicli DOannidati). A questo proposito, il FORTRAN impone due regole, entrambeovvie: DO annidati devono dipendere da variabili diverse e i loro ranghi nonsi devono intersecare. E ad esempio sbagliata una sequenza del tipo:

DO 50 J=1,N1...

DO 20 K=1,K2...

50 CONTINUE...

20 CONTINUE

Allo stesso modo, il rango di un DO puo contenere un costrutto IF (e,viceversa, un IF puo contenere un ciclo DO); non e pero possibile che i duecostrutti si intersechino, come nelle situazioni tratteggiate qui sotto:

IF(condizione)THEN DO 20 L=L1,1,-1...

...DO 20 K=1,K2 IF(condizione)THEN

......

ENDIF 20 CONTINUE...

...20 CONTINUE ENDIF

36

Page 41: Appunti di FORTRAN 77

I seguenti due esempi realizzano il calcolo del vettore y = Ax, dove xe un vettore di n componenti e A e una matrice n × n; nella sequenza diistruzioni di sinistra si usa una variabile ausiliaria s per accumulare la som-matoria

∑nj=1 aijxj , mentre in quella di destra si accumula la sommatoria

direttamente in yi:

DO 100 I=1,NS=0.DO 50 J=1,N

S=S+A(I,J)∗X(J)50 CONTINUE

Y(I)=S100 CONTINUE

DO 100 I=1,NY(I)=0.DO 50 J=1,N

Y(I)=Y(I)+A(I,J)∗X(J)50 CONTINUE100 CONTINUE

Nel secondo caso, i ranghi dei due DO finiscono nello stesso punto; in questasituazione si puo usare una sola istruzione finale senza che l’esecuzione cambirispetto alla versione con due diverse istruzioni finali:

DO 100 I=1,NY(I)=0.DO 100 J=1,N

Y(I)=Y(I)+A(I,J)∗X(J)100 CONTINUE

Consideriamo ora la seguente sequenza di istruzioni, nella quale si legge uncerto numero (≤ 100) di dati reali e per ognuno di essi si calcola e stampail logaritmo naturale del suo valore assoluto; le ripetizioni si interromponoprima di aver letto 100 dati, se viene immesso un dato uguale a 0.

DO 45 I=1,100PRINT∗,’Immetti il prossimo dato (0 per interrompere)READ∗,DATOIF(DATO.EQ.0.)GO TO 58Y=LOG(ABS(DATO))PRINT∗,Y

45 CONTINUE58 CONTINUE

Tramite l’istruzione GOTO 58 si esce dal rango del DO, di fatto fermandonel’esecuzione prima che le ripetizioni previste siano esaurite. Cio e perfetta-mente lecito, mentre non e lecito il contrario, cioe entrare con un GOTOdentro il rango di un DO.

Esecuzione di un ciclo DO. L’esecuzione di un ciclo DO prevede leseguenti fasi:

– Vengono calcolati i valori di e1, e2 e e3;

37

Page 42: Appunti di FORTRAN 77

– Viene calcolato il numero r di ripetizioni previste dal DO, dato da

r = max

(

0,e2 − e1 + e3

e3

)

e inizializzato a r il contatore delle ripetizioni;

– se r e zero, il ciclo DO viene saltato, senza alcuna segnalazione.

– Se r 6= 0, le istruzioni che compongono il rango del DO vengono ripetuter volte attribuendo a v i valori e1, e1 + e3, .... Diamo alcuni esempi diistruzioni DO con e1, e2 e e3 costanti, evidenziando il valore di r e i valoriassunti da v:

DO 10 I=1,10 r = 10 v = 1, 2, . . . , 10DO 10 I=1,10,2 r = 5 v = 1, 3, 5, 7, 9DO 10 K=3,0 r = 0DO 10 K=10,1,-1 r = 10 v = 10, 9, . . . , 1DO 10 J=16,0,-2 r = 9 v = 16, 14, . . . , 0

Ad ogni ripetizione, ogni volta che viene incrementato il valore di v, vieneanche decrementato di un’unita il contatore delle ripetizioni. Il controllo delcontatore e realizzato in modo tale che, in uscita dal DO, la variabile v nonha l’ultimo valore consentito, bensı quello successivo. Per esempio, dopol’esecuzione del seguente segmento di programma

N=0DO 110 I=1,10

J=IDO 100 K=2,5,2

L=KN=N+1

100 CONTINUE110 CONTINUE

i valori delle variabili coinvolte sono: I=11, J=10, K=6, L=4, N=20.

8.5 DO impliciti

Quando nei programmi dei paragrafi precedenti abbiamo avuto bisogno dileggere o scrivere gli elementi di un vettore, abbiamo usato scritture del tipo

(X(I), I=1,N)

all’interno delle istruzioni READ∗ e PRINT∗, intendendo con cio: “leggio scrivi i valori di X(I) per I che va da 1 a N”. La suddetta scrittura echiamata DO implicito. Come i cicli DO, cosı anche i DO impliciti possonoessere annidati, come si fa abitualmente quando si devono leggere o stamparegli elementi di una matrice; in questi casi si puo usare infatti la scrittura

((A(I,J), I=1,N), J=1,N)

38

Page 43: Appunti di FORTRAN 77

che consiste in due DO impliciti annidati. Il DO implicito piu esterno fariferimento alla variabile J, che rappresenta l’indice di colonna dell’elementoA(I,J), mentre il DO implicito piu interno fa riferimento all’indice di riga I.Se idealmente “srotoliamo” i DO, vediamo che gli elementi della matrice Avengono presi in considerazione nell’ordine seguente:

Si pone J=1 e si varia I da 1 a N: A(1,1) A(2,1) . . . A(N,1)Si pone J=2 e si varia I da 1 a N: A(1,2) A(2,2) . . . A(N,2)

...Si pone J=N e si varia I da 1 a N: A(1,N) A(2,N) . . . A(N,N)

In breve, la matrice viene letta o scritta per colonne: prima tutta la colonna1, poi tutta la colonna 2, e via dicendo fino alla colonna N. Se si vuoleleggere o scrivere la matrice per righe, si deve usare una scrittura diversa,ad esempio

((A(I,J), J=1,N), I=1,N) oppure ((A(J,I), I=1,N), J=1,N)

8.6 Fortran 90: DO illimitato e DO WHILE

Il Fortran 90 ha introdotto due forme alternative dell’istruzione DO perrealizzare cicli repeat e cicli while. Per i primi, si puo usare il cosiddetto DOillimitato combinato con l’istruzione EXIT, secondo la sintassi seguente:

DO...

IF(condizione) EXIT...

rango del DO illimitato

END DO

L’istruzione EXIT trasferisce il flusso all’istruzione che segue END DO. Leripetizioni continuano fintanto che la condizione espressa nell’IF e falsa,e si interrompe appena questa diventa vera. Le istruzioni del rango cheprecedono l’IF vengono sempre eseguite almeno una volta.

I cicli WHILE vengono realizzati tramite il cosiddetto DO WHILE, cheha la struttura seguente:

DO WHILE(condizione)Istruzione 1Istruzione 2

...

rango del DO WHILE

END DO

In questo caso, le ripetizioni continuano finche la condizione espressa nel-l’istruzione DO WHILE e vera, e si interrompono appena diventa falsa. Sela condizione e falsa prima dell’inizio del ciclo, le istruzioni del rango nonvengono eseguite neppure una volta.

39

Page 44: Appunti di FORTRAN 77

9 Esempi riassuntiviriassunto

9.1 Esempio 1es1

Il primo programma, chiamato NORMA, calcola la norma euclidea di unvettore x ∈ R

n, con n ≤ 20, mediante un algoritmo che permette di ridurrel’impatto degli errori di arrotondamento.

PROGRAM NORMAPARAMETER(NM=20)DIMENSION X(NM)PRINT∗, ’dare N minore o uguale di’, NMREAD∗, NPRINT∗, ’dare X’READ∗, (X(I), I=1,N)

C Calcolo XMAX= massimo valore assoluto degli elementi di XXMAX=0DO 15 I=1,N

IF(ABS(X(I)).GT.XMAX) XMAX=ABS(X(I))15 CONTINUE

IF(XMAX.EQ.0.)THENC Se XMAX e uguale a zero, pongo RNORM=0

RNORM=0.ELSE

C Altrimenti calcolo RNORM come somma dei quadrati di X(I)/XMAXRNORM=0.

DO 20 I=1,NRNORM=RNORM+ (X(I)/XMAX)∗∗2

20 CONTINUEC ... e poi l’aggiusto

RNORM=XMAX∗SQRT(RNORM)END IFPRINT∗,’norma euclidea di X: ’,RNORMEND

Il primo ciclo nel programma (DO 15 I=1,N) serve a calcolare la quantitar = maxi|xi|, memorizzandola in XMAX. Il DO e seguito da un IF–THEN–ELSE–ENDIF nel quale si controlla se XMAX e zero o diverso da zero. Nelprimo caso, il vettore X e evidentemente il vettore nullo e quindi il risultatoe RNORM=0; nel secondo caso si procede al calcolo della norma: con il cicloDO 20 I=1,N si calcola il quadrato della norma del vettore con componentixi/r, memorizzandolo in RNORM. Il valore di RNORM viene poi aggiustatoper dare la norma di x desiderata.

40

Page 45: Appunti di FORTRAN 77

9.2 Esempio 2

Il seguente programma ordina in senso crescente gli elementi di un vettorex di R

n, con n ≤ 100.

PROGRAM ORDINA∗ Programma che ordina in senso crescente N (<= 100) numeri reali

PARAMETER(NM=100)DIMENSION X(NM)

10 PRINT∗, ’dare N minore o uguale di’,NMREAD∗, NIF(N.GT.NM)THEN

PRINT∗,’N troppo grande. Leggi bene!’GOTO 10

END IFPRINT∗, ’dare X’READ∗, (X(I), I=1,N)

∗ Per ogni I da 1 a N-1 si sistema l’i-esimo elemento nell’ordinamentoDO 50 I=1,N-1

∗ Per I compreso fra 1 e N-1, si cerca l’indice MIN del piu∗ piccolo fra X(I), ..., X(N)

MIN=IDO 45 J=I+1,N

IF(X(J).LT.X(MIN)) MIN=J45 CONTINUE∗ Se MIN >I bisogna scambiare X(MIN) con X(I)

IF(MIN.GT.I))THENS=X(MIN)X(MIN)=X(I)X(MIN)=S

END IF50 CONTINUE∗ Stampa del vettore ordinato

PRINT∗,’vettore ordinato’,(X(I), I=1,N)END

In questo programma abbiamo inserito un controllo sul valore di N in in-gresso, dando la possibilita di tornare a leggere un nuovo valore nel caso cheil dato immesso sia troppo grande14. Dopo le istruzioni di lettura dei dati,il resto del programma si configura come un ciclo (DO 50 I=1,N-1) finaliz-

14Siamo consapevoli di un pericolo insito nel programma: se una persona continuasseindefinitamente a introdurre valori di N troppo grandi, l’esecuzione andrebbe avanti perun tempo infinito. Per evitare questo richio, avremmo dovuto introdurre un numeromassimo di tentativi possibili, oltre il quale far bloccare il programma. Non l’abbiamo fattoperche confidiamo nella non totale stupidita di qualsiasi persona. Lasciamo comunque aglistudenti come (utile) esercizio il perfezionamento del programma.

41

Page 46: Appunti di FORTRAN 77

zato ad aggiustare l’I-esimo elemento nell’ordinamento richiesto; terminatal’esecuzione del ciclo, l’ultimo elemento, l’N-esimo, e automaticamente gianell’ordine richiesto rispetto ai precedenti. Il rango del DO principale com-prende un altro ciclo DO e un IF. Il ciclo DO 45 J=I+1,N serve a individuarel’indice MIN del piu piccolo fra X(I), . . ., X(N): se MIN risulta uguale a I,non occorre fare niente perche X(I) rispetta gia l’ordinamento desiderato;altrimenti occorre scambiare fra loro X(MIN) e X(I). Lo scambio avvieneservendosi di una variabile d’appoggio S.

9.3 Esempio 3

Il programma MATRICE calcola una matrice H quadrata di ordine n, conn ≤ 20, i cui elementi sono dati da

hij = cos((j − 1)θ), con θ =(2i− 1)π

2n.

Una volta calcolata H, si calcola e si stampa la sua norma–1, definita da

‖H‖1 = maxj=1,...,n

n∑

i=1

|hij |.

Il programma usa la doppia precisione: infatti, tutte le variabili realisono esplicitamente dichiarate in doppia precisione e il nome simbolico PIidentifica la costante in doppia precisione 3.14159265358979D0. Se si volessetrasformare il programma in precisione semplice, sarebbe sufficiente toglierela dichiarazione DOUBLE PRECISION e modificare il valore della costantenell’istruzione PARAMETER, sostituendo la lettera D con la E e riducendoil numero di cifre dal momento che in precisione semplice non ha senso darecostanti con piu di 7 cifre.

Il corpo del programma e nettamente suddiviso in due parti: nella primasi calcola la matrice H e nella seconda la norma–1 di H. Il calcolo di H avvienetramite due DO annidati: il DO 10 I=1,N e il DO 5 J=1,N. Successivamente,si calcola la norma–1 attraverso altri due DO annidati, nei quali si calcolanole sommatorie previste dalla formula e, contemporaneamente, si porta avantiil calcolo della massima sommatoria. Piu precisamente, attraverso il DO piuesterno si fa variare J da 1 a N: per ogni J si calcola la sommatoria TMPdei valori assoluti degli elementi della J–esima colonna di H; poi, si aggiornaHNORM (inizializzato fuori dal DO con il valore zero) con il massimo fra ilprecedente valore e TMP. In questo modo, quando l’esecuzione del DO 30J=1,N e finita, il valore di HNORM e proprio la norma desiderata.

42

Page 47: Appunti di FORTRAN 77

PROGRAM MATRICEPARAMETER(PI=3.14159265358979D0)DOUBLE PRECISION H, HNORM, THETA, TMPDIMENSION H(20,20)PRINT∗, ’dare N minore o uguale di 20’READ∗, N

C Calcolo di HDO 10 I=1,N

THETA=(2∗I-1)∗PI/(2∗N)DO 5 J=1,N

H(I,J)=COS((J-1)∗THETA)5 CONTINUE10 CONTINUEC Calcolo di norma–1 di H

HNORM=0.DO 30 J=1,N

TMP=0.DO 20 I=1,N

TMP=TMP+ABS(H(I,J))20 CONTINUE

HNORM=MAX(TMP,HNORM)30 CONTINUEC Stampa della norma

PRINT∗,’norma–1 di H=’,RNORMEND

10 L’istruzione WRITE(u,f)write

In molte situazioni si ha bisogno di far scrivere i risultati di un programmasu un file di testo, che puo essere conservato in memoria ed eventualmentestampato in un secondo momento; si puo anche voler decidere il forma-to della stampa, nel senso di specificare quante cifre di mantissa scrivereper i numeri reali, quando andare a capo, se e come incolonnare i risultati,quanti spazi lasciare fra un numero e l’altro, e via dicendo. L’istruzionePRINT∗ usata finora non permette di fare nessuna delle due cose: i risul-tati vengono stampati sul video e con un formato prestabilito. Analoghiproblemi possono nascere con l’istruzione di lettura READ∗, che prevede lalettura esclusivamente da tastiera, impedendo ad esempio la lettura dei datida files precedentemente creati (cosa che spesso serve con programmi chemaneggiano grosse moli di dati).

Il FORTRAN prevede istruzioni alternative alla PRINT∗ e READ∗,meno semplici da usare di queste, ma piu flessibili. Il capitolo delle istruzionirelative alle operazioni di ingresso/uscita e molto vasto, ma anche molto

43

Page 48: Appunti di FORTRAN 77

tecnico (cfrAGM[1]). Noi parleremo esclusivamente di istruzioni di uscita, limi-

tandoci a presentare gli strumenti piu comunemente utilizzati per scrivere irisultati su file specificando il formato.

10.1 Scrivere su un file.

Per prima cosa si devono scegliere il nome del file su cui si vogliono scrivere irisultati e un numero intero da associare ad esso. Sia per esempio ris.txt ilnome e 7 il numero. Una volta deciso, si deve inserire nella sezione esecutivadel programma, in qualunque punto purche prima delle istruzioni di uscitache coinvolgono il file, l’istruzione

OPEN (UNIT=7, FILE= ’ris.txt’)

che serve a due scopi:

a) associare il numero 7 al file ris.txt, in modo da poter usare il numero 7al posto del nome ris.txt nelle successive istruzioni di uscita;

b) predisporre per la scrittura il file ris.txt. Se nella cartella di lavoronon esiste un file con questo nome, ne viene automaticamente creato uno,ovviamente vuoto per il momento; se invece esiste gia un file ris.txt, lamacchina si predispone a sovrascrivere sul contenuto precedente15. Al ter-mine dell’esecuzione del programma, il file ris.txt sara disponibile, con tuttele informazioni che il programma stesso ha provveduto a scrivervi.

Se si vuole rendere il programma indipendente dal nome del file, si deveprevedere che questo nome venga letto fra i dati in ingresso; a tale scopo sipuo seguire il seguente schema:

PROGRAM PIPPOCHARACTER∗10 FRIS

...PRINT∗,’dare il nome del file per i risultati’READ∗, FRIS

...OPEN ( UNIT= 7, FILE= FRIS)

...END

dove FRIS e una variabile di tipo carattere i cui valori sono stringhe di alpiu 10 caratteri (ovviamente il 10 puo essere sostituito da un altro numero).Il valore a FRIS viene assegnato tramite l’istruzione READ∗, FRIS; al mo-mento dell’esecuzione di questa istruzione, si dovra scrivere da tastiera ilnome prescelto, ad esempio il nostro solito ris.txt, fra apici.

15E possibile anche fare in modo che il contenuto nuovo venga accodato a quello vecchio;per i dettagli cfr.

AGM[1].

44

Page 49: Appunti di FORTRAN 77

10.2 Scegliere il formato di scrittura.

Una volta che l’istruzione OPEN e stata eseguita, il file e predisposto perla scrittura. L’istruzione piu generale per questa operazione e l’istruzioneWRITE, tramite la quale si puo specificare non solo il nome del file maanche il formato delle stampe. La forma dell’istruzione e la seguente:

WRITE(u,f) lista

dove:

– u e il numero associato al file nell’istruzione OPEN, oppure un asterisco;nel secondo caso la scrittura avviene sul video.

– f e l’etichetta di un’istruzione FORMAT associata alla WRITE nellaquale si descrive il formato con cui si vogliono scrivere i dati contenuti nellalista, oppure un asterisco; nel secondo caso il formato e quello deciso dallamacchina.

– lista e l’elenco delle variabili (o, piu in generale, delle espressioni) di cui sivuole scrivere il valore.

Esempi di istruzioni WRITE sono i seguenti:

WRITE(7,100) A,B,N+MWRITE(2,99) (X(I), I=1,N)WRITE(7,1500) (J, X(J), J=2,N-1)WRITE(7,∗)ABS(C),DWRITE(∗,100)X1 (equivalente a PRINT 100, X1)WRITE(∗,∗)BETA (equivalente a PRINT∗, BETA)

L’istruzione FORMAT ha la forma

f FORMAT (descrizione del formato)

dove la descrizione del formato fra parentesi descrive il modo in cui sivogliono comporre le righe di stampa. Questa descrizione si presenta comeun elenco di singoli descrittori separati da virgole, ognuno dei quali descriveuna “componente” della riga di stampa; i descrittori piu utilizzati nelleapplicazioni numeriche sono:

nX per lasciare n spazi

/ per andare a capo

’xxxxx’ per inserire la stringa di caratteri xxxxx

In per scrivere un numero intero composto da un massimo di ncaratteri, comprensivi delle cifre che compongono il numero edell’eventuale segno.

45

Page 50: Appunti di FORTRAN 77

Ew.d per scrivere un numero reale come costante FORTRAN innotazione scientifica con d cifre di mantissa. w rappresentail numero complessivo di caratteri occupati dal numero: oltrealla mantissa vanno infatti considerati l’eventuale segno, ilpunto decimale, la lettera E e l’esponente con eventuale segno.Abitualmente questo codice viene usato nella forma E13.6 oE14.7 per numeri reali in precisione semplice, per i quali elogico visualizzare 6 o 7 cifre di mantissa.

Dw.d analogo al precedente, viene si solito usato per dati in doppiaprecisione (quindi D22.15 o D23.16); nella stampa compare lalettera D, come nelle costanti FORTRAN doppia precisione.

Quelle che seguono sono alcune osservazioni sulle descrizioni di formato:

– Quando in una descrizione di formato e presente una /, questa funzionaanche da separatore fra descrittori e non occorre usare le virgole; ad esempio,le due descrizioni di formato

I5,/,E13.6 e I5/E13.6

sono equivalenti.

– Le stringhe di caratteri che si vogliono usare per “abbellire” le stampenon vengono di solito inserite nella lista che accompagna la WRITE (comeabbiamo fatto finora con l’istruzione PRINT∗), bensı nella descrizione diformato, tramite il codice ’xxxxx’. Cosı, ad esempio, la coppia di istruzioni

WRITE(∗,100)100 FORMAT(’Buongiorno!’)

e equivalente all’istruzione

PRINT∗,’Buongiorno!’

– Riguardo al codice In per i numeri interi, osserviamo che un numero com-posto da meno di n caratteri viene scritto allineato a destra nel campo din caratteri; se invece il numero richiede piu di n caratteri, l’operazione discrittura non puo essere eseguita e al posto del numero vengono scritti nasterischi (o qualcosa di analogo, a seconda dei compilatori).

– Per quanto concerne i numeri reali, oltre ai codici Ew.d e Dw.d, si puousare il codice Fw.d, con il quale il numero viene scritto come costanteFORTRAN senza esponente con d cifre dopo il punto decimale su un totaledi w caratteri. Se la parte intera del numero, compreso l’eventuale segno,occupa piu di w − d caratteri, il campo viene riempito di asterischi.

A titolo di esempio del funzionamento di un’istruzione WRITE con formato,analizziamo l’effetto della coppia di istruzioni seguente:

46

Page 51: Appunti di FORTRAN 77

WRITE(2,1000)ERR, N1000 FORMAT(3X, ’errore=’, E13.6//3x,’n=’,I4)

3X vengono lasciati 3 spazi all’inizio della riga’errore=’ viene scritto il messaggio “errore=”E13.6 viene scritto il valore di ERR in forma esponenziale con 6

cifre di mantissa/ si va a capo/ si va nuovamente a capo3X vengono lasciati 3 spazi all’inizio della nuova riga’n=’ viene scritto il messaggio “n=”I4 viene scritto il valore di N su un campo di 4 caratteri

Prima di dare altri esempi di istruzioni WRITE con formato, notiamo chepiu istruzioni WRITE in un’unita di programma possono far riferimento allastessa istruzione FORMAT. Inoltre, una FORMAT puo stare dovunque nellasezione esecutiva di un’unita di programma; molti programmatori usanoraggruppare tutte le FORMAT immediatamente prima della END.

10.3 Alcuni esempi

– La coppia di istruzioni

WRITE(7,222)X,Y,Z222 FORMAT(20X,’RISULTATI’/2X,D22.15,2X,D22.15,2X,D22.15)

permette di scrivere su una riga i valori di tre variabili in doppia precisioneX, Y, Z con formato D22.15, ognuno preceduto da 2 spazi. Questa riga epreceduta da un’altra su cui compare la scritta RISULTATI preceduta da20 spazi. La descrizione della seconda riga, in cui si ripete per 3 volte lasequenza 2X,D22.15, puo essere scritta in modo piu compatto 3(2X,D22.15)usando il contatore di ripetizione 3; pertanto l’istruzione FORMAT diventa:

222 FORMAT(20X,’RISULTATI’/3(2X,D22.15))

– Per stampare i primi N elementi di un vettore reale B incolonnati unosotto l’altro, possiamo usare la coppia di istruzioni

WRITE(7,111) (B(I), I=1,N)111 FORMAT(3X,’Vettore B’/(2X,E14.7))

La parentesi che contiene la descrizione 2X,E14.7 serve a impedire che ilmessaggio di intestazione “Vettore B” venga ripetuto prima di ogni rigacontenente il valore di un elemento di B. Infatti la macchina, quando esegueun’operazione di scrittura con formato, scandisce di pari passo la lista ela descrizione di formato. Se arriva alla fine della descrizione (ovvero allaparentesi chiusa finale) e c’e ancora qualcosa da stampare, la macchina ri-

47

Page 52: Appunti di FORTRAN 77

parte a scandire la descrizione dal cosiddetto punto di riscansione, costituitodall’ultima parentesi aperta.

– Con la seguente coppia di istruzioni

WRITE(7,1000)(I, V(I), I=1,N)1000 FORMAT(’V(’ , I3 ,’)=’ ,E14.7)

vengono generate N righe ognuna delle quali ha la forma “V(xxx)=yyyyyy”,dove xxx e il valore di I e yyyyyy e il valore di V(I) scritto in formaesponenziale con 7 cifre di mantissa.

– La sequenza di istruzioni

WRITE(7,121)DO 300 I=1,NWRITE(7,111) (A(I,J), J=1,M)

300 CONTINUE111 FORMAT(3(2X,E13.6))121 FORMAT(4X,’Matrice A per colonne’)

prevede N+1 operazioni di scrittura. Con la prima si crea una riga con l’in-testazione “Matrice A per colonne”. Con ognuna delle successive si scrivonogli elementi di una riga della matrice reale A di dimensione N×M; questielementi vengono scritti a tre a tre su una o piu righe, a seconda di quantovale M.

11 Sottoprogrammisottoprog

Come gia accennato nel paragrafocompila5.1, i programmi FORTRAN sono spesso

strutturati come un insieme di piu unita di programma, una (e una sola)delle quali e il programma principale e gli altri sono sottoprogrammi. Ogniunita di programma viene compilata indipendentemente dalle altre, dandoluogo a un modulo oggetto; il linker crea il programma eseguibile collegandofra loro i diversi moduli oggetto. Grazie a questa gestione autonoma deisottoprogrammi da parte del compilatore, e possibile creare e memorizzaredelle librerie di moduli oggetto corrispondenti a sottoprogrammi finalizzatialla risoluzione di particolari classi di problemi: una libreria per problemi dialgebra lineare, una per risolvere equazioni differenziali, una per problemidi ottimizzazione, per problemi statistici, e via dicendo. L’insieme delle fun-zioni intrinseche del FORTRAN costituisce una libreria che e gia compresanel software che accompagna il compilatore. Esattamente come si fa conqueste funzioni, i sottoprogrammi di una qualsiasi libreria esterna possonoessere usati da qualunque programma FORTRAN, demandando al linker ilcompito di attivare i dovuti collegamenti per creare il programma eseguibile.

48

Page 53: Appunti di FORTRAN 77

Mentre il programma principale puo non avere un nome, un sottopro-gramma deve averlo perche e concepito per essere chiamato, cioe utilizzato,dal programma principale o da altri sottoprogrammi. L’unita di programmache utilizza un sottoprogramma e detta unita chiamante. L’organizzazionedi un programma strutturato in piu unita di programma puo essere anchemolto complessa perche non c’e limite al numero di sottoprogrammi cheun’unita di programma piu chiamare o ai livelli di chiamate: il programmaprincipale chiama un certo numero di sottoprogrammi, ognuno dei quali nerichiama altri, ognuno dei quali ne richiama altri, ognuno dei quali ne richia-ma altri, .... L’unico vincolo e che un sottoprogramma non puo richiamare sestesso, ne direttamente ne indirettamente attraverso una catena di chiamateche alla fine torna a lui16.

L’esecuzione di un programma inizia sempre dal programma principalee procede sequenzialmente, finche non viene incontrato un riferimento aun sottoprogramma. A questo punto, il sottoprogramma viene attivato ele istruzioni della sua sezione esecutiva vengono eseguite sequenzialmentefinche non viene incontrata un’istruzione che rimanda al programma princi-pale, la cui esecuzione riprende in sequenza. Il ritorno al programma prin-cipale puo essere provocato dalla END oppure da un’istruzione RETURN,che provoca appunto l’interruzione del sottoprogramma e il ritorno all’unitachiamante.

In FORTRAN esistono due categorie di sottoprogrammi, che si differen-ziano per scopo e modalita di utilizzo. La prima categoria e costituita dalleFUNCTION, che sono una generalizzazione delle funzioni intrinseche: pos-sono dipendere da un numero qualsiasi di argomenti scalari o meno, ma ilrisultato e uno solo e scalare. La seconda categoria e rappresentata dalleSUBROUTINE, che realizzano algoritmi piu generali, con un numero qual-siasi di dati e risultati, scalari o dimensionati. La forma dell’intestazione diun sottoprogramma ne stabilisce l’appartenenza a una categoria o all’altra.

11.1 Sottoprogrammi FUNCTIONfunction

L’intestazione di una FUNCTION ha la forma

FUNCTION nome (m1,m2, . . . ,mn)

dove nome e m1,m2, . . . ,mn sono nomi simbolici: nome identifica contempo-raneamente il sottoprogramma e il risultato; m1,m2, . . . ,mn, detti argomen-ti muti o formali della FUNCTION, sono i nomi simbolici usati all’internodella FUNCTION per identificare i dati su cui la funzione deve operare.Mentre nome identifica sempre una grandezza scalare, il cui tipo e detto

16Questo si configurerebbe complessivamente come un algoritmo ricorsivo. A differenzadi altri linguaggi di programmazione, il FORTRAN non supporta questo tipo di algoritmi.

49

Page 54: Appunti di FORTRAN 77

tipo della FUNCTION, gli argomenti muti possono identificare grandezzescalari o arrays. Nel secondo caso, la sezione dichiarativa della FUNCTIONdeve contenere istruzioni dichiarative atte ad informare il compilatore dellanatura vettoriale o matriciale di queste grandezze. Allo stesso modo, even-tuali istruzioni di specificazione di tipo relative a nome o agli argomenti mutidevono necessariamente essere presenti nella FUNCTION. Ad esempio, nellaFUNCTION seguente

FUNCTION NF(N)C Calcolo di n!

REAL NFNF=1DO 100 K=2,N

NF=NF∗K100 CONTINUE

RETURNEND

che calcola n! per un dato valore di n, il risultato NF e uno scalare realeperche il nome NF e dichiarato di tipo REAL. L’unico argomento muto Ne invece di tipo intero. Precisiamo che un’eventuale dichiarazione del tipodella FUNCTION puo essere inserita direttamente nell’intestazione primadella parola chiave FUNCTION. Pertanto, le due istruzioni

FUNCTION NF(N)REAL NF

nella FUNCTION NF possono essere sostituire dall’unica istruzione

REAL FUNCTION NF(N)

Tipicamente, nella sezione esecutiva di una FUNCTION non compaionoistruzioni che possano modificare il valore degli argomenti muti; al contrario,devono essere presenti una o piu istruzioni che attribuiscano un valore alrisultato nome. Consideriamo ad esempio la FUNCTION NF. In essa sonopresenti due istruzioni di assegnazione che agiscono sul valore di NF: con laprima il valore di NF viene inizializzato a 1; successivamente, il valore vienecambiato tramite l’istruzione NF=NF∗K all’interno del DO, in modo taleche al termine dell’esecuzione del sottoprogramma NF contiene il risultatodesiderato.

Se nella sezione esecutiva di una FUNCTION non compaiono istruzioniche attribuiscano un valore a nome, il compilatore dovrebbe segnalare unerrore di sintassi e di conseguenza non creare il modulo oggetto. Purtroppo,non tutti i compilatori si comportano in questo modo. Per fare un esempio,supponiamo di cambiare il nome della FUNCTION di prima da NF a RNFlasciando invariato tutto il resto e ottenendo quindi il sottoprogramma

50

Page 55: Appunti di FORTRAN 77

FUNCTION RNF(N)C Calcolo di n!

REAL NFNF=1DO 100 K=2,N

NF=NF∗K100 CONTINUE

RETURNEND

che e chiaramente sbagliato perche il risultato RNF resta indefinito. Se sot-toponiamo la FUNCTION ai nostri due compilatori di riferimento, gfortrane Open WATCOM, non otteniamo messaggi di errore, bensı di Warning.Il compilatore gfortran, usato con opzione –Wall, da un messaggio deltipo: “Warning: Return value of function ... not set”; il compilatore OpenWATCOM da un Warning piu generico, avvertendo che la variabile RNF eunreferenced, ovvero che il sottoprogramma non contiene alcun riferimentoad essa. Trattandosi di Warnings e non errori, i compilatori creano il modulooggetto; nonostante questo, il programmatore attento che legge gli avverti-menti, puo fare mente locale al problema e correggere l’errore, ad esempioaggiungendo prima della RETURN l’istruzione di assegnazione RNF=NF.Ma...attenzione! Se invece di RNF=NF scriviamo NF=RNF, sbagliandoil “verso” dell’assegnazione, nessuno dei due compilatori segnala piu unasituazione anomala: peccato che il valore di RNF resti comunque indefinito!

Le FUNCTION si utilizzano allo stesso modo delle funzioni intrinseche,facendo riferimento ad esse all’interno di espressioni. Un riferimento ha laforma

nome(a1, a2, . . . , an)

dove a1, a2, . . . , an sono i cosiddetti argomenti attuali, costituiti da nomi sim-bolici (o, piu in generale, espressioni) usati nell’unita chiamante per iden-tificare i dati su cui effettivamente il sottoprogramma deve operare 17. Gliargomenti attuali sono in corrispondenza uno–a–uno con quelli muti: a1 cor-risponde a m1, a2 corrisponde a m2, e cosı via; ogni argomento attuale deveessere dello stesso tipo del corrispondente argomento muto e della stessanatura (scalare, vettoriale,...). Vedremo nel paragrafo

assoc11.3 il meccanismo

con cui gli argomenti attuali vengono resi disponibili per l’esecuzione delsottoprogramma. Consideriamo a titolo di esempio le seguenti istruzioni:

17L’aggettivo “attuali” e una brutta traduzione dell’inglese “actual”, ormai entratanell’uso corrente al posto di traduzioni migliori, come ad esempio “effettivi”.

51

Page 56: Appunti di FORTRAN 77

PRINT∗, NF(K)X=NF(N)IF(NF(J+1).GT.A)THEN...R=NF(N)/(NF(K)∗NF(N-K))

Tutti i riferimenti alla FUNCTION NF sono sintatticamente corretti; inalcuni casi l’argomento attuale e un nome di variabile e in altri casi e un’e-spressione, ma in ogni caso (stando alla regola di default sui tipi interoe reale) e di tipo intero, come l’argomento muto N. In fase di esecuzione,questi riferimenti daranno il giusto risultato se e solo se nell’unita chiamanteil nome NF e dichiarato REAL come nella FUNCTION (ricordiamo chel’unita chiamante e il sottoprogramma vengono compilati separatamente eautonomamente, e quindi le istruzioni di specificazione presenti in uno nonservono per l’altro).

Il seguente e un programma principale che usa la FUNCTION NF perdefinire gli elementi di una matrice simmetrica A secondo la formula

aij =

i!j!(i−j)! i > j

1 i = jaji i < j

C Programma che definisce una matrice A simmetrica usando iC coefficienti binomiali

REAL NFDIMENSION A(25,25)PRINT∗, ’dare N minore o uguale di 25’READ∗, NDO 50 I=1,N

A(I,I)=1.DO 50 J=1,I-1

A(I,J)=NF(I)/(NF(J)∗NF(I-J))A(J,I)=A(I,J)

50 CONTINUEPRINT∗,’Matrice A per righe’DO 300 I=1,NWRITE(∗,111) (A(I,J), J=1,N)

300 CONTINUE111 FORMAT(3(2X,E13.6))

END

Consideriamo ora la seguente FUNCTION per il calcolo della normaeuclidea di un vettore.

52

Page 57: Appunti di FORTRAN 77

FUNCTION ENORM(X,N)DIMENSION X(N)XMAX=0DO 15 I=1,N

IF(ABS(X(I)).GT.XMAX) XMAX=ABS(X(I))15 CONTINUE

IF(XMAX.EQ.0.)THENENORM=0.

ELSEXMAX=XMAX∗∗2ENORM=0.DO 20 I=1,N

ENORM=ENORM+ X(I)∗∗2/XMAX20 CONTINUE

ENORM=XMAX∗SQRT(ENORM)END IFRETURNEND

La sezione dichiarativa contiene l’istruzione

DIMENSION X(N)

che specifica la natura vettoriale dell’argomento muto X, in modo che il com-pilatore possa tradurre in modo adeguato le istruzioni eseguibili18 . In as-senza di questa dichiarazione, il compilatore interpreterebbe il simbolo X(I)come il riferimento a una FUNCTION di nome X e in tal senso produrrebbeil modulo oggetto. I problemi verrebbero fuori nella fase di collegamento nelcontesto di un qualsiasi programma: il linker cercherebbe infatti un modulooggetto di nome X, di fatto inesistente.

Usando questa FUNCTION, il programma NORMA del paragrafoes19.1

puo essere scomposto in due unita di programma: la FUNCTION stessa eil programma principale a cui restano i compiti di leggere i dati, usare laFUNCTION per fare i calcoli e stampare il risultato:

18A differenza di quanto visto negli esempi di programmi principali dei paragrafi prece-denti, qui non indichiamo la dimensione di X tramite una costante, ma tramite una vari-abile; piu avanti, nel paragrafo

dimvar11.5, spiegheremo perche questo e possibile e come funziona

in pratica.

53

Page 58: Appunti di FORTRAN 77

PARAMETER(NM=20)DIMENSION X(NM)PRINT∗, ’dare N minore o uguale di’,NMREAD∗, NIF (N.GT.NM)THEN

PRINT∗,’N troppo grande’ELSE

PRINT∗, ’dare X’READ∗, (X(I), I=1,N)RNORMA=ENORM(X,N)PRINT∗,’norma euclidea di X: ’,RNORMA

END IFEND

Puo capitare, anche se raramente, che l’algoritmo realizzato da unaFUNCTION non preveda dati in ingresso. In questo caso l’intestazionedella FUNCTION non contiene una lista di argomenti muti, ma soltantouna coppia di parentesi tonde (aperta e chiusa) vuota. A titolo di esem-pio, riportiamo una FUNCTION per il calcolo della precisione di macchina,tipico algoritmo senza dati in ingresso:

FUNCTION EPSM( )X=1.

10 X=0.5∗XY=1.+XIF(Y.GT.1.) GO TO 10EPSM=2. ∗XEND

e i seguenti sono esempi di utilizzo:

PRINT ∗, EPSM( )IF(ABS(X).LT.EPSM( )) X=0.IF(RCOND.LT.EPSM( ))PRINT∗,’Matrice singolare’

11.2 Sottoprogrammi SUBROUTINEsubroutine

L’intestazione di una SUBROUTINE ha la forma

SUBROUTINE nome(m1,m2, . . . ,mn)

dove nome e il nome del sottoprogramma e m1,m2, . . . ,mn sono gli argo-menti muti. In questo caso nome non riveste un ruolo particolare comenelle FUNCTION: esso serve solo per poter chiamare la SUBROUTINE daun’altra unita di programma e non puo essere usato come nome di variabileall’interno della SUBROUTINE stessa o di un’unita che la chiami. Gli ar-

54

Page 59: Appunti di FORTRAN 77

gomenti muti sono i nomi simbolici usati all’interno della SUBROUTINEper identificare i dati su cui essa deve operare e i risultati che essa produce.Tutti gli argomenti muti possono essere scalari o arrays.

La chiamata di una SUBROUTINE richiede un’istruzione speciale cheha la forma:

CALL nome(a1, a2, . . . , an)

dove a1, a2, . . . , an sono gli argomenti attuali.

Supponiamo di voler trasformare la FUNCTION ENORM in un sottopro-gramma di tipo SUBROUTINE. Se scegliamo per la SUBROUTINE il nomeNORMA, l’intestazione diventa:

SUBROUTINE NORMA(ENORM,X,N)

dove il risultato ENORM e stato inserito nella lista degli argomenti muti; ilresto del sottoprogramma non cambia. Per quanto riguarda il programmaprincipale, tutto resta come prima, salvo che l’istruzione di assegnazione

RNORMA=ENORM(X,N)

viene sostituita da:

CALL NORMA(RNORMA,X,N)

dove l’argomento attuale corrispondente a ENORM e RNORMA, nomeusato nel programma principale per il risultato.

Talvolta un argomento di una SUBROUTINE rappresenta contempo-raneamente un dato e un risultato: quando la SUBROUTINE viene attivata,il valore dell’argomento costituisce un dato in ingresso; poi la SUBROUTINEne cambia il valore, cosı che al termine dell’esecuzione della SUBROUTINE,quando il controllo torna all’unita chiamante, lo stesso argomento costituisceun risultato. A titolo di esempio, consideriamo la seguente SUBROUTINEORDINA, per la quale il vettore X funge da dato (il vettore originale con glielementi non in ordine) e da risultato (il vettore con gli elementi riordinati).

SUBROUTINE ORDINA(N,X)DIMENSION X(N)

C Sottoprogramma che ordina in senso crescente gli elementi di XC N contiene in ingresso la lunghezza del vettoreC X contiene in ingresso il vettore da ordinareC e in uscita il vettore ordinato

DO 50 I=1,N-1MIN=IDO 45 J=I+1,N

IF(X(J).LT.X(MIN)) MIN=J45 CONTINUE

55

Page 60: Appunti di FORTRAN 77

IF(MIN.GT.I))THENS=X(MIN)X(MIN)=X(I)X(MIN)=S

END IF50 CONTINUE

RETURNEND

Il seguente programma principale usa la SUBROUTINE ORDINA per or-dinare gli elementi di un vettore e la FUNCTION ENORM per calcolarnela norma euclidea:

PARAMETER(NM=100)DIMENSION V(NM)OPEN(UNIT=2,FILE=’ris.txt’)PRINT∗, ’dare N minore o uguale di’, NMREAD∗, NPRINT∗, ’dare V’READ∗, (V(I), I=1,N)WRITE(2,20)(V(I), I=1,N)CALL ORDINA(N,V)WRITE(2,10)(V(I), I=1,N)WRITE(2,30)ENORM(V,N)

10 FORMAT(2X,’Vettore ordinato’/(2X,E13.6))20 FORMAT(2X,’Vettore originale’/(2X,E13.6))30 FORMAT(//2X,’Norma euclidea=’,E13.6)

END

11.3 Associazione fra argomenti muti e argomenti attualiassoc

Nelle istruzioni che compongono la sezione esecutiva di un sottoprogram-ma, vengono utilizzati gli argomenti muti e anche altre variabili, i cui nominon fanno parte della lista degli argomenti muti perche non identificanograndezze i cui valori devono essere comunicati dall’unita chiamante al sot-toprogramma o viceversa; esse sono le cosiddette variabili locali, usate al-l’interno del sottoprogramma per identificare grandezze utili alla scritturadell’algoritmo. Le variabili locali e gli argomenti muti sono trattati in mo-do diverso dal compilatore: le prime vengono inserite nella tavola dei sim-boli e associate a locazioni di memoria nel modo usuale; per i secondi, puoessere allocata memoria oppure no, a seconda delle modalita previste perl’associazione fra essi e gli argomenti attuali che saranno specificati nellechiamate del sottoprogramma.

Fondamentalmente, i linguaggi di programmazione possono scegliere fradue modalita per attuare questa associazione:

56

Page 61: Appunti di FORTRAN 77

– per valore, nel qual caso il compilatore alloca memoria per gli argomen-ti muti. Al momento dell’attivazione del sottoprogramma il valore di ogniargomento in ingresso viene copiato nella locazione del corrispondente argo-mento muto e, viceversa, al momento del rilascio il valore di ogni argomentomuto in uscita viene copiato nella locazione del corrispondente argomentoattuale.

– per indirizzo, nel qual caso il compilatore non alloca memoria per gliargomenti muti. Al momento dell’attivazione, l’unita chiamante invia alsottoprogramma gli indirizzi delle locazioni di memoria allocate per gli ar-gomenti attuali, in modo che il sottoprogramma operi direttamente su questelocazioni. In questo modo il sottoprogramma trova i dati in ingresso nelle lo-cazioni degli argomenti attuali corrispondenti a argomenti muti in ingresso;inoltre, siccome ogni modifica fatta dal sottoprogramma su un argomentomuto e di fatto un cambiamento del valore memorizzato nella locazione delcorrispondente argomento attuale, l’unita chiamante trova i risultati diretta-mente nelle locazioni degli argomenti in uscita. In pratica, l’associazione perindirizzo puo essere vista come un cambiamento temporaneo di nome per lelocazioni degli argomenti attuali: per la durata dell’esecuzione del sottopro-gramma la locazione identificata con il nome ai dall’unita chiamante vieneidentificata con il nome mi, e riacquisice il suo nome originale al momentodel rientro nell’unita chiamante.

Lo svantaggio ovvio dell’associazione per valore e il costo in termini dioccupazione di memoria; quello dell’associazione per indirizzo e che talvoltaoccorre fare preventivamente una copia di un argomento attuale se non sivuole che il sottoprogramma ne cambi il valore. Alcuni linguaggi usanodi default l’associazione per indirizzo, altri quella per valore, altri infinepermettono di scegliere la modalita argomento per argomento. Il FORTRANappartiene alla prima categoria.

Cerchiamo di capire meglio, alla luce di questa informazione, cosa siintende quando si afferma che gli argomenti attuali devono essere in cor-rispondenza uno–a–uno con gli argomenti muti, anche alla luce del fatto cheabitualmente i compilatori non prevedono controlli sulla correttezza delleliste di argomenti attuali rispetto alle corrispondenti liste di argomenti muti(e pertanto, gli errori si manifestano in fase di esecuzione). Sia dato adesempio un sottoprogramma con l’intestazione

SUBROUTINE ESER(M,N,X,R)

dove M e N sono scalari interi e X e R scalari reali; consideriamo le seguentichiamate, supponendo che anche nell’unita chiamante sia rispettata la regoladi default per i nomi delle variabili intere e reali:

57

Page 62: Appunti di FORTRAN 77

1) CALL ESER(M,M1,DATO,R1)2) CALL ESER(M,M1,V(2),ARS)3) CALL ESER(10,J,DATO,R(10))4) CALL ESER(N,M,DATO,RIS)5) CALL ESER(K(1),K(2),DATO, RR)6) CALL ESER(A,N,X,R)7) CALL ESER(M,N,RR)

–La prima e la quarta chiamata sono corrette.

–La seconda chiamata e corretta se nell’unita chiamante V e un vettore: infase di esecuzione l’indirizzo del secondo elemento di V viene mandato alsottoprogramma, che lavora su questa locazione usando il nome X.

–La terza chiamata e corretta se nell’unita chiamante R e un vettore dialmeno 10 elementi e se l’argomento muto M rappresenta un dato per ilsottoprogramma che non viene modificato in corso di esecuzione (se cosınon fosse, il sottoprogramma, operando sulla locazione in cui e memorizzatala costante 10 e modificandone il contenuto, cambierebbe di fatto il valoredella costante !!).

–La quinta chiamata e corretta se nell’unita chiamante K e un vettore.

–La sesta chiamata e sbagliata perche il primo argomento attuale A e ditipo reale mentre il corrispondente argomento muto M e di tipo intero. Cosasuccede in questo caso? Come gia detto, il compilatore in generale non rileval’errore, e il problema si manifesta durante l’esecuzione: tenendo conto chei nomi A e M si riferiscono di fatto alla stessa locazione di memoria, l’unitachiamante interpretera la sequenza di “0” e “1” contenuta nella locazionecome un numero reale floating point, e il sottoprogramma interpretera lastessa sequenza come un numero intero: e facilmente intuibile che i duevalori non avranno niente a che vedere fra loro. Lo stesso tipo di errore siverificherebbe se si utilizzasse la FUNCTION NF del paragrafo

function11.1 senza

dichiarare il nome NF di tipo REAL nell’unita chiamante.

–L’ultima chiamata e sbagliata perche ci sono 3 argomenti attuali contro 4argomenti muti. Anche questo errore si manifestera in fase di esecuzione,probabilmente come segmentation fault.

11.4 Argomenti muti dimensionati

Come funziona l’associazione per indirizzo se l’argomento muto e il nome diuna variabile dimensionata? In questa situazione l’argomento attuale deveessere una variabile dimensionata a sua volta, oppure il nome di un elemen-to di variabile dimensionata: nel primo caso, l’indirizzo passato al sotto-programma e quello della variabile dimensionata attuale, che coincide conquello del suo primo elemento; nel secondo caso, l’indirizzo e quello dell’ele-mento specificato come argomento attuale. Per meglio puntualizzare questi

58

Page 63: Appunti di FORTRAN 77

concetti, consideriamo la SUBROUTINE ORDINA(N,X) del paragrafosubroutine11.2

e supponiamo di chiamarla da un programma principale che contiene ladichiarazione

DIMENSION Y(100), AM(10,10)

Allora le seguenti chiamate:

1) CALL ORDINA(M,Y)2) CALL ORDINA(M,Y(11))3) CALL ORDINA(M,A)4) CALL ORDINA(M,A(1,2))

sono tutte corrette se M e una variabile intera. Esaminiamole ad una aduna supponendo che il valore di M sia 10.

1) La chiamata e equivalente a CALL ORDINA(M,Y(1)). Viene trasmessoal sottoprogramma l’indirizzo del vettore Y e a partire da questo indirizzoil sottoprogramma “vede” il suo vettore X; lo schema di associazione fra isingoli elementi del vettore attuale e del vettore muto e pertanto

Y(1) Y(2) Y(3) · · · Y(10)

X(1) X(2) X(3) · · · X(N)

essendo l’argomento muto N associato a M, che vale 10. Per effetto di questachiamata, i valori dei primi 10 elementi del vettore Y risulteranno ordinatiin senso crescente.

2) Viene trasmesso al sottoprogramma l’indirizzo di Y(11). L’associazionee descritta dalla figura seguente

Y(11) Y(12) Y(13) · · · Y(20)

X(1) X(2) X(3) · · · X(N)

e l’effetto e l’ordinamento degli elementi di Y da Y(11) a Y(20).

3) Viene trasmesso al sottoprogramma l’indirizzo della matrice A, ovvero delprimo elemento A(1,1), e a partire da questa locazione il sottoprogrammavede il suo vettore X; tenendo conto che le matrici sono memorizzate percolonne, l’associazione e descritta dalla figura seguente

A(1,1) A(2,1) A(3,1) · · · A(10,1)

X(1) X(2) X(3) · · · X(N)

e l’effetto e il riordino degli elementi della prima colonna di A.

4) Questa chiamata e simile alla precedente, salvo il fatto che ora vienetrasmesso al sottoprogramma l’indirizzo dell’elemento di A di indici (1,2);l’associazione e allora descritta dalla figura seguente

A(1,2) A(2,2) A(3,2) · · · A(10,2)

X(1) X(2) X(3) · · · X(N)

e l’effetto e l’ordinamento degli elementi della seconda colonna di A.

59

Page 64: Appunti di FORTRAN 77

Il seguente e un programma che usa la FUNCTION ENORM per calco-lare la norma euclidea di tutte le colonne di una matrice X di N righe e Mcolonne.

DIMENSION X(20,30)PRINT∗, ’dare N <= 20 e M <=30’READ∗, N,MPRINT∗, ’dare X per colonne’READ∗, ((X(I,J), I=1,N), J=1,M)DO 25 J=1,M

PRINT∗,’norma della colonna ’,J,: ’,ENORM(X(1,J),N)25 CONTINUE

END

11.5 Dimensionamento variabile e indefinito per vettoridimvar

Nei paragrafi precedenti abbiamo usato istruzioni DIMENSION riferite aargomenti muti dei sottoprogrammi, in cui la lunghezza del vettore era de-scritta dalla variabile N (a sua volta, argomento muto). Questo rientra nellanorma del FORTRAN 77, secondo il quale e possibile specificare la lunghez-za di un vettore argomento muto tramite un’espressione intera, nella qualecompaiano costanti e variabili intere, con il vincolo che queste variabili de-vono essere a loro volta argomenti muti, o parte di un blocco COMMON(cfr. paragrafo

com15). Si parla in questo caso di dimensionamento variabile (in

inglese, adjustable size). Sono esempi corretti di uso del dimensionamentovariabile i seguenti:

FUNCTION ES1(X,IW,N,M,...)DIMENSION X(N+M), IW(N)

SUBROUTINE PIPPO(VET,N,...)DOUBLE PRECISION VET(N)

SUBROUTINE PLUTO(L,ALFA, WORK,...)DIMENSION WORK(L+1), ALFA(2∗L)

Come funziona in pratica il dimensionamento variabile? Sia X il nomedell’argomento muto dimensionato in modo variabile. L’istruzione di speci-ficazione in cui si dichiara la dimensione di X serve per informare il compi-latore della natura dimensionata di X, in modo tale che esso possa tradurrecorrettamente le istruzioni eseguibili che coinvolgono elementi di X. Lalunghezza effettiva di X non serve ai fini della compilazione, ma viene de-terminata in fase di esecuzione, quando alle variabili che intervengono nel-l’espressione della dimensione vengono associati i corrispondenti argomentiattuali e quindi il sottoprogramma puo disporre del loro valore. Conside-

60

Page 65: Appunti di FORTRAN 77

riamo la SUBROUTINE PLUTO dell’esempio precedente. Se si effettua lachiamata

CALL PLUTO(5, A, W,...)

le lunghezze effettive di ALFA e WORK determinate durante l’esecuzionedella chiamata saranno rispettivamente 5+1=6 e 2×5=10.

La conoscenza della lunghezza effettiva del vettore non serve per allocarememoria, perche le locazioni per l’argomento muto sono di fatto quelle delcorrispondente argomento attuale; essa viene sfruttata soltanto se nel sot-toprogramma figurano istruzioni che fanno riferimento al vettore nella suatotalita, come ad esempio PRINT∗, ALFA.

E importante ricordare che il dimensionamento variabile e consentito so-lo per argomenti muti, e non per variabili locali. Un compilatore che rispettirigorosamente lo standard FORTRAN 77 segnala errore se questa regola nonviene rispettata. Cosı reagisce ad esempio l’Open WATCOM. Il compi-latore gfortran prevede invece la possibilita di usare il dimensionamentovariabile all’interno di un sottoprogramma anche per variabili locali, purchele variabili intere che compaiono nella dichiarazione di dimensione siano ar-gomenti muti o facciano parte di un blocco COMMON. La memoria perquesti vettori viene allocata in fase di esecuzione, al momento del calcolodella lunghezza effettiva, e rilasciata al termine dell’esecuzione del sotto-programma. Questo e un piccolo esempio di uso dinamico della memoria.Il problema, purtroppo, e che gfortran non gestisce sempre bene questaallocazione dinamica, con effetti imprevedibili sul risultato dei programmi,analoghi a quelli che si possono verificare quando si usa piu memoria diquella riservata a una variabile.

Quando in un sottoprogramma non sono presenti istruzioni che fannoriferimento ad un vettore argomento muto nella sua totalita si puo usareuna forma di dimensionamento ancora piu semplice di quello variabile. Sipuo infatti specificare la dimensione tramite un asterisco (∗), e si parla inquesto caso di dimensionamento indefinito (in inglese, assumed size). Adesempio, nella FUNCTION ENORM si potrebbe sostituire l’istruzione

DIMENSION X(N)

con

DIMENSION X(∗)Dal punto di vista del compilatore, le due istruzioni sono equivalenti. L’unicadifferenza e che nel secondo caso non viene mai determinata la lunghezzaeffettiva del vettore19.

19Per questo motivo non e possibile, neanche usando gfortran, usare il dimensiona-mento indefinito per vettori che non facciano parte della lista degli argomenti muti. Se losi fa, viene segnalato l’errore “Assumed size array... must be a dummy argument”.

61

Page 66: Appunti di FORTRAN 77

La scelta fra dimensionamento variabile o indefinito e una questionedi gusto personale del programmatore, che deve decidere come far sapereall’utente del sottoprogramma quante locazioni di memoria devono esseredisponibili per l’array al momento dell’attivazione del sottoprogramma. Sesi opta per il dimensionamento variabile, questa informazione e contenutanell’istruzione di specificazione usata nel sottoprogramma per dichiarare l’ar-ray; se invece si opta per il dimensionamento indefinito, si deve corredare ilsottoprogramma di linee di commento in cui precisare la lunghezza dell’array.

11.6 Dimensionamento variabile e indefinito per matricidimvarmat

Il dimensionamento variabile puo essere usato anche per matrici, ma inquesto caso occorre una certa accortezza. Per spiegare questa affermazione,consideriamo il seguente sottoprogramma

SUBROUTINE MAT(A,N)DIMENSION A(N,N)DO 10 I=1,N

DO 10 J=1,NA(I,J)=0.1∗(I+J)

10 CONTINUERETURNEND

il cui scopo e definire una matrice reale A quadrata di ordine n, con elementiaij = 0.1(i+ j). La matrice e un argomento muto e puo essere dimensionatain modo variabile; pertanto abbiamo usato l’istruzione dichiarativa

DIMENSION A(N,N).

Il seguente programma principale utilizza la SUBROUTINE MAT. L’argo-mento attuale B corrispondente a A e una matrice di ordine 4, e quindi ilsottoprogramma puo essere usato per valori di n minori o uguali di 4.

PARAMETER(NM=4)DIMENSION B(NM,NM)PRINT ∗, ’dare N <=’,NMREAD ∗,NCALL MAT(B,N)WRITE( ∗,100) ((B(I,J), J=1,N), I=1,N)

100 FORMAT(4(2X,E13.6))END

Se eseguiamo il programma con N uguale a N, il risultato e

0.200000E+00 0.300000E+00 0.400000E+00 0.500000E+000.300000E+00 0.400000E+00 0.500000E+00 0.600000E+000.400000E+00 0.500000E+00 0.600000E+00 0.700000E+000.500000E+00 0.600000E+00 0.700000E+00 0.800000E+00

62

Page 67: Appunti di FORTRAN 77

e possiamo facilmente verificare che e quello giusto. Ma se N vale 2, ilrisultato e 20.

0.200000E+00 0.512685E-19 0.300000E+00 0.459163E-40

laddove il risultato corretto sarebbe

0.200000E+00 0.300000E+00 0.300000E+00 0.400000E+00

A cosa e dovuto questo risultato sbagliato, dal momento che tutte edue le unita di programma sono perfettamente corrette dal punto di vistasintattico? Per rispondere a questa domanda, dobbiamo ricordare che l’as-sociazione fra B e A avviene per indirizzo, e che le matrici sono memorizzateper colonne. Al momento dell’attivazione del sottoprogramma, il program-ma principale invia l’indirizzo di B (ovvero quello di B(1,1)) e a partire daquesta locazione di memoria il sottoprogramma “vede” la matrice A. Inoltre,per effetto del dimensionamento variabile, il sottoprogramma determina ledimensioni effettive di A durante l’esecuzione in base al valore attuale cor-rispondente a N. Pertanto, quando N vale 4, la matrice A viene consideratadi 4 righe e 4 colonne e l’associazione fra gli elementi di B e quelli di A e:

B(1,1) B(2,1) B(3,1) B(4,1) B(1,2) B(2,2) B(3,2) B(4,2) · · ·A(1,1) A(2,1) A(3,1) A(4,1) A(1,2) A(2,2) A(3,2) A(4,2) · · ·B(1,3) B(2,3) B(3,3) B(4,3) B(1,4) B(2,4) B(3,4) B(4,4)

A(1,3) A(2,3) A(3,3) A(4,3) A(1,4) A(2,4) A(3,4) A(4,4)

con una corrispondenza perfetta fra gli indici usati nel programma princi-pale per B e quelli usati nel sottoprogramma per A: la locazione che il sot-toprogramma identifica come A(I,J) e la stessa che il programma principaleidentifica come B(I,J), qualunque sia la coppia di indici (I,J).

Osserviamo ora cosa succede quando N vale 2. In questo caso, A risultauna matrice 2× 2 e l’associazione con B segue lo schema seguente:

B(1,1) B(2,1) B(3,1) B(4,1) · · ·A(1,1) A(2,1) A(1,2) A(2,2)

Questa volta non c’e piu corrispondenza fra gli indici usati dal sottoprogram-ma e quelli usati dal programma principale: i primi due elementi di A (cherappresentano la prima colonna) sono associati agli omonimi elementi di B;poi pero, il sottoprogramma “fa partire” la seconda colonna di A, mentreancora la prima colonna di B non e finita. Se vogliamo ottenere una perfettacorrispondenza di indici anche in questo caso, dobbiamo fare in modo che ilsottoprogramma “salti” il resto della prima colonna di B e associ A(1,2) aB(1,2), secondo uno schema del tipo

B(1,1) B(2,1) B(3,1) B(4,1) B(1,2) B(2,2) · · ·A(1,1) A(2,1) A(1,2) A(2,2)

20Teniamo conto che in virtu del formato di stampa scelto, troviamo 4 numeri su ogniriga: per N=2, i primi due numeri formano la prima riga di B e gli altri la seconda riga.

63

Page 68: Appunti di FORTRAN 77

Questo scopo puo essere raggiunto soltanto rendendo noto al sottoprogram-ma il numero di righe di B, in modo che esso possa attribuire a A esatta-mente lo stesso numero di righe. Questa informazione puo essere passataal sottoprogramma in fase di esecuzione se inseriamo fra gli argomenti mutiuna variabile NR a cui far corrispondere come argomento attuale il numerodi righe di B (qualunque sia il valore di N). La variabile NR deve essereusata nel sottoprogramma esclusivamente per definire le dimensioni di A,sostituendo l’istruzione

DIMENSION A(N,N)

con

DIMENSION A(NR,N)

Con questo cambiamento, ci sara corrispondenza fra gli indici usati dall’unitachiamante per B e quelli usati dal sottoprogramma per A, qualunque sia ilvalore di N. Ad esempio, per N pari a 2, si ottiene l’associazione desideratafra gli elementi di B e quelli di A:

B(1,1) B(2,1) B(3,1) B(4,1) B(1,2) B(2,2) B(3,2) B(4,2)· · ·A(1,1) A(2,1) A(3,1) A(4,1) A(1,2) A(2,2) A(3,2) A(4,2)

Gli elementi A(3,1), A(4,1), A(3,2) e A(4,2) non verrano mai usati nel-la sezione esecutiva. Infatti, in questa sezione del sottoprogramma, si de-vono continuare a usare soltanto le locazioni identificate dai nomi A(I,J) perI,J=1,N. In conclusione, la SUBROUTINE MAT e il programma principalediventano:

SUBROUTINE MAT(A,N,NR) !!!DIMENSION A(NR,N) !!!DO 10 I=1,N

DO 10 J=1,NA(I,J)=0.1∗(I+J)

10 CONTINUERETURNEND

PARAMETER(NM=4)DIMENSION B(NM,NM)PRINT ∗, ’dare N <=’,NMREAD ∗,NCALL MAT(B,N,NM) !!!WRITE( ∗,100) ((B(I,J), J=1,N), I=1,N)

100 FORMAT(4(2X,E13.6))END

dove abbiamo contrassegnato con !!! le istruzioni cambiate rispetto alla

64

Page 69: Appunti di FORTRAN 77

versione precedente.Data la sua importanza ai fini del corretto uso del sottoprogramma, il nu-

mero di righe di una matrice argomento muto e chiamato anche dimensioneprincipale (in inglese leading dimension) della matrice.

Anche per le matrici e possibile usare il dimensionamento indefinito, masoltanto per quanto riguarda il numero di colonne. Ad esempio, se H e unargomento muto di un sottoprogramma, si puo utilizzare una dichiarazionedel tipo

DIMENSION H(NR, ∗)ma non

DIMENSION H(∗,∗)Questa restrizione ha una sua logica: una volta che il sottoprogramma hal’informazione sul numero di righe della matrice, puo assegnare gli indici aisingoli elementi e identificare la locazione chiamata H(I,J) per qualunquecoppia di indici I e J. Se potesse essere lasciato indefinito anche il numerodi righe, il sottoprogramma non sarebbe in grado di assegnare indici dopol’elemento H(1,1).

12 Alcune regole di buona programmazione

Una volta scritto ed eventualmente compilato, un sottoprogramma e in lineadi principio utilizzabile nel contesto di qualsiasi programma FORTRAN incui sia necessario ricorrere all’algoritmo da esso realizzato. Tenendo a mentequesto fatto, ogni programmatore dovrebbe scrivere i sottoprogrammi inmodo da non limitarne le possibilita di utilizzo. Qui di seguito riportiamoalcune regole da seguire per ottenere questo scopo.

12.1 Istruzioni di scrittura nei sottoprogrammi

Le istruzioni di scrittura sono in genere bandite dai sottoprogrammi. Ilprogrammatore puo talvolta decidere di inserire nella lista degli argomentimuti un argomento in ingresso tramite il quale l’utente puo scegliere seeseguire stampe oppure no (cfr. Esempio 2 del paragrafo

esempi13). Fatta salva

questa situazione, le operazioni di scrittura sono riservate al programmaprincipale, al quale il sottoprogramma deve inviare tutte le informazioniutili per poter decidere che cosa stampare.

Per fare un esempio, consideriamo la seguente SUBROUTINE ERONE,che calcola l’area di un triangolo con la formula di Erone e prevede controlliatti a individuare le situazioni di errore, come nel programma (principale)ERONE3 del paragrafo

ELSE8.2.3. A differenza di quanto fatto in quel program-

ma, nella SUBROUTINE non abbiamo inserito istruzioni di stampa, ma

65

Page 70: Appunti di FORTRAN 77

abbiamo previsto fra gli argomenti muti un argomento in uscita che indicaall’unita chiamante come “sono andate a finire le cose“; piu precisamente,la SUBROUTINE prevede due risultati:

– IND e un intero che in uscita vale 1 se tutto e andato bene e l’area e statacalcolata, 0 altrimenti;

– AREA e una variabile reale il cui valore e l’area del triangolo se IND vale1 ed e 0 se IND vale 0.

La coppia di istruzioni

IND=0

AREA=0

prende il posto dell’istruzione di stampa

PRINT∗,’Dati non corrispondenti a un triangolo’

del programma ERONE3.

SUBROUTINE ERONE(A,B,C,IND,AREA)C Calcolo dell’area di un triangolo con la formula di EroneC A,B,C reali in ingressoC IND intero in uscita:C =1 se tutto va beneC =0 se A,B e C non sono le lunghezze dei lati di un triangoloC AREA reale in uscita:C area del triangolo se IND=1C 0 se IND=0C

IF((A.GT.0.).AND.(B.GT.0.).AND.(C.GT.0.))THENSP=(A+B+C)/2.Q=SP∗(SP-A)∗(SP-B)∗(SP-C)IF(Q.GT.0.)THEN

AREA=SQRT(Q)IND=1

ELSEIND=0AREA=0.

END IFELSE

IND=0AREA=0.

END IFEND

Un programma principale che usi questa SUBROUTINE deve contenereun’istruzione IF dopo la chiamata per controllare il risultato attraverso il

66

Page 71: Appunti di FORTRAN 77

valore di IND e eseguire le operazioni di stampa coerenti. Una sequenza diistruzioni atta allo scopo potrebbe essere la seguente:

CALL ERONE(A,B,C,IND,AREA)IF(IND.EQ.0)THEN

PRINT∗,’Dati non corrispondenti a un triangolo’...

ELSEPRINT∗,’area= ’, AREA...

END IF

12.2 Istruzioni STOP e RETURN

Un sottoprogramma non contiene mai istruzioni STOP. E utile a questoproposito puntualizzare la differenza fra le istruzioni RETURN e STOP.L’istruzione RETURN, che puo comparire soltanto in un sottoprogramma,interrompe l’esecuzione del sottoprogramma e rimanda all’unita di program-ma chiamante, nella quale l’esecuzione riprende in sequenza. L’istruzioneSTOP invece interrompe l’esecuzione dell’intero programma, in qualunqueunita (programma principale o sottoprogramma) venga incontrata. E ovvioche un sottoprogramma non puo “arrogarsi” il diritto di chiudere l’esecuzionedi qualsiasi programma in cui venga usato 21.

12.3 Arrays di lavorolavoro

Quando un sottoprogramma e finalizzato alla risoluzione di un problemadi dimensione variabile (sistema lineare di n equazioni in n incognite, in-terpolazione polinomiale su n nodi, etc.), i vettori e le matrici coinvoltinell’algoritmo devono essere dimensionati in modo variabile o indefinito,a meno che la loro dimensione non sia indipendente dalla dimensione delproblema. Questo implica che talvolta si devono inserire nella lista degliargomenti muti nomi di variabili dimensionate che non rappresentano datio risultati dell’algoritmo, ma sono semplicemente arrays di lavoro. Comeesempio di buona programmazione nel senso suddetto, mostriamo qui di se-guito la parte iniziale del sottoprogramma SSTEV della libreria LAPACK,reperibile in rete ad esempio all’indirizzo http://www.netlib.org, per il cal-

21Questa appena enunciata e la precedente relativa alle istruzioni di scrittura, sonoregole di buona programmazione. Il fatto che comunque non sia vietato inserire istruzionidi stampa e STOP in un sottoprogramma, permette di farne uso in fase di messa a puntodei programmi. Infatti si usa spesso, quando un programma non da risultati giusti, fareuna sorta di debug manuale, inserendo stampe in vari punti per capire dove si general’errore, e eventualmente controlli che bloccano l’esecuzione del programma in determinatecircostanze.

67

Page 72: Appunti di FORTRAN 77

colo di autovalori ed eventualmente autovettori di una matrice tridiagonalesimmetrica di ordine n.

SUBROUTINE SSTEV( JOBZ, N, D, E, Z, LDZ, WORK, INFO )** – LAPACK driver routine (version 3.2) –* – LAPACK is a software package provided by Univ. of Tennessee,* – Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd.* – November 2006* .. Scalar Arguments ..

CHARACTER JOBZINTEGER INFO, LDZ, N

* .. Array Arguments ..REAL D( * ), E( * ), WORK( * ), Z( LDZ, * )

* Purpose* =======* SSTEV computes all eigenvalues and, optionally, eigenvectors of a real* symmetric tridiagonal matrix A.* =========* Arguments** JOBZ (input) CHARACTER*1* = ’N’: Compute eigenvalues only;* = ’V’: Compute eigenvalues and eigenvectors.** N (input) INTEGER* The order of the matrix. N >= 0.** D (input/output) REAL array, dimension (N)* On entry, the n diagonal elements of the tridiagonal matrix A.* On exit, if INFO = 0, the eigenvalues in ascending order.** E (input/output) REAL array, dimension (N-1)* On entry, the (N-1) subdiagonal elements of the tridiagonal* matrix A, stored in elements 1 to N-1 of E.* On exit, the contents of E are destroyed.** Z (output) REAL array, dimension (LDZ, N)* If JOBZ = ’V’, then if INFO = 0, Z contains the orthonormal* eigenvectors of the matrix A, with the i-th column of Z* holding the eigenvector associated with D(i).* If JOBZ = ’N’, then Z is not referenced.*

68

Page 73: Appunti di FORTRAN 77

* LDZ (input) INTEGER* The leading dimension of the array Z. LDZ >= 1, and if* JOBZ = ’V’, LDZ >= max(1,N).** WORK (workspace) REAL array, dimension (max(1,2*N-2))* If JOBZ = ’N’, WORK is not referenced.** INFO (output) INTEGER* = 0: successful exit* < 0: if INFO = -i, the i-th argument had an illegal value* > 0: if INFO = i, the algorithm failed to converge; i* off-diagonal elements of E did not converge to zero.*

Dall’istruzione dichiarativa

REAL D(∗), E(∗), WORK(∗), Z(LDZ,∗)

apprendiamo che gli argomenti muti D, E, WORK, Z sono variabili dimen-sionate per le quali gli autori hanno utilizzato il dimensionamento indefinito.Dalla successiva documentazione apprendiamo che:

– D e E sono argomenti di input/output: al momento dell’attivazione delsottoprogramma identificano dei dati, poi vengono modificati in modo taleche al momento del rientro nell’unita chiamante identificano dei risultati.

– Z e un argomento di output che contiene, se richiesti, gli autovettori. Seil dato JOBZ vale ’N’, la matrice Z non viene usata; pertanto l’argomentoattuale corrispondente a Z potra essere uno scalare e quello corrispondentea LDZ potra essere 1. Se invece JOBZ e ’Y’, la matrice Z viene usata el’argomento attuale corrispondente a LDZ dovra essere maggiore o ugualea N (noi sappiamo che dovra essere uguale al numero di righe della matriceattuale corrispondente a Z).

– Infine, WORK e un vettore di lavoro che viene utilizzato se JOBZ vale ’Y’.Esso e presente nella lista degli argomenti muti perche la sua dimensione,2N-2, dipende da N.

Un programma principale che utilizzi questo sottoprogramma deve contenereun’istruzione dichiarativa tramite la quale si alloca memoria per il vettoreWORK: se W e il nome dell’argomento attuale che si intende associare aWORK, il programma deve contenere ad esempio le istruzioni

PARAMETER(NM=20)DIMENSION W(2∗NM-2)

A proposito di arrays di lavoro, e interessante la seguente osservazione. Sup-

69

Page 74: Appunti di FORTRAN 77

poniamo di avere un programma costituito dal programma principale e duesottoprogrammi, UNO e DUE: il programma principale chiama UNO, che asua volta chiama DUE. Supponiamo anche che DUE abbia bisogno di un vet-tore di lavoro W con dimensione variabile, ma che questo vettore non servaa UNO. Ebbene, il vettore fara sicuramente parte della lista degli argomentimuti di DUE, ma saremo costretti a inserirlo anche in quella di UNO perchela memoria verra allocata nel programma principale e, in fase di esecuzione,UNO dovra ricevere l’indirizzo del vettore attuale dal programma principalee trasmetterlo a DUE.

13 Esempi di programmi con sottoprogrammiesempi

13.1 Esempio 1.

In questo programma si approssima l’integrale

∫ π

2

0cos2(x)esin(2x)dx

mediante le formule composite dei Trapezi e di Simpson su n sottointervalli.Tutte le variabili reali sono in doppia precisione. Il programma e compostoda quattro unita di programma:

– Il programma principale, i cui compiti sono: leggere n; definire l’intervallodi integrazione; calcolare i valori della funzione y0, . . . , yn nei nodi usan-do la FUNCTION F; calcolare i valori approssimati dell’integrale usando isottoprogrammi SIMP e TRAP; stampare i risultati.

– La FUNCTION SIMP che realizza la formula di Simpson composita.

– La FUNCTION TRAP che realizza la formula dei Trapezi composita.

– La FUNCTION F che descrive la funzione integranda.

C =========================================C Programma per l’approssimazione di un integrale mediante le formuleC composite di Simpson e dei Trapezi (Numero di sottointervalli <=20)C

PARAMETER (M=20)IMPLICIT DOUBLE PRECISION (A-H,O-Z)DIMENSION Y(0:M)PRINT ∗, ’Dare il numero N di sottointervalli’PRINT ∗, ’N pari e <=’, MREAD*,NA=0.D0

C Si calcola pi/2 come 2*arctg(1)B = 2.D0*ATAN(1.D0)H= (B-A)/N

70

Page 75: Appunti di FORTRAN 77

DO 100 I = 0, NY(I) = F(A+I*H)

100 CONTINUES=SIMP(N,H,Y)T=TRAP(N,H,Y)PRINT*,’N=’, N,’ S=’, S, ’ T=’,TEND

C =========================================FUNCTION F(X)DOUBLE PRECISION F, XF=COS(X)**2*EXP(SIN(2.D0*X))END

C =========================================FUNCTION SIMP(N,H,Y)IMPLICIT DOUBLE PRECISION (A-H,O-Z)

CC Subroutine per il calcolo di un integrale mediante la formula compositaC di Simpson con N sottointervalli di ampiezza HC Il vettore Y contiene i valori della funzione integranda nei nodiC

DIMENSION Y(0:N)S1=0.DO 150 I = 1, N-1, 2

S1 = S1 + Y(I)150 CONTINUE

S2=0.DO 200 I = 2, N-2, 2

S2 = S2 + Y(I)200 CONTINUE

SIMP = H*(Y(0)+ 2.D0*S1+ 4.D0*S2 + Y(N))/3.D0RETURNEND

C =========================================FUNCTION TRAP(N,H,Y)IMPLICIT DOUBLE PRECISION (A-H,O-Z)

CC Subroutine per il calcolo di un integrale mediante la formula compositaC dei Trapezi con N sottointervalli di ampiezza HC Il vettore Y contiene i valori della funzione integranda nei nodiC

DIMENSION Y(0:N)S=0.DO 150 I = 1, N-1

S = S + Y(I)150 CONTINUE

TRAP = H*(Y(0)+ 2.D0*S+ Y(N))/2.D0RETURNEND

C =========================================

71

Page 76: Appunti di FORTRAN 77

13.2 Esempio 2

Il secondo esempio riguarda il metodo di Newton per risolvere un’equazionenon lineare f(x) = 0. Il programma e composto da cinque unita di pro-gramma:

– Il programma principale, nel quale si leggono i dati, si esegue il meto-do di Newton utilizzando la SUBROUTINE NEWTON, e si stampano irisultati. Questi vengono scritti su file usando l’istruzione WRITE (cfr.paragrafo

write10): il nome del file e identificato dalla variabile di tipo carat-

tere NOMEF, il cui valore e un dato in ingresso, e l’identificatore nu-merico del file e espresso tramite una variabile intera IUNIT. L’istruzioneOPEN(UNIT=IUNIT,FILE=NOMEF) predispone il file per la scrittura.Gli altri dati letti sono: il punto iniziale, il numero massimo di iterazioni ela tolleranza per il criterio di arresto. Oltre a questi, si prevede il dato IP,con valore 1 se si vuole che la SUBROUTINE stampi i risultati di tutte leiterazioni e 0 altrimenti.

–La SUBROUTINE NEWTON, che realizza il metodo di Newton. Questosottoprogramma utilizza la FUNCTION F e la FUNCTION DER per ilcalcolo dei valori di f e della derivata f ′ rispettivamente. Inoltre, essoutilizza la FUNCTION EPSM per calcolare la precisione di macchina ǫm:se a una certa iterazione la derivata e in valore assoluto minore di ǫm, ilsottoprogramma si arresta.

– La FUNCTION F che descrive la funzione f . Nell’esempio, si definisce inparticolare la funzione polinomiale f(x) = x3 − 100x2 − x + 100.

– La FUNCTION DER che descrive la derivata della funzione f .

– La FUNCTION EPSM che calcola la precisione di macchina.

C =========================================PROGRAM EQNONLINCHARACTER*10 NOMEFPRINT∗,’dare il nome del file per i risultati’READ∗,NOMEFIUNIT=3OPEN(UNIT=IUNIT,FILE=NOMEF)PRINT∗,’dare x (punto iniziale)’READ∗,XPRINT∗,’dare kmax (numero massimo di iterazioni)’READ∗,KMAXPRINT∗,’dare tol (tolleranza per il criterio di arresto)’READ∗,TOLPRINT∗,’stampe ad ogni iterazione (0 NO/1 SI)?’READ∗,IPCALL NEWTON(IUNIT,X,KMAX,TOL,IP,IND,FX,ITER)

72

Page 77: Appunti di FORTRAN 77

IF(IND.EQ.1)THENWRITE(IUNIT,2000)

ELSE IF(IND.EQ.-1)THENWRITE(IUNIT,4000)

ELSEWRITE(IUNIT,5000)

END IFIF(IP.EQ.0)WRITE(IUNIT,6000)ITER,X,FXSTOP

2000 FORMAT(’soddisfatto il criterio di arresto’)4000 FORMAT( ’derivata uguale a zero’)5000 FORMAT( ’esaurite le iterazioni’)6000 FORMAT(2X,’numero di iterazioni effettuate: ’,I3

1 2X,’ultima iterata : ’,E13.62 2X,’VALORE DI f : ’,E13.6)END

C =========================================SUBROUTINE NEWTON(IUNIT,X,KM,TOL,IP,IND,FX,ITER)

cc Metodo di Newton per risolvere un’equazione non lineare f(x)=0cc in ingresso:c IUNIT identificatore dell’unita di uscitac X approssimazione inizialec KM numero massimo di iterazionic TOL tolleranza per il criterio di arrestoc IP stampe a tutte le iterazioni (1) o no (0)cc in uscita:c IND indicatore del risultato:c =1 soddisfatto il criterio di arrestoc =-1 |derivata| < della precisione di macchinac =-2 esaurite le iterazionic X ultima approssimazione calcolatac FX valore di f in Xc ITER numero di iterazioni effettuatecc L’utente deve fornire un sottoprogramma FUNCTION F(X)c e un sottoprogramma FUNCTION DER(X) che descrivonoc rispettivamente la funzione f e la sua derivatac

EPS=EPSM( )FX=F(X)

73

Page 78: Appunti di FORTRAN 77

IF(IP.EQ.1)THENK=0WRITE(IUNIT,1000)K,X,FX

END IFDO 500 K=1,KMITER=KFDX=DER(X)

c valore assoluto della derivata < della precisione di macchinaIF(FDX.LE.EPS)THEN

IND=-1RETURN

END IFc calcolo della successiva iterata

DX=FX/FDXX=X-DXFX=F(X)IF(IP.EQ.1)THEN

WRITE(IUNIT,1000)K,X,FXEND IF

c criterio di arrestoIF(ABS(FX).LE.TOLF) THEN

IND=1RETURN

END IF500 CONTINUEc esaurite le iterazioni

IND=-2RETURN

1000 FORMAT(2X,’k=’,I3,2X,’ x=’, E13.6,2X,’f(x)=’,E13.6)END

C =========================================FUNCTION EPSM( )X=1.

10 X=0.5∗XY=1.+XIF(Y.GT.1.) GO TO 10EPSM=2. ∗XEND

C =========================================FUNCTION F(X)F= X ∗∗3-100 ∗X ∗∗2-X+100END

FUNCTION DER(X)DER=3∗X∗∗2-200∗X-1END 74

Page 79: Appunti di FORTRAN 77

13.3 Esempio 3

In questo terzo esempio si vuole verificare se due matrici date A e B com-mutano. Il programma e organizzato su tre unita di programma:

– Il programma principale, nel quale si leggono le matrici, si calcolano idue prodotti AB e BA usando la SUBROUTINE PMAT e si controlla lacommutativita mediante la FUNCTION ICOMM. Siccome il risultato dellaSUBROUTINE PMAT viene sovrascritto alla seconda matrice, si devonousare delle matrici di appoggio SA e SB. Inoltre, e necessario dichiarareun vettore di lavoro W perche richiesto dalla stessa SUBROUTINE. Il pro-gramma prevede di leggere il valore di una tolleranza TOL utilizzata dallaFUNCTION ICOMM.

– La SUBROUTINE PMAT che calcola il prodotto AB memorizzando ilrisultato su B.

– La FUNCTION ICOMM, che verifica se due matrici reali date sono ugualia meno di una tolleranza assegnata. Si tratta di una funzione logica, il cuirisultato e la costante logica .TRUE. oppure .FALSE.

C =========================================C Programma per verificare se due matrici reali date commutanoC

PROGRAM COMMUTAPARAMETER (NM=20)DIMENSION A(NM,NM),B(NM,NM),SA(NM,NM),SB(NM,NM)DIMENSION W(NM)LOGICAL ICOMMPRINT ∗, ’Dare TOL’READ*,TOLPRINT ∗, ’Dare N <=’,NMREAD*,NPRINT ∗, ’Dare A per righe’READ*,((A(I,J), J=1,N), I=1,N)PRINT ∗, ’Dare B per righe’READ*,((B(I,J), J=1,N), I=1,N)

C Faccio copie di A e BDO 100 J=1,N

DO 100 I=1,NSA(I,J)=A(I,J)SB(I,J)=B(I,J)

100 CONTINUEC Memorizzo il prodotto AB in SB e il prodotto BA in SA

CALL PMAT(N,NM,A,SB,W)CALL PMAT(N,NM,B,SA,W)

75

Page 80: Appunti di FORTRAN 77

C Verifico la commutativita’IF(ICOMM(N,NM,SA,SB,TOL))THEN

PRINT*,’Le due matrici commutano’ELSE

PRINT*,’Le due matrici non commutano’END IFEND

CC =========================================C

SUBROUTINE PMAT(N,NR,A,B,W)DIMENSION A(NR,N), B(NR,N), W(N)

cC Sottoprogramma che calcola il prodotto fra A e B, memorizzandolo in BC W vettore di lavoroC

DO 50 J=1,NDO 30 I=1,N

W(I)=0.DO 30 K=1,N

W(I)=W(I)+A(I,K)∗B(K,J)30 CONTINUE

DO 40 I=1,NB(I,J)=W(I)

40 CONTINUE50 CONTINUE

RETURNEND

C =========================================C

LOGICAL FUNCTION ICOMM(N,NR,A,B,TOL)DIMENSION A(NR,N), B(NR,N)

C Sottoprogramma che verifica se A e B sono uguali a meno di TOLC In uscita: ICOMM=.TRUE. se A e B sono ugualiC =.FALSE. altrimenti

DO 200 J=1,NDO 200 I=1,NIF(ABS(A(I,J)-B(I,J)).GT.TOL∗ABS(A(I,J))+TOL)THEN

ICOMM=.FALSE.RETURN

END IF200 CONTINUE

ICOMM=.TRUE.END

76

Page 81: Appunti di FORTRAN 77

13.4 Esempio 4

L’ultimo esempio e dedicato al metodo di Gauss con pivoting per la risoluzionedi un sistema lineare Ax = b. Il programma consiste di cinque unita diprogramma, tutte in doppia precisione:

– Il programma principale, in cui la matrice A e prevista in lettura, mentreil termine noto e definito da bi =

∑nj=1 aij , in modo che sia nota la soluzione

esatta x = (1, 1, . . . , 1)T . Una volta risolto il sistema, il programma calcola

(usando la FUNCTION VETNINF) e stampa l’errore ‖x− x‖∞ e ‖r‖∞‖b‖∞

, dover = Ax− b e il vettore residuo.

– La SUBROUTINE GAUSSPIV, il cui scopo e triangolarizzare A usando ilmetodo di Gauss con pivoting; se nel corso dell’algoritmo viene trovato unpivot uguale a zero, la SUBROUTINE “comunica” al programma principaleche A e singolare.

– La SUBROUTINE RISOLVI che risolve il sistema usando i risultati dellaSUBROUTINE GAUSSPIV.

– La SUBROUTINE RESIDUO che calcola il vettore residuo.

– La FUNCTION VETNINF per il calcolo della norma infinito di un vettore.

C =========================================C Soluzione di un sistema lineare con il metodo di Gauss con pivotingC

PROGRAM DGAUSSIMPLICIT DOUBLE PRECISION (A-H,O-Z)PARAMETER(NM=10)DIMENSION A(NM,NM),B(NM),X(NM),IP(NM-1),R(NM),E(NM)DIMENSION CA(NM,NM), CB(NM)CHARACTER*10 RISPRINT∗,’dare il nome del file risultati’READ*,RISOPEN(UNIT=2,FILE=RIS)PRINT∗,’dare n <=’,NMREAD∗,NPRINT∗,’dare A per colonne’READ∗,((A(I,J), I=1,N), J=1,N)

C Si calcola B e si fanno copie di A e B, da usarsi per il calcoloC del vettore residuo (GAUSSPIV e RISOLVI modificano A e B)

DO 10 I=1,NB(I)=0.DO 5 J=1,N

B(I)=B(I)+ A(I,J)CA(I,J)=A(I,J)

77

Page 82: Appunti di FORTRAN 77

5 CONTINUECB(I)=B(I)

10 CONTINUEC Si triangolarizza A. Se risulta singolare (IFLAG=1),ci si ferma.

CALL GAUSSPIV(N,A,NM,IPIV,IFLAG)IF(IFLAG.EQ.1)THEN

WRITE(2,1000)STOP

END IFC Si procede alla risoluzione del sistema triangolare

CALL RISOLVI(N,NM,A,IP,B,X)C Si calcolano vettore residuo e errore e relative norme

CALL RESIDUO(N,NM,CA,CB,X,R)DO 50 I=1,N

E(I)=X(I)-1.D050 CONTINUE

RNORM= VETNINF(R,N)BNORM= VETNINF(B,N)ENORM= VETNINF(E,N)WRITE(2,2000)WRITE(2,3000) (X(I),IPIV(I),I=1,N)WRITE(2,3100) ENORM, RNORM/BNORM

1000 FORMAT(/2X,’ matrice singolare’)2000 FORMAT(10X,’soluzione’, 6X ,’ipiv’//)3000 FORMAT(2X,D22.15,2X,I3)3100 FORMAT(/10X,’errore: ’, D13.6/10X,’residuo relativo: ’, D13.6)

END

C =========================================SUBROUTINE GAUSSPIV(N,A,NMAX,IPIV,IFLAG)IMPLICIT DOUBLE PRECISION (A-H,O-Z)DIMENSION A(NMAX,N), IPIV(N-1)

CC Metodo di Gauss con pivoting, fase 1: triangolarizzazione di ACArgomenti in ingresso:C N, dimensione del sistemaC A, matrice dei coefficientiC NMAX, dimensione principale di AC Argomenti in ingresso:C Argomenti in uscita:C A, nel triangolo superiore contiene la matrice triangolareC nel triangolo strettamente inferiore contiene i moltiplicatoriC IPIV, vettore degli indici delle righe pivotaliC IFLAG, indicatore del risultato:C =0 tutto OKC =1 matrice singolareC

IFLAG=0

78

Page 83: Appunti di FORTRAN 77

DO 1000 K=1,N-1IPIV(K)=KAMAX= ABS(A(K,K))DO 10 I=K+1,N

IF(AMAX.LT.ABS(A(I,K))THENAMAX=ABS(A(I,K))IPIV(K)=I

END IF10 CONTINUE

IF(AMAX.EQ.0)THENIFLAG=1RETURN

END IFIF(IPIV(K).NE.K)THEN

DO 20 J=K,NS=A(IPIV(K),J)A(IPIV(K),J)=A(K,J)A(K,J)=S

20 CONTINUEEND IFDO 40 I=K+1,N

A(I,K)=A(I,K)/A(K,K)DO 40 J=K+1,N

A(I,J)=A(I,J)-A(I,K)∗A(K,J)40 CONTINUE1000 CONTINUE

IF(A(N,N).EQ.0.)IFLAG=1RETURNEND

C =========================================SUBROUTINE RISOLVI(N,NMAX,A,IPIV,B,X)IMPLICIT DOUBLE PRECISION (A-H,O-Z)DIMENSION A(NMAX,N), B(N), X(N),IPIV(N-1)

CC Metodo di Gauss con pivoting, fase 2: modifica di b e risoluzione delC sistema triangolare con il metodo di sostituzione all’indietroCC Argomenti in ingresso:C N, dimensione del sistemaC NMAX, dimensione principale di AC A, IPIV come usciti dalla SUBROUTINE GAUSSPIVC B, vettore dei termini notiC Argomenti in uscita:C B, modificato con le trasformazioni di GaussC X, soluzione del sistema

79

Page 84: Appunti di FORTRAN 77

C Trasformazione di BDO 1000 K=1,N-1

IF(IPIV(K).NE.K)THENS=B(K)B(K)=B(IPIV(K))B(IPIV(K))=S

END IFDO 100 I=K+1,N

B(I)=B(I)-A(I,K)∗B(K)100 CONTINUE1000 CONTINUEC Sostituzione all’indietro

X(N)=B(N)/A(N,N)DO 200 I=N-1,1,-1

S=0.DO 150 J=I+1,N

S=S+A(I,J)∗X(J)150 CONTINUE

X(I)=(B(I)-S)/A(I,I)200 CONTINUE

ENDC =========================================

SUBROUTINE RESIDUO(N,NR,A,B,X,R)IMPLICIT DOUBLE PRECISION (A-H,O-Z)DIMENSION A(NR,N), B(N), X(N),R(N)

C Calcolo del vettore residuo r=Ax-bDO 200 I=1,N

S=-B(I)DO 99 J=1,N

S=S+A(I,J)∗X(J)99 CONTINUE

R(I)=S200 CONTINUE

RETURNEND

C =========================================FUNCTION VETNINF(V,N)IMPLICIT DOUBLE PRECISION (A-H,O-Z)DIMENSION V(N)VETNINF=0.DO 100 I=1,N

IF(ABS(V(I)).GT.VETNINF) VETNINF=ABS(V(I))100 CONTINUE

END

80

Page 85: Appunti di FORTRAN 77

14 Istruzione EXTERNALext

Consideriamo la SUBROUTINE NEWTON dell’Esempio 2. Un utente chevoglia utilizzarla deve scrivere due FUNCTION per descrivano la funzionedi cui si vuole calcolare uno zero e la sua derivata; questi sottoprogrammidevono necessariamente chiamarsi F e DER, perche il linker ha bisogno diun modulo oggetto di nome F e uno di nome DER per creare il programmaeseguibile. In alcune situazioni questo vincolo sui nomi puo essere restritti-vo. Ad esempio, l’utente puo avere gia due FUNCTION atte allo scopo macon nomi diversi da F e DER, oppure puo voler scrivere un programma perrisolvere due equazioni corrispondenti a due diverse funzioni (e ovvio chele FUNCTION corrispondenti ai due problemi non possono chiamarsi nel-lo stesso modo). Per questo motivo, converrebbe modificare l’intestazionedella SUBROUTINE NEWTON inserendo i nomi F e DER nell’elenco degliargomenti muti, in modo tale i due nomi diventino formali; in questo mo-do, gli argomenti attuali corrispondenti, ovvero i nomi dei sottoprogrammirealmente esistenti, potranno essere diversi da F e DER, esattamente comesuccede per tutti gli argomenti di un sottoprogramma. In questa ottica, lalista degli argomenti muti della SUBROUTINE diventerebbe:

(F,DER,IUNIT,X,KM,TOLF,TOLX,IP,IND,FX,K)

e la parte di documentazione che recita

c L’utente deve fornire un sottoprogramma FUNCTION F(X)c e un sottoprogramma FUNCTION DER(X) che descrivonoc rispettivamente la funzione f e la sua derivata

sarebbe da intendersi vincolante per quanto concerne gli argomenti dei sot-toprogrammi F e DER, ma non per quanto riguarda i nomi. Con questanuova intestazione, si potrebbe concepire la seguente chiamata:

CALL NEWTON(F1,D1,IUNIT,X,KM,TOLF,TOLX,IP,IND,FX,K)

purche siano disponibili una FUNCTION F1 e una FUNCTION D1, en-trambe dipendenti da un unico argomento reale.

Affinche il linker sappia che i nomi dei moduli oggetto da cercare sonoF1 e D1, e l’associazione fra i nomi formali F e DER e i nomi attuali F1e D1 possa essere correttamente realizzata in fase di esecuzione, occorreinformare il compilatore che questi ultimi sono nomi di sottoprogrammi,e non semplicemente nomi di variabili. Questa informazione viene fornitatramite l’istruzione dichiarativa

EXTERNAL F1, D1

che ovviamente deve comparire nell’unita di programma chiamante. Inquesto modo sarebbe possibile concepire una sequenza di istruzioni comequella tratteggiata qui sotto, in cui si risolvono piu equazioni:

81

Page 86: Appunti di FORTRAN 77

EXTERNAL F1,D1, F2,D2, F3, D3...

CALL NEWTON(F1,D1,IUNIT,X,KM,TOLF,TOLX,IP,IND,FX,K)...

CALL NEWTON(F2,D2,IUNIT,X,KM,TOLF,TOLX,IP,IND,FX,K)...

CALL NEWTON(F3,D3,IUNIT,X,KM,TOLF,TOLX,IP,IND,FX,K)

Il programma in questione sarebbe composto da otto unita di programma: ilprogramma principale, la SUBROUTINE NEWTON, e le function F1, F2,F3, D1, D2 e D3.

Alcuni programmatori, tipicamente quelli che hanno l’abitudine di speci-ficare il tipo di tutte le variabili anche quando non e necessario, sono solitiinserire un’istruzione EXTERNAL anche nel sottoprogramma fra i cui ar-gomenti muti compare un nome di sottoprogramma. Ad esempio, questiprogrammatori inserirebbero nella SUBROUTINE NEWTON con la nuovaintestazione l’istruzione

EXTERNAL F, DER

E importante ribadire che questa dichiarazione non e assolutamente neces-saria per la corretta compilazione del sottoprogramma e tanto meno per lacorretta esecuzione, esattamente come non lo e una dichiarazione del tipoINTEGER N. Dichiarazioni superflue come queste vanno intese in generalecome nient’altro che informazioni per l’utilizzatore del sottoprogramma.

15 Istruzione COMMONcom

Per quanto abbiamo visto finora, lo scambio di informazioni fra unita di pro-gramma avviene esclusivamente attraverso il meccanismo di associazione fraargomenti muti e argomenti attuali (o, come si dice abitualmente, attraversola lista degli argomenti). Ci sono situazioni in cui questo puo provocare unappesantimento del lavoro del programmatore.

Per esempio, abbiamo gia osservato nel paragrafolavoro12.3 cosa puo succedere

in presenza di una catena di chiamate del tipo

P. principale ⇒ Sottoprog. 1 ⇒ Sottoprog. 2 ⇒ Sottoprog. 3

Se il sottoprogramma 3 ha bisogno di un vettore di lavoro dimensionato inmodo variabile, questo vettore deve far parte della lista degli argomenti mutidei sottoprogrammi 1 e 2 perche l’indirizzo del vettore attuale deve arrivaredal programma principale attraverso tutti gli anelli della catena. Questovincolo non riguarda ovviamente solo le variabili di lavoro, ma in generale

82

Page 87: Appunti di FORTRAN 77

tutte le variabili con dimensionamento variabile o indefinito, e puo talvoltacostringere i programmatori a scrivere liste degli argomenti molto lunghe 22.

Esaminiamo ora un’altra situazione in cui l’uso esclusivo delle liste diargomenti come strumento per la trasmissione delle informazioni fra unitadi programma puo diventare molto oneroso. A questo scopo consideriamoancora il sottoprogramma NEWTON. Qualunque sia il nome che si utilizzaper il sottoprogramma che descrive la funzione f , questo deve prevedereun solo argomento muto, reale e scalare; l’obbligo deriva dal modo in cuila funzione F viene usata nella SUBROUTINE NEWTON. Supponiamoora di voler scrivere un programma in cui si usa la SUBROUTINE perrisolvere un’equazione dipendente da un parametro, per diversi valori diquesto parametro. Ad esempio, l’equazione potrebbe essere:

f(x;α) = x2 − αx + cos(3x + α) = 0,

dove α e il parametro, a cui vogliamo assegnare i valori 0.5, 1.5 e 2. A causadell’impossibilita di usare la lista degli argomenti muti per trasmettere allaFUNCTION il valore di α, siamo costretti a scrivere tre diverse FUNCTION,una per ogni valore di α:

FUNCTION F1(X)ALPHA=0.5F1=X∗∗2-ALPHA∗X+COS(3.∗X+ALPHA)END

FUNCTION F2(X)ALPHA=1.5F2=X∗∗2-ALPHA∗X+COS(3.∗X+ALPHA)END

FUNCTION F3(X)ALPHA=2.F4=X∗∗2-ALPHA∗X+COS(3.∗X+ALPHA)END

e altrettante FUNCTION da far corrispondere alla DER. Dovremmo a questopunto fare tre chiamate alla SUBROUTINE NEWTON, secondo uno schemaanalogo a quello tracciato nell’esempio precedente. In questa ottica, se vo-lessimo usare α = 0.5k con k = 1, 2, . . . , 20, dovremmo scrivere 20 “copie”di F e 20 di DER.

In realta esiste un’alternativa. Ogni volta che, per un motivo qualsiasi,non si puo o non si vuole utilizzare la lista degli argomenti come mezzodi comunicazione fra unita di programma, si puo ricorrere ad un diversomeccanismo di comunicazione offerto dal FORTRAN: i blocchi COMMON.

22Anche se un programmatore esperto sa come fare per evitarlo; ma questo e un discorsoche esula dallo scopo di queste dispense.

83

Page 88: Appunti di FORTRAN 77

Un blocco COMMON e un insieme di locazioni di memoria consecutivealle quali hanno accesso piu unita di programma, che vi fanno riferimentocon nomi locali. Ad esempio, un blocco COMMON costituito da 3 locazioniper numeri floating point in precisione semplice potrebbe essere visto comeun unico vettore reale di 3 elementi da una unita di programma e come3 variabili reali scalari da un altro. Per definire un blocco COMMON siusa l’istruzione dichiarativa caratterizzata dalla parola chiave COMMON.Se X,Y e Z sono tre variabili reali scalari, l’istruzione

COMMON X,Y,Z

definisce un blocco COMMON formato da tre locazioni consecutive. Nel-l’unita di programma in cui questa istruzione compare, le tre locazioni sonoidentificate dai nomi X, Y e Z. Se in un’altra unita dello stesso programmacompare l’istruzione

COMMON A,B,C

le stesse locazioni sono identificate in quella unita dai nomi A, B e C.L’istruzione COMMON puo essere usata anche per dichiarare i vettori, allastregua delle istruzioni di specificazione di tipo. Cosı, l’istruzione

COMMON X(3)

dice al compilatore che X e un vettore di 3 elementi, le cui locazioni costi-tuiscono un blocco COMMON da spartire con altre unita di programma.

Con questo nuovo strumento si puo risolvere brillantemente la situazioneprecedente delle equazioni dipendenti da un parametro. Possiamo infattiscrivere un programma principale del tipo:

PROGRAM EQALFACOMMON ALPHAEXTERNAL F,DER

...DO 100 K=1,20ALPHA=0.5∗KCALL NEWTON(F,DER,IUNIT,X,KM,TOLF,TOLX,IP,IND,FX,K)

...100 CONTINUE

END

dove le funzioni F e DER acquisiscono il valore del parametro accedendo alblocco COMMON:

FUNCTION F(X)COMMON ALPHAFALFA=X∗∗2-ALPHA∗X+COS(3.∗X+ALPHA)END

84

Page 89: Appunti di FORTRAN 77

FUNCTION DER(X)COMMON ALPHADALFA=2.∗X-ALPHA-3.∗SIN(3.∗X+ALPHA)END

E importante sottolineare che l’istruzione COMMON compare soltanto nelleunita di programma in cui la variabile coinvolta (ALPHA) viene utilizzata:nel programma principale, dove le viene assegnato il valore, e nelle dueFUNCTION F e DER che usano questo valore. Non e invece assolutamentenecessario inserire l’istruzione anche nella SUBROUTINE NEWTON perchein questa SUBROUTINE la variabile ALPHA non interviene. Di fatto, pos-siamo dire che in questo modo abbiamo scavalcato un anello della catena dichiamate, mettendo in comunicazione direttamente il programma principalecon le FUNCTION F e DER.

L’istruzione COMMON puo essere usata per definire piu di un bloccoCOMMON all’interno di un programma FORTRAN. In questo caso i blocchivengono contraddistinti da un nome e vengono chiamati blocchi COMMONetichettati, mentre quello che abbiamo usato prima e un blocco non etichet-tato, detto anche blank COMMON. Per definire un blocco etichettato si usal’istruzione COMMON nella forma

COMMON/nome/ lista

Ad esempio, l’istruzione

COMMON/C1/ A(1000)

definisce un blocco COMMON di nome C1 formato da 1000 locazioni dimemoria per dati reali, identificate come elementi di un vettore di lunghez-za 1000. Un’altra unita di programma potrebbe avere accesso alle stesselocazioni di memoria identificandole come elementi di una matrice di 10righe e 100 colonne (ordinati per colonna) usando l’istruzione

COMMON/C1/ A(10,100)

Per ulteriori dettagli sull’istruzione COMMON rimandiamo aAGM[1].

Riferimenti bibliografici

AGM [1] G.Aguzzi, M.G. Gasparo, M. Macconi, FORTRAN 77 uno strumentoper il calcolo scientifico, Pitagora ed. 1987.

MR [2] M. Metcalf, J. Reid, Fortran 90/95 explained, Oxford SciencePublications, 1996.

Overton [3] M.L. Overton dal, Numerical computing with IEEE floating pointarithmetic, SIAM, 2001.

85