note per il corso linguaggi di programmazione per il ...seghini/fortran/pdf/note-lezioni.pdf ·...
Post on 14-Feb-2019
221 Views
Preview:
TRANSCRIPT
Università degli Studi di Roma "La Sapienza"
Corso di laurea in Matematica
Note per il corso
Linguaggi di programmazione per il calcolo scientifico
Introduzione alla programmazione in linguaggio fortran
Alessandra Seghini
Introduzione alla programmazione in linguaggio fortran
Indice: (per stampare, utilizzare le note del corso in formato PDF)
Introduzione
Variabili e costanti scalari
Operatori ed espressioni
Scelte e decisioni
Cicli
Foglio esercizi 1
Array
Foglio esercizi 2
Tipi derivati
Inizializzazione aree di memoria
Procedure:
Subroutine
Function
Foglio esercizi 3
Intent e Interface
Foglio esercizi 4
Foglio esercizi 5
Ricorsività
Procedure come argomenti
Foglio esercizi 6
Variabili globali
Funzioni di tipo array e di tipo derivato
Istruzioni di input/output
Gestione dei file
Foglio esercizi 7
Foglio esercizi 8
Puntatori
Foglio esercizi 9
Limiti del F77
Note per l'utilizzo del compilatore fortran in ambiente linux
Bibliografia:
S. J. Chapman, Fortran 90/95 - Guida alla programmazione, Mc Graw Hill
T.M.R. Ellis, Programmazione Strutturata in Fortran 77 con elementi di Fortran 90, Zanichellli
M. Metcalf, J. Reid, Fortran 90 Explained, Oxford University Press
Nota: queste pagine forniscono una traccia degli argomenti svolti nel corso "Linguaggi di programmazione per il calcolo scientifico"
Alessandra Seghini
LINGUAGGI AD ALTO LIVELLO
Codice macchina (codice binario specifico per ogni tipo di computer)
Linguaggio assemblatore (forma mnemonica del codice macchina)
Linguaggio ad alto livello (Fortan, Pascal, C, Ada, Cobol, etc.)
Linguaggio ad alto livello ---(compilatore)---> Codice macchina
Compilatore:
controlla la sintassi delle istruzioni e produce informazioni
diagnostiche che permettono di correggere eventuali errori.
traduce il programma in codice macchina
Lo stesso programma ad alto livello può essere eseguito su computer
completamente diversi compilando con compilatori diversi che siano in grado di
interpretare la stessa sequenza di input (istruzione in linguaggio ad alto livello) e
tradurre nel codice macchina specifico per quel computer.
Il FORTRAN è stato il primo linguaggio ad alto livello ed è ancora largamente usato
per scopi tecnici e scientifici. Nasce intorno alla metà degli anni '50 col nome di:
IBM FORmula TRANslation System
Il FORTRAN 66 è stato il primo standard ufficiale.
Standard successivi largamente diffusi sono stati il FORTRAN 77 ed il FORTRAN
90.
PROGETTARE ... PROGRAMMARE... VERIFICARE
Progettare
Tracciare il percorso logico del programma costruendo una mappa di
sviluppo che riporti la struttura generale a vari livelli di dettaglio.
1.
Programmare
Nella costruzione del programma saranno necessari i seguenti strumenti:
editor
----->
programma sorgente (.f90, .f77, .for)
compilatore
----->
modulo oggetto (.o, .obj, .lis, .err, etc.)
linker
----->
programma eseguibile (.exe)
Un ambiente di sviluppo integrato è un insieme di applicazioni (editor,
2.
compilatore, linker, debugger) per scrivere, compilare e testare un
programma. Per molti linguaggi sono disponibili pacchetti che dispongono
di tali ambienti di sviluppo (es. Borland Pascal, Microsoft Fortran, etc.)
Verificare
Individuazione e correzione degli errori:
errori sintattici (o grammaticali)
individuati dal compilatore e (normalmente) facili da correggere
errori semantici (o logici)
talvolta difficili da trovare. Per evitare errori logici e per poterli
individuare più facilmente è necessario pianificare la costruzione
del programma ed utilizzare tecniche di programmazione
strutturata, con uso di subroutine o gruppi di subroutine, che
possano essere costruite e testate in modo indipendente.
L'individuazione degli errori logici può essere facilitata dall'utilizzo
di appositi programmi di debugging.
FORMATO DI UNA RIGA DI PROGRAMMA
Il formato dei programmi scritti con il vecchio standard fortran 77 era molto
rigido. Tale rigidità è un retaggio dell'epoca in cui si usavano ancora le schede
perforate: ogni singola riga di programma usava solo le prime 72 colonne (le
colonne 73-80 erano usate per la numerazione delle schede):
Num.colonna significato
1
2
3
4
5
la lettera C o il carattere * in col.1 indicano "commento"
Col.1-5: label istruzione (sempre di tipo numerico)
6
qualsiasi carattere diverso da 0 indica "continuazione della riga
precedente"
7
8
.
.
72
ISTRUZIONE FORTRAN
Questa rigidità di formato è superata nel fortran 90:
non ci sono più colonne riservate
3.
possono esserci più istruzioni sulla stessa riga (separate da ;)
possono esserci commenti sulla stessa riga dell'istruzione (il commento
inizia con !)
il carattere & in fondo ad una riga indica che l'istruzione prosegue sulla
riga successiva.
Nel fortran 77 i nomi dei programmi e/o delle variabili, possono essere costituiti al
max da 6 lettere e/o cifre e devono sempre iniziare con una lettera. Gli spazi bianchi
non sono considerati, quindi le 3 istruzioni seguenti sono uguali:
PROGRAM ESEMPIO , PROGRAMESEMPIO , P R O G R A M E S E M P I O
Il fortran 90 riconosce fino a 31 caratteri ed ammette anche alcuni caratteri
speciali come _ e $. Attribuisce un significato allo spazio bianco.
SCHEMA DI UN "MAIN PROGRAM"
[PROGRAM nome-programma]
Istruzione opzionale, ma raccomandata
Direttive per il compilatore
dichiarazione e dimensionamento variabili, etc.
non danno luogo a codice macchina
Istruzioni eseguibili
END [PROGRAM [nome-programma]]
Sottopogrammi
(subroutine e function)
Esempio:
Program norma_euclidea
! Calcolo della norma euclidea di un vettore
! DIRETTIVE PER IL COMPILATORE! ============================! dichiarazione variabili integer:: n,i real, dimension(100):: x real:: s
! ISTRUZIONI ESEGUIBILI! =====================! input dei dati do print *, 'n =?' read *, n if ((n.gt.0).and.(n.le.100)) exit end do read *, (x(i), i=1,n)
! calcolo della norma s=0. do i=1,n s = s + x(i)**2 end do s = sqrt(s)
! output del risultato print *, s
stop end program norma_euclidea
I 6 TIPI DI DATI INTRINSECI
INTEGER(kind=4), o INTEGER
Numeri interi. Sono rappresentati esattamente nella memoria del computer all'interno di
un determinato intervallo di definizione (range), che dipende dalla dimensione della
locazione di memoria utilizzata: se la locazione di memoria è di n bit, l'intervallo di
definizione dei numeri interi andrà da -2
n-1
a 2
n-1
-1.
Un intero con kind=4 è memorizzato in 4 byte.
REAL(kind=4), o REAL
Numeri reali in singola precisione. Sono rappresentati nella memoria del computer in
maniera approssimata utilizzando la tecnica di memorizzazione in virgola mobile, o
floating point: viene specificata una base (mantissa) e un esponente, che indica la
potenza di 10 per la quale la base deve essere moltiplicata.
Un reale con kind=4 è memorizzato in 4 bytes. Un numero prefissato di bit è destinato
alla mantissa (che definisce la precisione, ovvero il numero di cifre significative) e un
numero prefissato di bit è destinato all'esponente (che definisce il range, ovvero
l'ordine di grangezza). Per numeri reali in singola precisione si hanno 6 cifre
significative con range da 10
-37
a 10
+37
.
Es.: 1. , -27.315 , 0. , 7.5E+02 , 5.E-07
REAL(kind=8), o DOUBLE PRECISION
Numeri reali in doppia precisione. Sono memorizzati utilizzando una locazione di
memoria di dimensione doppia rispetto alla locazione di memoria utilizzata per
memorizzare i numeri reali in singola precisione. Un reale con kind=8 è memorizzato in
8 bytes, ha 15 cifre significative e range da 10
-307
a 10
+307
.
Es.: -1D-7 , 8.45D4 , -15.7685D0
COMPLEX
Numeri complessi, rappresentati da una coppia ordinata di numeri reali.
Es.: (3.5 , -3.) , (2.76E4 , -25E-2)
LOGICAL
Variabili logiche. Possono assumere i valori .TRUE. o .FALSE.
CHARACTER(len=n) (o CHARACTER*n)
Stringhe di caratteri alfanumerici. Ogni carattere viene memorizzato secondo il suo
codice ASCII ed occupa 1 byte.
Es.: CHARACTER(len=5) NOME ; NOME = 'Carla'
Le funzioni KIND, HUGE, RANGE, PRECISION
Program interi_e_reali! VARIABILI INTEGER
print *, "Per il tipo INTEGER" ! numero di byte occupati in memoria print *, "KIND = ", kind(1) ! valore max print *, "HUGE = ", huge(1) print *
! VARIABILI REAL print *, "Per il tipo REAL" ! numero di byte occupati in memoria print *, "KIND = ",kind(1.0) ! valore max print *, "HUGE = ", huge(1.0) ! numero di cifre significative e range print *, "PRECISION = ",precision(1.0) print *, "RANGE = ",range(1.0) print *
! VARIABILI DOUBLE PRECISION print *, "Per il tipo DOUBLE PRECISION"! numero di byte occupati in memoria print *, "KIND = ",kind(1.d0) ! valore max print *, "HUGE = ", huge(1.d0) ! numero di cifre significative e range print *, "PRECISION =",precision(1.d0) print *, "RANGE = ",range(1.d0)end program interi_e_reali
Output del programma Per il tipo INTEGER KIND = 4 HUGE = 2147483647
Per il tipo REAL KIND = 4 HUGE = 3.402823E+38 PRECISION = 6 RANGE = 37
Per il tipo DOUBLE PRECISION KIND = 8 HUGE = 1.79769313486232D+308 PRECISION = 15 RANGE = 307
DICHIARAZIONE DI VARIABILI SCALARI DI TIPO
INTRINSECO
Dichiarazione esplicita
TIPO:: lista variabili
ESEMPIO: INTEGER :: i,j REAL :: a,bCHARACTER(len=5):: nomeCHARACTER(len=4):: idLOGICAL:: condizione
o anche INTEGER i,jREAL a,betc.
Dichiarazione implicita
in mancanza di una dichiarazione esplicita di variabile, il compilatore fortran
applica la così detta "regola del nome", assumendo che la variabile sia intera
se il suo nome inizia con una lettera compresa in (I-N) e che sia reale altrimenti.
La "regola del nome" può essere modificata definendo una nuova serie di tipi
impliciti per mezzo della direttiva IMPLICIT.
Ad esempio utilizzando la direttiva:
IMPLICIT REAL(A-D,W), INTEGER(H-L), LOGICAL(M-P)
si potranno utilizzare le seguenti variabili di tipo implicito:
ALE, WORK, C di tipo REALH, LEN di tipo INTEGERMAI di tipo LOGICAL
La direttiva IMPLICIT deve comparire prima di qualunque altra dichiarazione
esplicita.
È consigliabile dichiarare esplicitamente tutte le variabili, utilizzando la direttiva
IMPLICIT NONE da mettere prima di tutte le altre dichiarazioni esplicite di variabili.
DEFINIZIONE DI COSTANTI
Un'altra importante direttiva per il compilatore è la direttiva PARAMETER che
permette la definizioni delle costanti. La sintassi dell'istruzione è la seguente:
TIPO, PARAMETER:: nome = espressione
ESEMPI: REAL, PARAMETER:: zero = 1.E-7INTEGER, PARAMETER:: N=100REAL, PARAMETER:: PI=acos(-1.), P34=3*PI/4
La definizione di una costante tramite la direttiva PARAMETER presenta alcune
fondamentali differenze rispetto ad una normale istruzione di assegnazione (ad es.
N = 100):
il valore assegnato con una istruzione PARAMETER non occupa spazio in
memoria (non viene memorizzato in una variabile), ma viene utilizzato
direttamente dal compilatore nella traduzione del programma sorgente in
codice binario;
il valore assegnato ad una costante con una istruzione PARAMETER non può
essere modificato né con una istruzione di assegnazione né con un'altra
istruzione PARAMETER;
le costanti definite con una istruzione PARAMETER possono essere utilizzate
per dimensionare array non rilocabili.
TIPI DI DATI PARAMETRIZZATI
Il programmatore può definire numeri reali con una precisione e/o un range diversi
da quella dei reali in singola e in doppia precisione tramite la funzione
SELECTED_REAL_KIND. Questa funzione restituisce in output il numero di byte
(KIND) necessario per memorizzare un tipo reale con la precisione ed il range
richiesti.
Se ad esempio, si vuole lavorare con almeno 18 cifre sigificative in un range in
valore assoluto compreso fra 10
-30
e 10
30
si potranno utilizzare le seguenti
dichiarazioni:
INTEGER, PARAMETER :: mio_reale = SELECTED_REAL_KIND (18,30) REAL(KIND=mio_reale):: a,b,c
Anche per gli INTEGER è possibile ridefinire l'intervallo di ammissibilità tramite la
funzione SELECTED_INT_KIND.
Se ad esempio si desidera lavorare con numeri interi fino a 12 cifre, ovvero
compresi nell'intervallo [-999999999999, +999999999999], si potranno utilizzare le
seguenti dichiarazioni:
INTEGER, PARAMETER :: mio_intero = SELECTED_INT_KIND(12) INTEGER(KIND=mio_intero):: i,j
OPERATORI
Operatore di assegnazione (nome = espressione )
ESEMPIO: S=A+B ; C=C+1 ; A=20
Operatori aritmetici
** elevamento a potenza priorità alta
* moltiplicazione priorità media
/ divisione priorità media
+ addizione priorità bassa
- sottrazione priorità bassa
a parità di priorità ed in mancanza di parentesi le operazioni sono
eseguite da sinistra a destra, ad eccezione dell'operazione di elevamento
a potenza:
A**B**C equivale a A**(B**C)
se un operatore aritmetico opera su operandi di tipo diverso, prima del
calcolo dell'espressiome, tutti gli operandi vengono convertiti nel tipo di
"ordine maggiore" (integer -> real -> double precision -> complex)
nella divisione fra interi il risultato viene troncato
un'espressione reale memorizzata in una variabile intera viene troncata
(esempio: I = 5.6*2 --> I=11)
Operatori di relazione
.EQ. .NE. .LT. .LE. .GT. .GE.
== /= o <> < <= > >=
Operatori logici
.NOT. .AND. .OR.
Operatore di concatenazione stringhe (solo in fortran 90): //
ESEMPIO:Program esempio_concatenazione_stringhe implicit none character(len=20):: nome, ext, nome_file nome='myprog'; ext='f90'! la funzione trim() riporta la stringa senza gli spazi finali nome_file=trim(nome)//'.'//trim(ext) print *, nome_fileend program esempio_concatenazione_stringhe
ESPRESSIONI
aritmetiche
costanti o variabili numeriche separate da operatori aritmetici
di relazione
costanti o variabili di qualsiasi tipo separate da operatori di relazione
logiche
costanti o variabili logiche separate da operatori logici
In mancanza di parentesi vengono prima calcolate le espressioni aritmetiche,
quindi quelle di relazione ed infine quelle logiche.
ESEMPIO:REAL:: a,b,cLOGICAL:: cond1, cond2, trovato
cond1 = (a*b) .EQ. ccond2 = (.NOT.(a == b)) .AND. (b < c)IF ((cond1) .AND. (.NOT.cond2)) .......
....................................IF ((.NOT.tovato).AND.(a > b)) .......
ESEMPIO:Program esempio_uso_logical implicit none integer:: a,b logical:: AmaggioreB
print *, "inserisci a, b" read *, a,b AmaggioreB = a.gt.b print *, "a>b ? ", AmaggioreBend program esempio_uso_logical
SCELTE E DECISIONI
1. IF LOGICO
IF statement
IF (espressione logica) istruzione
ESEMPI: IF (x<0) x=0IF (.not.condizione) GOTO 10IF (condizione.OR.((a.GT.b).AND.(b.LE.0))) a=a+1
IF construct
IF (condizione) THEN
blocco istruzioni
END IF
IF (condizione) THEN
blocco_1
ELSE
blocco_2
END IF
IF (condizione1) THEN
blocco_1
ELSE IF (condizione2) THEN
blocco_2
ELSE IF ......
........
ELSE
blocco_n
END IF
ESEMPIO 1: ! f(x)= funzione caratteristica dell'intervallo [a,b]
IF ((x>=a).AND.(x<=b)) THEN f=1ELSE f=0END IF
ESEMPIO 2: ! f(x)= segno(x) (-1 per x<0, 0 per x=0, 1 per x>0)
IF (x<0) THEN f=-1ELSE IF (x=0) THEN f=0ELSE f=1END IF
2. IF ARITMETICO
IF (espressione aritmetica) label
1
, label
2
, label
3
Il controllo del programma salterà a label
1
se l'espressione aritmetica è negativa, a
label
2
se l'espressione aritmetica è nulla, a label
3
se l'espressione aritmetica è
positiva.
Sintassi obsoleta tipica del fortran 77.
ESEMPI: IF (x) 10,20,30 IF (A-B) 10,10,50
Utilizzando un IF aritmetico, la funzione caratteristica dell'intervallo [a,b] diventa:
C f(x)= funzione caratteristica dell'intervallo [a,b] IF ((x-a)*(b-x)) 10,20,2010 f=0 GOTO 2120 f=121 .......
3. CASE
Il costrutto CASE permette di scegliere fra diverse opzioni. La sintassi è la
seguente:
SELECT CASE (espressione)CASE (scelta_1)
blocco_1..CASE (scelta_n)
blocco_n
END SELECT
L'espressione che appare nell'istruzione SELECT CASE deve essere uno
scalare di tipo INTEGER, CHARACTER o LOGICAL.
Nel caso di espressioni di tipo INTEGER o CHARACTER i valori scelta_1 ...
scelta_n nelle selezioni CASE possono essere degli intervalli espressi nella
forma (valore_min : valore_max) se valore_min è assente vengono selezionati
tutti i valori minori o uguali a valore_max; se valore_max è assente vengono
selezionati tutti i valori maggiori o uguali a valore_min.
la forma generale dei selettori scelta_1 ... scelta_n è una lista di valori e di
intervalli dello stesso tipo, senza sovrapposizioni, come ad esempio
(3, 7, 9:15, 20, 30:)
L'espressione CASE DEFAULT serve a selezionare tutti i valori non inclusi
nelle altre selezioni CASE
ESEMPIO 1:SELECT CASE (I)CASE (:-1) ! I <= -1 segno = -1CASE (0) ! I = 0 segno = 0CASE (1:) ! I >= +1 segno = 1END SELECT
ESEMPIO 2:PROGRAM CARATTERECHARACTER:: CHARCHARACTER(len=10):: TIPO_CHAR
READ *, CHARSELECT CASE (CHAR)CASE (0:9) TIPO_CHAR = 'numerico'CASE (a:z)
TIPO_CHAR = 'minuscolo'CASE (A:Z)
TIPO_CHAR = 'maiuscolo'CASE DEFAULT
TIPO_CHAR = 'altro'END SELECTPRINT *, TIPO_CHAR
STOP END
ESEMPIO 3:Program esempio_uso_case implicit none character(len=25):: domanda,nome character(len=10):: lingua character (len=13):: risposta
print *,"scegli la lingua (inglese,italiano, spagnolo,francese)" read *, lingua select case (lingua) case ('italiano') domanda = 'come ti chiami?' risposta = 'Salve ' case ('spagnolo') domanda ='Como te llamas?' risposta = 'Buenos dias ' case ('francese') domanda ='comment t''appelles-tu?' risposta = 'Bonjour ' case default domanda ='what is your name?' risposta = 'Good Morning ' end select print *, domanda read *, nome ; print *,risposta, nome stopend program esempio_uso_case
ESECUZIONI CICLICHE
1. CICLO con contatore
La forma generale di un ciclo con contatore in fortran 90 è:
DO contatore=val_iniziale, val_finale [,step]
. . . . .
. . . . .
blocco istruzioni
. . . . .
. . . . .
END DO
contatore è una variabile di tipo integer;
val_iniziale, val_finale, step sono variabili/costanti/espressioni di tipo
integer;
step è opzionale (se non c'è, si assume step=1)
ESEMPIO: do i=1,n print *, i end do
In fortran 77 non si usa l'istruzione END DO.
L'istruzione di apertura di un ciclo con contatore diventa:
DO label_fine_ciclo contatore=valore_iniziale, valore_finale [,step]
label_fine_ciclo è l'etichetta che identifica l'ultima istruzione del ciclo.
ESEMPIO: do 10 i=1,n print *, i 10 continue
Alcune osservazioni:
non si può saltare all'interno di un ciclo DO senza eseguire l'istruzione di
apertura del ciclo;
la variabile DO (il contatore) non può essere modificata all'interno del
ciclo DO;
quando non si usa END DO, l'ultima istruzione del ciclo deve essere
"compiuta" in se stessa e non deve bloccare l'esecuzione del programma.
Non sono quindi ammesse le istruzioni: STOP, END, PROGRAM, DO.
Spesso per chiudere un ciclo (in fortran 77) viene usata l'istruzione CONTINUE;
è possibile costruire cicli DO annidati; il ciclo DO aperto "internamente"
deve essere chiuso prima (o insieme) al ciclo DO aperto "esternamente";
in un ciclo DO si possono utilizzare le istruzioni:
EXIT permette di uscire dal ciclo, trasferendo il controllo alla prima
istuzione dopo END DO;
CYCLE trasferisce il controllo all'istruzione END DO e, se il ciclo non è
giunto al termine, inizia una nuova iterazione;
è possibile etichettare l'istruzione di apertura di un ciclo
ESEMPIO 1:ciclo1: do i=1,n ..... istruzioniciclo2: do j=1,m ..... istruzioni if (condizione) exit --> esce da ciclo2 ..... istruzioni end do ciclo2 ..... istruzioni end do ciclo1
ESEMPIO 2:ciclo1: do i=1,n ..... istruzioniciclo2: do j=1,m ..... istruzioni if (condizione) exit ciclo1--> esce da ciclo1 ..... istruzioni end do ciclo2 ..... istruzioni end do ciclo1
2. CICLO con uscita su condizione
! ciclo di tipo while
DO WHILE (condizione)
. . . . .
blocco istruzioni
. . . . .
END DO
! ciclo di tipo repeat ... until
DO
. . . . .
blocco istruzioni
. . . . .
IF (condizione) EXIT
END DO
Nel ciclo while il blocco di istruzioni, che viene ripetuto fintanto che la
condizione resta vera, potrebbe non essere mai eseguito.
Nel ciclo repeat ... until il blocco di istruzioni, che viene ripetuto fintanto
che la condizione resta falsa, è sempre eseguito almeno una volta.
ESEMPIO ciclo di tipo while: LOGICAL:: convergenza DO WHILE (.NOT.convergenza) ........ | ........ | blocco istruzioni da ripetere ........ | END DO
ESEMPIO ciclo di tipo repeat ... until LOGICAL:: convergenza DO ........ | ........ | blocco istruzioni da ripetere ........ | IF (convergenza) EXIT END DO
In fortran 77 l'istruzione DO WHILE non esiste.
Il ciclo while può essere implementato utilizzando la seguente sintassi:
label1 IF (.NOT.condizione) GO TO label2 ...... blocco istruzioni ......GO TO label1
label2 ........
In fortran 77 l'istruzione DO ... EXIT non esiste.
Il ciclo repeat ... until può essere implementato utilizzando la seguente
sintassi:
label1 ...... blocco istruzioni ......IF (.NOT.condizione) GO TO label1.........
Foglio esercizi n.1
Leggere in input la misura di un angolo in radianti e convertirla in gradi. Stampare a
video il risultato.
1.
Leggere un intero n>=0 e calcolare n!. Stampare a video il risultato.2.
Leggere due interi n, k con 0<=k<=n e calcolare il coefficiente binomiale (n,k) = n!/(k!*
(n-k)!). Stampare a video il risultato.
3.
Leggere un intero n>0 e stampare i primi n termini della successione di fibonacci:
f(1)=1 ; f(2)=1 ; f(i) = f(i-1)+f(i-2), per i=3,...,n
4.
Svolgimento
Program rad2gr! Questo programma converte la misura di un angolo da radianti a gradi implicit none real, parameter :: Pi = acos(-1.0) real :: gradi, radianti print *, "Misura dell'angolo in radianti? " read *, radianti gradi = 180.*radianti/Pi print *, radianti, " radianti = ",gradi," gradi"end program rad2gr
1.
Program fattoriale! attenzione dichiarando la variabile utilizzata per memorizzare! n! come INTEGER, il programma funziona solo con n <= 12, poiche'! per n>13 risulta n! > huge(n) implicit none integer:: n,i,f do print *, 'Calcolo di n! per n = ? (n>=0)' read *,n if (n.ge.0) exit end do f = 1 do i=2,n f= f*i end do print *, 'n! = ',f stop end program fattoriale
2.
Program coefficiente_binomiale! calcola il coefficiente binomiale (n,k) utilizzando! lo schema iterativo:! (n,0) = 1! (n,i) = (n,i-1)*(n-i+1)/i per i=1,...,k implicit none integer:: n,k,bin integer:: i do print *, 'n, k = ? (n>=0, k>=0, n>=k)' read *,n,k if ((k.ge.0).and.(n.ge.k)) exit end do
3.
bin = 1 do i=1,k bin = (bin*(n-i+1))/i end do print *, bin stop end program coefficiente_binomiale
Program fibonacci! Legge in input un intero n>0 e stampa i primi! n termini della successione di fibonacci:! f(1)=1 ; f(2)=1 ; f(i) = f(i-1)+f(i-2), per i=3,...,n implicit none integer:: n, i, f, fm1, fm2 do print *,"Inserire n: (n>0)" read *, n if (n>0) exit end do f=1 ; fm1=0 do i=1,n print *, f fm2=fm1; fm1=f f=fm1+fm2 end do stopend program fibonacci
4.
GLI ARRAY
L'array è una tabella di elementi tutti dello stesso tipo (vettori e matrici fino a 7
dimensioni). Per utilizzare un array è necessario dichiararne il tipo e la dimensione.
La dimensione può essere dichiarata con la direttiva DIMENSION, oppure
direttamente nella dichiarazione di tipo.
ESEMPI: REAL, DIMENSION(50):: X, YLOGICAL, DIMENSION (10,5):: MATINTEGER, PARAMETER :: NMAX=100REAL, DIMENSION(0:NMAX) :: VETREAL a,bINTEGER cDIMENSION a(100), b(10,20), c(15)DOUBLE PRECISION p(-5:5,6,2:11)
Nel dimensionare un array è necessario specificare i valori min e max per gli indici.
Se il valore min non è indicato esplicitamente si assume che questo sia 1. Per riferirsi
ad un elemento dell'array si utilizza il nome dell'array seguito dagli indici, chiusi in
parentesi tonda e separati da virgola. Gli indici possono essere: costanti intere,
variabili intere o espressioni che forniscono un risultato intero.
ESEMPIO: a(I+3), b(5,J*4), p(-3,N,I-2)
ESEMPI di lettura della matrice MAT(10,5):1) read *, MAT <----legge la matrice MAT per colonne2) read *, (MAT(i,j), j=1,5), i=1,10)
3) do i=1,10 read *, (MAT(i,j), j=1,5)
end do
L'array è l'unico tipo di dato "strutturato" disponibile in fortran 77. In fortran 77 tutte
le operazioni sugli array devono essere eseguite elemento per elemento, in fortan 90
invece possono essere eseguite globalmente sull'intero array. Ad esempio, dichiarate
le seguenti matrici
REAL a(10,20), b(10,20), s(10,20)
le seguenti righe di codice fortran 77
DO 10 j=1,20 DO 10 i=1,10 s(i,j) = a(i,j)+b(i,j)
10 CONTINUE
in fortan 90 si riducono alla sola istruzione: s=a+b
In fortran 90 esistono inoltre molte funzioni intrinseche che lavorano sugli array (es.
MAXVAL(x), MINVAL(x), SUM(x), DOT_PRODUCT(x,y), MATMUL(matrix1,matrix2))
GLI ARRAY DINAMICI
Il fortan 90 permette l'utilizzo di ARRAY DINAMICI, tramite l'introduzione dell'attributo
ALLOCATABLE.
ESEMPIO 1: INTEGER n,mREAL, DIMENSION (:,:), ALLOCATABLE :: a..
READ *, n,mALLOCATE (a(n*2,n+m))..DEALLOCATE (a)
.
ESEMPIO 2: Program intervallo ! legge gli estremi di un intervallo [a,b] ! e lo divide in n parti implicit none real:: a,b, com, h real, dimension(:), allocatable:: x integer:: n,i
print *,'Legge gli estremi di un intervallo e', & ' lo divide in n parti'
do print *, 'dammi gli estremi dell''intervallo' read *, a,b if (a.ne.b) exit end do if (a>b) then com=a; a=b; b=com end if do print *, 'n=? (n>0)' read *,n if (n>0) exit end do allocate (x(0:n)) h = (b-a)/n; x(0) = a; print *, a do i=1,n x(i) = x(i-1) + h print *, x(i) end do stop end program
Vedi anche un esempio di utilizzo di funzioni che operano su array
program
arr
ay
implicit none
real, dimension(:,:), allocatable :: mat
integer n,m, i,j
print *
print *, "
ES
EM
PI
DI
UT
ILIZ
ZO
DI
AL
CU
NE
FU
NZ
ION
E C
HE
OP
ER
AN
O S
U A
RR
AY"
print *
print *, "
uti
lizi
amo l
a m
atri
ce m
at(n
,m)"
do
print *, "
n, m
= ?"
read *, n, m
if ((n>0).and.(m>0)) exit
end do
allocate (mat(n,m))
print *, "
ele
men
ti d
ella
mat
rice
per
colo
nna:"
read *, mat
do i=1,n
print *, (mat(i,j), j=1,m)
end do
print *
print *, "
ES
EM
PI
UT
ILIZ
ZO
DI
sum"
print *, "
som
ma
di
tutt
i gli
ele
men
ti d
ell’
arra
y (
scal
are)
:" print *, "
s
um
(mat
) =", sum(mat)
print *, "
som
ma
per
colo
nne
(vet
tore
di
m e
lem
enti
):"
print *, "
s
um
(mat
,1)=", sum(mat,1)
print *, "
som
ma
per
rig
he
(vet
tore
di
n e
lem
enti
):"
print *, "
s
um
(mat
,2)=", sum(mat,2)
print *, "
som
ma
elem
enti
sull
a ri
ga
1 (
scal
are)
:"
print *, "
s
um
(mat
(1,1
:m))
=", sum(mat(1,1:m))
print *, "
som
ma
elem
enti
sull
a co
lonna
3 (
scal
are)
:"
print *, "
s
um
(mat
(1:n
,3))
=", sum(mat(1:n,3))
print *, "
som
ma
elem
enti
posi
tivi
(sca
lare
):"
print *, "
s
um
(mat
,mat
>0)=", sum(mat,mat>0)
print *
print *, "
ES
EM
PI
UT
ILIZ
ZO
DI
pro
duct"
print *, "
pro
dott
o d
i tu
tti
gli
ele
men
ti d
ell’
arra
y (
scal
are)
:" print *, "
p
roduct
(mat
) =", product(mat)
print *, "
pro
dott
o p
er c
olo
nne
(vet
tore
di
m e
lem
enti
):"
print *, "
p
roduct
(mat
,1)=", product(mat,1)
print *, "
pro
dott
o p
er r
ighe
(vet
tore
di
n e
lem
enti
):"
print *, "
p
roduct
(mat
,2)=", product(mat,2)
print *, "
pro
dott
o e
lem
enti
posi
tivi
(sca
lare
):"
print *, "
p
roduct
(mat
,mat
>0)=", product(mat,mat>0)
print *
print *, "
ES
EM
PI
UT
ILIZ
ZO
DI
max
val
e m
axlo
c" print *, "
max
fra
tutt
i gli
ele
men
ti d
ell’
arra
y (
scal
are)
:" print *, "
m
axval
(mat
) =", maxval(mat)
print *, "
max
sull
e co
lonne
(vet
tore
di
m e
lem
enti
):"
print *, "
m
axval
(mat
,1)=",maxval(mat,1)
print *, "
max
sull
e ri
ghe
(vet
tore
di
m e
lem
enti
):"
print *, "
m
axval
(mat
,2)=",maxval(mat,2)
print *, "
indic
i del
max
:" print *, "
m
axlo
c(m
at)=", maxloc(mat)
print *, "
indic
e del
la r
iga
corr
isponden
te a
l m
ax p
er o
gni
colo
nna:"
print *, "
m
axlo
c(m
at,1
)=",maxloc(mat,1)
print *, "
indic
e del
la c
olo
nna
corr
isponden
te a
l m
ax p
er o
gni
riga:"
print *, "
m
axlo
c(m
at,2
)=",maxloc(mat,2)
stop
endMar
11, 10 1
6:3
4P
age 1
/2arr
ay.f
90
OUTPUT DEL PROGRAMMA array.f90
==============================
ESEMPI DI UTILIZZO DI ALCUNE FUNZIONE CHE OPERANO SU ARRAY
utiliziamo la matrice mat(n,m)
n, m = ?
2 3
<−−−−−− DATI IN INPUT
elementi della matrice per colonna:
−1 3
<−−−−−− DATI IN INPUT
2 −4
<−−−−−− DATI IN INPUT
1 5
<−−−−−− DATI IN INPUT
−1.00000000 2.0000000 1.00000000
3.0000000 −4.0000000 5.0000000
ESEMPI UTILIZZO DI sum
somma di tutti gli elementi dell’
arra
y (
scal
are)
: su
m(m
at)
= 6
.0000000
som
ma
per
colo
nne
(vet
tore
di
m e
lem
enti
): su
m(m
at,1
)= 2
.0000000 −
2.0
000000 6
.0000000
som
ma
per
rig
he
(vet
tore
di
n e
lem
enti
): su
m(m
at,2
)= 2
.0000000 4
.0000000
som
ma
elem
enti
sull
a ri
ga
1 (
scal
are)
: su
m(m
at(1
,1:m
))=
2
.0000000
som
ma
elem
enti
sull
a co
lonna
3 (
scal
are)
: su
m(m
at(1
:n,3
))=
6
.0000000
som
ma
elem
enti
posi
tivi
(sca
lare
): su
m(m
at,m
at>
0)=
1
1.0
00000
ES
EM
PI
UT
ILIZ
ZO
DI
pro
duct
pro
dott
o d
i tu
tti
gli
ele
men
ti d
ell’array (scalare):
product(mat) = 120.00000
prodotto per colonne (vettore di m elementi):
product(mat,1)= −3.0000000 −8.0000000 5.0000000
prodotto per righe (vettore di n elementi):
product(mat,2)= −2.0000000 −60.000000
prodotto elementi positivi (scalare):
product(mat,mat>0)= 30.000000
ESEMPI UTILIZZO DI maxval e maxloc
max fra tutti gli elementi dell’
arra
y (
scal
are)
: m
axval
(mat
) =
5
.0000000
max
sull
e co
lonne
(vet
tore
di
m e
lem
enti
): m
axval
(mat
,1)=
3
.0000000 2
.0000000 5
.0000000
max
sull
e ri
ghe
(vet
tore
di
m e
lem
enti
): m
axval
(mat
,2)=
2
.0000000 5
.0000000
indic
i del
max
: m
axlo
c(m
at)=
2
3
indic
e del
la r
iga
corr
isponden
te a
l m
ax p
er o
gni
colo
nna:
m
axlo
c(m
at,1
)= 2
1
2
indic
e del
la c
olo
nna
corr
isponden
te a
l m
ax p
er o
gni
riga:
m
axlo
c(m
at,2
)= 2
3
Mar
11, 10 1
6:3
4P
age 2
/2a
rra
y.f
90
Printe
d b
y A
lessandra
Seghin
i
Thurs
day M
arc
h 1
1, 2010
1/1
arr
ay.f90
Foglio esercizi n.2
Leggere un numero n>=2 e stampare tutti i numeri primi <=n (per trovare i numeri
primi utilizzare il 'crivello di Eratostene').
1.
Leggere un numero n>=0 e stampare le prime (n+1) righe del triangolo di Tartaglia.2.
Esercizio 1 della prova d'esame 3/2007 (senza subroutine e con stampa a video)3.
Esercizio 1 della prova d'esame 3/2004 (senza subroutine e con stampa a video)4.
Svolgimento
Program crivello_eratostene!! Utilizzando il "crivello di Eratostene" stampa tutti i numeri primi <= n.! Il "crivello di Eratostene" fornisce un algoritmo efficiente per l'individuazione ! dei numeri primi: partendo da 2 (primo) si eliminano tutti i multipli di 2.! Quindi si prende il primo numero non eliminato, 3 (primo), e si eliminano tutti i ! multipli di 3 e cosi` via.!implicit noneinteger:: n,i,j,maxfattlogical, dimension (:),allocatable:: primoprint *,"Stampiamo tutti i numeri primi minori di n, n>=2"do print *, "Inserire n: (n>=2)" read *,n if (n.ge.2) exitend doallocate (primo(2:n))primo=.true.maxfatt=int(sqrt(real(n)))do i=2,maxfatt if (.not.primo(i)) cycle do j=i+i, n, i primo(j)=.false. end doend dodo i=2,n if (primo(i)) print *, iend dostop end program crivello_eratostene
1.
Vengono proposte due diverse soluzioni:
-------------------------- soluzione 1 --------------------------program tartaglia1! Stampa delle prime (n+1) righe del triangolo di Tartaglia! si usa un vettore per memorizzare la riga i-esima del triangolo, ! ma non viene sfruttata la simmetria del triangolo di tartaglia!implicit noneinteger, dimension(:), allocatable :: tinteger :: i, j, nprint *, "Stampa delle prime (n+1) righe del triangolo di Tartaglia"do print *, "n=? (n>=0"
2.
read *,n if (n.ge.0) exitend doallocate (t(0:n)); t=0do i=0,n t(i) = 1 do j=i-1, 1, -1 t(j) = t(j)+t(j-1) end do print *, (t(j), j=0,i)end doend program tartaglia1
-------------------------- soluzione 2 --------------------------program tartaglia2! Stampa delle prime (n+1) righe del triangolo di Tartaglia! si usa un vettore per memorizzare la riga i-esima del triangolo! e si sfrutta la simmetria del triangolo!implicit noneinteger, dimension(:), allocatable :: tinteger :: i, j, n, imezzi, im1mezziprint *, "Stampa delle prime (n+1) righe del triangolo di Tartaglia"do print *, "n=? (n>=0)" read *,n if (n.ge.0) exitend doallocate (t(0:n/2)); t=0t(0)=1; print *, t(0)do i=1,n imezzi=i/2; im1mezzi = (i-1)/2 if (mod(i,2)==0) t(imezzi) = t(imezzi-1)*2 do j= im1mezzi, 1, -1 t(j) = t(j)+t(j-1) end do print *, (t(j), j=0,imezzi), (t(j), j=im1mezzi,0,-1) print *, end doend program tartaglia2
TIPI DI DATI DERIVATI
Il fortan 90 consente la definizione di nuovi tipi di dati derivati da combinazione
dei tipi già esistenti.
ESEMPIO 1: ! definizione del tipo persona type persona
character(len=20) cognome, nome integer eta end type persona
! dichiarazione della var studente di tipo persona type (persona):: studente
studente%cognome='Rossi'
studente%nome='Mario' studente%eta=20 oppure studente = persona('Rossi','Mario',20)
read *, studente%cognome, studente%nome, studente%eta oppure read *, studente
ESEMPIO 2: type punto ! definizione del tipo punto real x,y end type punto
type cerchio ! definizione del tipo cerchio type (punto) c real r end type cerchio
! dichiarazione della var gamma di tipo cerchio type (cerchio):: gamma
! gamma e' il cerchio di centro l'origine e raggio 1 gamma%c%x = 0.; gamma%c%y = 0.; gamma%r = 1.
oppure gamma = cerchio(punto(0.,0.), 1.)
ESEMPIO 3: program esempio_tipi_derivati implicit none
type punto real x,y end type punto
type cerchio type (punto) c real r end type cerchio
type rettangolo type (punto) downleft real base, altezza end type rettangolo
type (punto) :: P type (cerchio) :: c1,c2,c3 type (rettangolo):: r real diag
print *, 'Coordinate del punto P?' ! read *, P%x, P%y !..... o piu` brevemente read *, P print *, 'punto P', P
print *, 'Cerchio c1:' print *, 'coordinate del centro?'; read *, c1%c%x, c1%c%y print *, 'lunghezza del raggio?'; read *, c1%r print *, 'centro e raggio di c1', c1
print *, 'Cerchio c2:' print *, 'coordinate del centro e raggio?'; read *, c2 print *, 'centro e raggio di c2', c2
c3 = cerchio(punto(-1,1), 10.) print *, 'centro e raggio di c3', c3
r = rettangolo(punto(0,2),3,4) diag = sqrt(r%base**2 + r%altezza**2) print *, 'rettangolo estremo sinistro: ',r%downleft print *, 'base, altezza e diagonale', & r%base, r%altezza, diag
stop end program esempio_tipi_derivati
INIZIALIZZAZIONE AREE DI MEMORIA
Su alcuni sistemi tutte le variabili vengono azzerate automaticamente al
caricamento del programma. Per inizializzare opportunamente le aree di memoria
utilizzate si può utilizzare la direttiva DATA.
DATA lista variabili/lista valori/,lista variabili/lista valori/,..
ovviamente ci deve essere "coerenza" in numero, ordine e tipo fra la lista delle
variabili e la lista dei valori assegnati.
ESEMPI:
REAL a,b,cDATA a,b,c/ 3.2, 5.7, -.5E-4/ o analogamenteDATA a/3.2/,b/5.7/,c/-5.E-4/
REAL sum(10), alfa(3), INTEGER m(5,5)CHARACTER(len=10) nomeDATA sum/10*0./, nome/'giulia'/DATA (alfa(i), i=1,3)/10,20,30/ DATA ((m(i,j), i=1,5), j=1,5)/25*0/
L'istruzione DATA viene eseguita al caricamento in memoria del programma prima
dell'inizio dell'esecuzione. È consigliabile collocarla alla fine della parte dichiarativa,
prima delle istruzioni eseguibili.
PROCEDURE: SOTTOPROGRAMMI E FUNZIONI
1. UTILIZZO DI SUBROUTINES
SUBROUTINE nome [(lista parametriformali)]
Direttive per il compilatore
dichiarazionepar.formali,var.locali, var.globali
Istruzioni eseguibili
RETURN
END [SUBROUTINE [nome]]
Nel programma chiamante: CALL nome [(lista parametri attuali)]
Coerenza in numero, ordine e tipo fra la lista dei parametriformali e la lista dei parametri attuali.
Se nella lista dei parametri ci sono vettori, di norma, vienepassata anche la dimensione fra gli argomenti.
ESEMPIO:subroutine dividi_intervallo(p,q,m,y)! divide l'intervallo [p,q] in m parti e restituisce! nel vettore y(0:m) le cordinate degli (m+1) nodi implicit none real:: p, q, y(0:m) integer:: m real:: h integer:: i h = (q-p)/m do i=0,m y(i) = p +i*h end do returnend subroutine dividi_intervallo
..... nel programma chiamante .....
Program intervallo implicit none real:: a,b real, dimension(:), allocatable:: x integer n
........ legge a,b,n
allocate (x(0:n)) call dividi_intervallo(a,b,n,x) print *, xend program intervallo
2. UTILIZZO DI FUNZIONI
[tipo] FUNCTION nome [(lista parametri formali)]
Direttive per il compilatore
Istruzioni eseguibili
RETURN
END [FUNCTION [nome]]
Le funzioni restituiscono al programma chiamante un solovalore.Il tipo della funzione è il tipo della variabile di ritorno. Questa èuna variabile speciale, il cui nome coincide con il nome dellafunzione.Nella sezione eseguibile di una funzione deve sempre esserciun'istruzione del tipo
nome = espressionecon la quale viene assegnato il valore da restituire alprogramma chiamante.
ESEMPIO:
real function distanza (a, b) implicit none real:: a(2),b(2) distanza = sqrt((a(1)-b(1))**2 + (a(2)-b(2))**2) returnend function distanza
..... nel programma chiamante .....
Program esempio_uso_function implicit none real:: p(2),q(2), delta real:: distanza
........ legge p, q
delta = distanza (p,q) print *, deltaend program esempio_uso_function
In fortran 77 Le funzioni costituite da una singola istruzionepossono essere definite come macro-istruzioni utilizzando laseguente sintassi (obsoleta in fortran 90):
nome-funzione(lista parametri formali) = espressione
ESEMPIO: REAL a(2), b(2) REAL distanza distanza(a,b)=sqrt((a(1)-b(1))**2+(a(2)-b(2))**2)
Si chiamano funzioni intrinseche quelle procedure che nondevono essere scritte dal programmatore, ma che già fannoparte del linguaggio stesso. Fra di esse sono comprese tutte leprincipali funzioni matematiche (max, abs, sqrt, exp, sin, cos,etc.). Per una descrizione delle procedure intrinseche, vederead esempio Expanded description of Fortran 90/95 intrinsicprocedures, supplemento al testo "Introduction to Fortran90/95" di S. J. Chapman.
ESEMPI: 1) program calcolo_volume_cilindro implicit none real:: r,h, volume_cil print *, "r,h=?" read *, r,h print *, volume_cil(r,h) stop
end program calcolo_volume_cilindro
real function volume_cil(r,h) implicit none real:: r,h real, parameter :: pi=acos(-1.0) volume_cil=pi*r**2*h return end function volume_cil
2) program controlla_primi ! riceve in input numeri interi e controlla se sono primi implicit none integer:: n logical:: primo do print *, "Inserire n (n<=1 per terminare)" read *,n if (n.le.1) exit if (primo(n)) then print *, n," e` primo" else print *, n," non e` primo" end if end do stop end program controlla_primi
logical function primo(n) implicit none integer:: n integer:: i, maxfatt primo = .true. ! se n e` fattorizzabile, almeno uno dei fattori ! deve essere <= sqrt(n) maxfatt = int(sqrt(real(n))) do i=2,maxfatt if (mod(n,i).eq.0) then primo =.false. exit end if end do return end function primo
3) program norma_di_frobenius_di_una_matrice implicit none
integer:: n real, dimension (:,:), allocatable :: a real:: frobenius_norm do print *, "Inserisci n:" read *,n if (n.gt.0) exit end do allocate (a(n,n)) print *, "Inserisci la matrice a per colonne:" read *,a print *, "Norma di Frobenius di a: ",frobenius_norm(n,a) stop end program norma_di_frobenius_di_una_matrice
real function frobenius_norm(n,a) implicit none integer:: n real, dimension(n,n) :: a integer:: i,j real:: s s = 0. do i=1,n do j=1,n s = s + a(i,j)*a(i,j) end do end do frobenius_norm = sqrt(s)! o piu' brevemente, avendo dichiarato ! real, dimension(n,n) :: b! b=a*a; frobenius_norm=sqrt(sum(b)) return end function frobenius_norm
Vedi Foglio esercizi 3
3. L'ATTRIBUTO INTENT ED IL BLOCCO INTERFACE
Per ciascuno dei parametri formali che una procedura scambia conil programma chiamante, è possibile utilizzare l'attributo INTENTper specificare se il parametro è di input INTENT(in), di outputINTENT(out) o di input/output INTENT(inout).Un parametro con attributo INTENT(in) non può essere modificatodalla procedura. Un parametro con attributo INTENT(out) assumeun valore non definito al momento della chiamata alla procedura.
Tramite la direttiva INTERFACE è possibile fornire ad una unità di
programma un blocco di interfaccia, contenente le informazionirelative alle procedure da esso richiamate.
ESEMPI:1) program lati_triangolo ! Riceve in input le coordinate dei 3 vertici di ! un triangolo e stampa la lunghezza dei 3 lati. implicit none real A(2),B(2),C(2) ! coordinate dei 3 vertici real l1,l2,l3 ! lunghezze dei 3 lati interface subroutine calcola_lati(A,B,C,l1,l2,l3) real, intent(IN) :: A(2), B(2), C(2) real, intent(OUT) :: l1,l2,l3 end subroutine calcola_lati end interface print *, 'dammi le coordinate dei 3 vertici' read *, A, B, C call calcola_lati(A,B,C,l1,l2,l3) print *, l1,l2,l3 end program lati_triangolo
subroutine calcola_lati(A,B,C,l1,l2,l3) implicit none real, intent(IN) :: A(2), B(2), C(2) real, intent(OUT) :: l1,l2,l3 interface real function distanza (P,Q) real, intent(IN) :: P(2),Q(2) end function distanza end interface l1 = distanza(A,B) l2 = distanza(B,C) l3 = distanza(C,A) return end subroutine calcola_lati
2) Vedi svolgimento esercizio 1 del foglio n.3 (area triangolo) con utilizzo di INTENT e INTERFACE.
Vedi Foglio esercizi 4 e Foglio esercizi 5
Foglio esercizi n.3
Scrivere un programma che legga le coordinate di 3 punti del piano, verifichi tramite
un'apposita logical function che i 3 punti non siano allineati e calcoli tramite
un'apposita function l'area del triangolo.
Se i 3 punti sono allineati, mandare un messaggio a schermo.
Suggerimenti:
- condizione di allineamento per 3 punti A=(a1,a2), B=(b1,b2), C=(c1,c2)
(a1-b1)*(c2-b2)=(a2-b2)*(c1-b1)
- formula di Erone per il calcolo dell'area di un triangolo
Area = sqrt(p*(p-l1)*(p-l2)*(p-l3)), con p = semiperimetro, l1,l2,l3 = lati del
triangolo
- per calcolare la lunghezza dei lati scrivere una funzione che calcoli la distanza fra
due punti del piano.
1.
Leggere un intero n>=2 e stampare a video la sua scomposizione in fattori primi
(prima di iniziare la scomposizione, richiamare un'apposita subroutine per individuare
tramite il 'crivello di Eratostene' tutti i numeri primi <= n).
2.
Data una matrice reale A(n,m), scrivere una logical function per verificare che per ogni
riga della matrice A, gli elementi sulla riga siano tutti distinti. Scrivere il main program
per testare la function.
3.
Esercizio 2 della prova d'esame 3/20054.
Esercizio 1 della prova d'esame 2/2006 (con stampa a video)5.
Esercizio 1 della prova d'esame 1/20076.
Svolgimento
Program area_triangolo! Dati 3 punti A,B, C verifica che i 3 punti non siano allineati ! e calcola l'area del triangolo ABC utilizzando la formula di Erone! Area = sqrt(P*(P-L1)*(P-L2)*(P-L3))! con P = semiperimetro, L1,L2,L3 = lati del triangoloimplicit nonereal:: a(2),b(2),c(2), arealogical:: allineatiprint *, 'coordinate del I vertice'; read *, aprint *, 'coordinate del II vertice'; read *, bprint *, 'coordinate del III vertice'; read *, cif (.not.allineati(a,b,c)) then print *, 'area = ', area(a,b,c)else print *, 'punti allineati'end ifstopend program area_triangolo
logical function allineati(a,b,c) implicit none real a(2),b(2),c(2) real com allineati=.false.
1.
com = (a(1)-b(1))*(c(2)-b(2))-(a(2)-b(2))*(c(1)-b(1)) if (com.eq.0) allineati=.true. returnend function allineati
real function area(a,b,c) implicit none real a(2),b(2),c(2) real l1,l2,l3, p real distanza l1 = distanza(a,b) ; l2 = distanza(a,c) ; l3 = distanza(b,c) p =(l1+l2+l3)/2 area = sqrt(p*(p-l1)*(p-l2)*(p-l3)) returnend function area
real function distanza(x,y) implicit none real x(2),y(2) distanza = sqrt((x(1)-y(1))**2 + (x(2)-y(2))**2) returnend function distanza
Vedi anche una soluzione dell'esercizio 1 in cui si utilizzano le direttive INTENT e INTERFACE.
Program scomponi_in_fattori_primi! Legge un intero n>=2 e lo scompone in fattori primi.! Prima di iniziare a scomporre n, si utilizza il crivello di eratostene ! per individuare tutti i numeri primi <= n. implicit noneinteger:: n, m, i, maxfattlogical, dimension(:), allocatable:: primo do print *, 'n = ? (n>=2)' read *, n if (n>=2) exitend doallocate (primo(2:n))call eratostene(n,primo) ! individua tutti i numeri primi <= n if (primo(n)) then print *, n, " e' un numero primo"else print *, 'scomposizione in fattori primi di n = ', n m = n maxfatt=int(n/2) do i=2,maxfatt if (.not.primo(i)) cycle do while (mod(m,i).eq.0) print *, i m = m/i end do if (m.eq.1) exit end doend ifend program scomponi_in_fattori_primi
subroutine eratostene(n,primo) implicit none integer n logical primo(2:n) integer i,j,maxfatt
2.
primo=.true. maxfatt = int(sqrt(real(n))) do i=2,maxfatt if (.not.primo(i)) cycle do j=i+i,n,i primo(j)=.false. end do end do returnend subroutine eratostene
Program controlla_matrice! Controlla che su ogni riga della matrice A, gli elementi siano! tutti distinti implicit none integer:: n,m,i,j real, dimension(:,:), allocatable :: a logical:: elementi_righe_distinti do print *, "dammi n e m (n>0, m>0)" read *, n, m if ((n>0).and.(m>0)) exit print *, "immettere n e m positivi" end do allocate (a(n,m)) print *, "elementi della matrice A per riga" do i=1,n read *, (a(i,j), j=1,m) end do if (elementi_righe_distinti(n,m,a)) then print *, "su ogni riga, gli elementi sono tutti distinti" else print *, "ci sono righe con elementi non tutti distinti" endif stopend program controlla_matrice
logical function elementi_righe_distinti(n,m,a) implicit none integer n,m,i,j,k,mm1 real, dimension(n,m) :: a real ele mm1=m-1 elementi_righe_distinti=.false. do i=1,n do j=1,mm1 ele = a(i,j) do k=j+1,m if (ele == a(i,k)) return end do end do end do elementi_righe_distinti=.true. returnend
3.
Esempio di utilizzo INTENT e INTERFACE
Si propone una soluzione dell'esercizio 1 del foglio n.3 con utilizzo di INTENT e
INTERFACE.
Esercizio
Scrivere un programma che legga le coordinate di 3 punti del piano, verifichi tramite
un'apposita logical function che i 3 punti non siano allineati e calcoli tramite
un'apposita function l'area del triangolo.
Se i 3 punti sono allineati, mandare un messaggio a schermo.
Suggerimenti:
- condizione di allineamento per 3 punti A=(a1,a2), B=(b1,b2), C=(c1,c2)
(a1-b1)*(c2-b2)=(a2-b2)*(c1-b1)
- formula di Erone per il calcolo dell'area di un triangolo
Area = sqrt(p*(p-l1)*(p-l2)*(p-l3)), con p = semiperimetro, l1,l2,l3 = lati del
triangolo
- per calcolare la lunghezza dei lati scrivere una funzione che calcoli la distanza fra
due punti del piano.
Svolgimento
Program area_triangolo! Dati 3 punti A,B, C verifica che i 3 punti non siano allineati ! e calcola l'area del triangolo ABC utilizzando la formula di Erone! Area = sqrt(P*(P-L1)*(P-L2)*(P-L3))! con P = semiperimetro, L1,L2,L3 = lati del triangolo!! Nel programma si utilizzano le direttive INTENT e INTERFACEimplicit nonereal:: a(2),b(2),c(2)interface function allineati(a,b,c) logical:: allineati real, intent(in) :: a(2),b(2),c(2) end function allineati
function area(p1,p2,p3) real:: area real, intent(in):: p1(2),p2(2),p3(2) end function area end interface
print *, 'coordinate del primo vertice:'; read *, aprint *, 'coordinate del secondo vertice:'; read *, bprint *, 'coordinate del terzo vertice:'; read *, cif (allineati(a,b,c)) then print *, 'I punti sono allineati'else print *, 'Area totale = ', area(a,b,c)end ifstopend program area_triangolo
function allineati(a,b,c) implicit none logical:: allineati real, intent(in) :: a(2),b(2),c(2) real:: prova allineati=.false. prova=(c(1)-a(1))*(b(2)-a(2))-(c(2)-a(2))*(b(1)-a(1)) if (prova==0) allineati=.true. returnend function allineati
function area(p1,p2,p3) implicit none real:: area real, intent(in):: p1(2),p2(2),p3(2) real:: l1,l2,l3,semip interface function distanza (p1,p2) implicit none real :: distanza real, intent(in) :: p1(2), p2(2) end function distanza end interface l1=distanza(p1,p2) l2=distanza(p2,p3) l3=distanza(p3,p1) semip=(l1+l2+l3)/2 area = sqrt(semip*(semip-l1)*(semip-l2)*(semip-l3)) returnend function area
function distanza(p,q) implicit none real:: distanza real, intent(in):: p(2),q(2) distanza=sqrt(((p(1)-q(1))**2)+(p(2)-q(2))**2) returnend function distanza
Foglio esercizi n.4
Dato un polinomio di grado n a coefficienti reali
P(x) = p
n
x
n
+ p
n-1
x
n-1
+ ....... + p
1
x + p
o
scrivere una function che calcoli il valore del polinomio P(x) in un punto assegnato x
o
;1.
scrivere una function che calcoli la derivata del polinomio P(x) in un punto assegnato x
o
;2.
scrivere una function che calcoli l'integrale definito del polinomio P(x) in un intervallo [a,b].3.
Scrivere il main program per testare le function.
Per calcolare il valore del polinomio in un punto, utilizzare il metodo di Horner:
P(x) = ((((p
n
x + p
n-1
)x + p
n-2
)x + ....... + p
1
)x + p
o
Svolgimento
real function Polinomio (n,P,x)! calcola il valore del polinomio P di grado n nel punto x! utilizzando il metodo di Horner! P(x) = ((((P[n]x+P[n-1])x+P[n-2])x+ .....)x+P[0] implicit none integer:: n real, dimension(0:n):: P real:: x integer i,nm1 Polinomio = P(n) nm1= n-1 do i=nm1,0,-1 Polinomio = Polinomio*x+P(i) end do returnend function Polinomio
1.
Vengono proposte due diverse soluzioni:
---------------------------- soluzione 1 ----------------------------real function Derivata1 (n,P,x)! calcola la derivata del polinomio P di grado n nel punto x, ! utilizzando il metodo di Horner sul polinomio ottenuto derivando P! dP(x) = ((((nP[n]x+(n-1)P[n-1])x+ .....)x+P[1] implicit none integer:: n real, dimension(0:n):: P real:: x integer i,nm1 Derivata1 = n*P(n) nm1= n-1 do i=nm1,1,-1 Derivata1 = Derivata1*x+i*P(i) end do returnend function Derivata1
---------------------------- soluzione 2 ----------------------------real function Derivata2 (n,P,x)! calcola la derivata del polinomio P di grado n nel punto x, ! calcolando i coefficienti del polinomio ottenuto derivando P
2.
! e poi richiamando la function Polinomio() implicit none integer:: n real, dimension(0:n):: P real:: x integer i,nm1,ip1 real DP(0:n-1), Polinomio nm1=n-1 do i=0,nm1 ip1= i+1 DP(i) = P(ip1)*ip1 end do Derivata2 = Polinomio(nm1,DP,x) returnend function Derivata2
Vengono proposte due diverse soluzioni:
---------------------------- soluzione 1 ----------------------------real function Integrale1 (n,P,a,b)! calcola l'integrale definito in [a,b] del polinomio P di grado n,! utilzzando il metodo di Horner sul polinomio ottenuto integrando! IntP(x) = (((P[n]/(n+1))x+P[n-1]/n)x+....+P[0])x! Integrale = IntP(b) - IntP(a) implicit none integer:: n real, dimension(0:n):: P real:: a,b integer i, nm1 real Inta,Intb, com Inta = P(n)/(n+1) ; Intb = Inta nm1=n-1 do i=nm1,0,-1 com = P(i)/(i+1) Inta = Inta*a + com Intb = Intb*b + com end do Inta = Inta*a ; Intb = Intb*b Integrale1 = Intb - Inta returnend function Integrale1
---------------------------- soluzione 2 ----------------------------real function Integrale2 (n,P,a,b)! calcola l'integrale definito in [a,b] del polinomio P di grado n,! calcolando i coefficienti del polinomio ottenuto integrando P! e poi richiamando la function Polinomio() implicit none integer:: n real, dimension(0:n):: P real:: a,b integer i, np1 real IntP(0:n+1), Polinomio np1= n+1 IntP(0) = 0. do i=1,np1 IntP(i) = P(i-1)/i end do Integrale2 = Polinomio(np1,IntP,b) - Polinomio(np1,IntP,a) returnend function Integrale2
3.
Foglio esercizi n.5
Esercizio 1 della prova d'esame 3/2005 (con stampa a video)1.
Esercizio 1 della prova d'esame 1/2006 (con stampa a video)2.
Esercizio 1 della prova d'esame 2/2007 (con stampa a video)3.
Esercizio 1 della prova d'esame 1/2008
Suggerimento: per generare una matrice A(n,n) di numeri interi random compresi fra 0 e
100, usare le seguenti istruzioni (A è dichiarata come matrice intera di ordine n e B come
matrice reale di ordine n):
call random_seed() ! imposta il seed call random_number(B) ! genera una matrice B di numeri random ! compresi fra 0 e 1 A = int(100*B)
4.
Svolgimento
Le soluzioni sono disponibili sulla pagina delle passate prove d'esame.
4. RICORSIVITÀ
In fortran 90 è possibile utilizzare procedure ricorsive, ovvero procedure che
richiamano se stesse, o che richiamano procedure dalle quali sono a loro volta
richiamate.
L'istruzione di apertura di una subroutine ricorsiva dovrà essere:
RECURSIVE SUBROUTINE nome [(lista parametri formali)]
L'istruzione di apertura di una funzione ricorsiva dovrà essere:
RECURSIVE [tipo] FUNCTION nome [(lista parametri formali)] RESULT (nome-risultato)
In fortran 77 non è ammessa la ricorsività.
ESEMPI:1) Funzione per il calcolo di n!
con procedimento iterativointeger function fatt(n) implicit none integer n,i fatt = 1 do i=2,n fatt = fatt*i end do returnend function
con procedimento ricorsivorecursive function fatt1(n) result (f) implicit none integer n, f if (n <= 1) then f = 1 else f = fatt1(n-1)*n end if returnend function
2) Funzione per il calcolo del coefficiente binomiale
con procedimento iterativointeger function bin(n,k) implicit none integer n,k,i bin = 1 do i=1,k bin = bin*(n-i+1)/i end do returnend function
con procedimento ricorsivorecursive function bin1(n,k) result (binomio) implicit none integer n,k, binomio if (k == 0) then binomio = 1 else binomio = bin1(n,k-1)*(n-k+1)/k end if returnend function
5. PROCEDURE COME ARGOMENTI
Un programma chiamante può passare ad una subroutine, per mezzo dei suoi
argomenti, i nomi di altre procedure.
In questo caso il nome della subroutine, della funzione esterna o della funzione
intrinseca passato come parametro deve comparire nella sezione dichiarativa del
programma chiamante con l'attributo EXTERNAL o INTRINSIC, oppure deve
essere dichiarato in un blocco INTERFACE.
La direttiva:
EXTERNAL nome1,nome2,...
dichiara un elenco di procedure (subroutine e/o function) che potranno essere
utilizzate come argomenti attuali (ovvero come parametri di input per altre
procedure).
La direttiva:
INTRINSIC fun1,fun2,...
dichiara un elenco di funzioni intrinseche che potranno essere utilizzate come
argomenti attuali (ovvero come parametri di input per altre procedure).
ESEMPIO: Program esempio integer:: n real:: x
real, external:: fattoriale intrinsic cos
.... .... CALL SUB1 (n,x,cos,fattoriale) .... .... stop end program esempio
SUBROUTINE SUB1 (m,y,f1,f2) integer:: m
real:: y real, external:: f1,f2
....
Vedi due esempi di sottoprogrammi che ricevono una funzione tra i parametri di
input (formula di quadratura dei trapezi e metodo di bisezione per il calcolo degli zeri di
una funzione).
Vedi Foglio esercizi 6
Esempi di sottoprogrammi che ricevono una funzione fra i parametri
di input
Function per il calcolo del valore approssimato dell'integrale di una funzione tramite la
formula composita dei trapezi.
real function IntTrap(a,b,n,f)! Formula di quadratura del trapezio:! [a,b] intervallo di integrazione! h = (b-a)/n passo di integrazione! x(i) = a+i*h , i=1,...,n-1! IntTrap = h*[f(a)/2+f(x(1))+....+f(x(n-1))+f(b)/2] implicit none real a,b ! estremi dell'intervallo integer n real, external:: f real h,x integer i,nm1 h =(b-a)/n IntTrap = (f(a)+f(b))/2 nm1 = n-1 x=a do i = 1,nm1 x = x+h IntTrap = IntTrap + f(x) end do IntTrap = IntTrap*h returnend function IntTrap(a,b,n,f)
Main program che richiama la funzione IntTrap per calcolare l'integrale approssimato
delle funzioni 3*x^2 e cos(x), utilizzando le direttive EXTERNAL e INTRINSIC.
Program test1_trapezio implicit none real a,b integer n real IntTrap real, external :: g ! o anche real g; external g real, intrinsic :: cos ! o anche intrinsic cos print *, 'calcolo dell''integrale fra a e b della funzione g(x)=3*x^2' print *, 'a,b=?' read *, a,b print *, 'n=?' read *,n print *, IntTrap(a,b,n,g) print * print *, 'calcolo dell''integrale fra a e b della funzione cos(x)' print *, 'a,b=?' read *, a,b print *, 'n=?' read *,n print *, IntTrap(a,b,n,cos) stopend program test1_trapezio
real function g(x) implicit none
1.
real, intent(in) :: x g = 3*x*x returnend function g
Main program che richiama la funzione IntTrap per calcolare l'integrale approssimato
delle funzioni 3*x^2 e cos(x), utilizzando le direttive EXTERNAL e INTRINSIC e il
blocco INTERFACE.
Program test2_trapezio implicit none real a,b integer n intrinsic cos interface real function IntTrap(a,b,n,f) real, intent(in):: a,b integer, intent(in):: n real, external :: f end function IntTrap real function g(x) real, intent(in) :: x end function g end interface print *, 'calcolo dell''integrale fra a e b della funzione g(x)=3*x^2' print *, 'a,b=?' read *, a,b print *, 'n=?' read *,n print *, IntTrap(a,b,n,g) print * print *, 'calcolo dell''integrale fra a e b della funzione cos(x)' print *, 'a,b=?' read *, a,b print *, 'n=?' read *,n print *, IntTrap(a,b,n,cos) stopend program test2_trapezio
real function g(x) implicit none real, intent(in) :: x g = 3*x*x returnend function g
Subroutine che utilizza il metodo di bisezione per il calcolo della radice di una
funzione in un intervallo [a,b] (la funzione f deve essere continua in [a,b] con
f(a)*f(b)<0).
Subroutine bisezione(a,b,tol,nmax,f,radice,trovato)! Metodo di bisezione per il calcolo della radice di una! funzione continua in [a,b] con f(a)*f(b) <0!! QUALCHE COMMENTO SUL METODO DI BISEZIONE! ========================================! CRITERIO DI ARRESTO:! il metodo iterativo si arresta quando l'ampiezza dell'intervallo nel
2.
! quale si cerca la radice e` minore di una tolleranza fissata.!! CONVERGENZA E NUMERO DI ITERAZIONI:! sia [a,b] l'intervallo di partenza entro il quale si cerca la radice,! dopo n iterazioni l'ampiezza dell'intervallo sara` (b-a)/2^n! quindi num.iterazioni = int[log_2((b-a)/tol)]+1.! Il metodo converge quindi sempre in un numero di iterazioni finito! e prevedibile, ma in generale converge lentamente. Una delle cause! e` che il metodo non usa tutte le informazioni disponibili, infatti! usa solo il segno della f agli estremi dell'intervallo e non il valore. !! LIMITI:! l'intervallo di partenza deve contenere una radice;! la convergenza e` lenta (vedi osservazione precedente).! implicit none! dichiarazione parametri formali real a,b ! estremi dell'intervallo contenente la radice real tol ! tolleranza nel calcolo della radice integer nmax ! numero max di iterazioni real, external:: f ! funzione esterna di cui si vuole calcolare la radice real radice logical trovato! dichiarazione variabili locali real sinistra, destra real fs,fd,frad integer i
! inizializzazione variabili trovato = .false. sinistra = a ; destra = b fs = f(sinistra); fd = f(destra) ! controlla che l'intervallo [a,b] contenga una radice if ((fs*fd).gt.0.) return
do i = 1,nmax radice = (sinistra+destra)* 0.5 ; frad = f(radice) if ((radice-sinistra).le.tol) then trovato = .true. ; exit end if if ((fs*frad).gt.0.) then sinistra = radice ; fs = frad else destra = radice ; fd = frad end if end do
returnend subroutine bisezione
Foglio esercizi n.6
Scrivere un programma che legga da tastiera due numeri interi positivi e calcoli il MCD con il
metodo di Euclide basato sulle divisioni successive (implementare il metodo di Euclide in maniera
ricorsiva).
1.
Scrivere una subroutine che riceva in input
due numeri reali a,b
un numero intero positivo n
una funzione reale f
e stampi a video la seguente tabella:
x
o
f(x
o
)
x
1
f(x
1
)
..... .....
..... .....
x
n
f(x
n
)
con x
0
=a, h=(b-a)/n, x
i+1
=x
i
+h, per i=0,.....,n-1.
Testare la subroutine tramite un programma che:
permetta di scegliere fra le seguenti funzioni:
- real external function f1(x) = |x
2
sin(x)|
- real intrinsic function cos(x)
- real external function f2(x) = exp(-x
2
)
a.
legga in input a, b reali con a<b e un intero positivo n;b.
richiami la subroutine per stampare la tabella relativa alla funzione selezionata.c.
2.
Implementazione delle formule composite del punto medio, dei trapezi e di Cavalieri-Simpson per
il calcolo del valore approssimato dell'integrale di una funzione: vedi formule di quadratura ed
esempio implementazione formule di quadratura.
3.
Esercizio 2 della prova d'esame 1/2004 (con stampa a video)4.
Svolgimento
! Calcolo MCD(a,b) con algoritmo di Euclide per divisioni successive ! L'algoritmo si basa sulla seguente proprietà:! dati due interi positivi a,b con a>=b e a=b*q+r! se r=0 => b=MCD(a,b)! se r<>0 => MCD(a,b) = MCD(b,r)
Program Calcola_MCD implicit none integer:: a,b,com integer:: mcd print *, 'Calcolo MCD(a,b)' print *, 'dammi due interi positivi a,b' read *, a,b! se necessario aggiusta i dati in input a=abs(a); b=abs(b) if (a.lt.b) then; com=a; a=b; b=com; end if print *, "MCD = ", mcd(a,b)end program
1.
recursive function mcd(a,b) result (m) implicit none integer:: m, a, b, r r = mod(a,b) if (r==0) then m=b else m=mcd(b,r) end if returnend function
Per completezza si presenta anche un'implementazione del metodo con schema iterativo:
function mcd(a,b) result (m) integer:: m, a, b, r do r=mod(a,b) if (r==0) then m=b; exit else a=b; b=r end if end do returnend function
program stampa_funzione_in_tabella implicit none integer n real a,b real, external:: f1 real, external:: f2 intrinsic cos integer esempio print *, 'Funzione test:' print *, ' [1] abs(x*x*sin(x))' print *, ' [2] cos(x)' print *, ' [3] exp(-x*x)' do print *, 'Scegli la funzione test:' read *, esempio if ((esempio>=1).and.(esempio<=3)) exit end do do print *, "estremi dell'intervallo (a,b):" read *, a,b if (a.lt.b) exit print *, "immettere a<b" end do do print *, "n=? (n>0)" read *, n if (n>0) exit print *, "immettere n>0" end do select case(esempio) case(1) call stampa_tabella(a,b,n,f1) case(2) call stampa_tabella(a,b,n,cos) case(3) call stampa_tabella(a,b,n,f2) end selectstopend program stampa_funzione_in_tabella
2.
subroutine stampa_tabella(a,b,n,f) implicit none real a,b integer n real, external:: f real h,x integer i h=(b-a)/n x=a do i=0,n print *, x, f(x) x=x+h end do returnend subroutine stampa_tabella
real function f1(x) implicit none real x f1= abs(x*x*sin(x)) returnend function f1
real function f2(x) implicit none real x f2= exp(-x*x) returnend function f2
Linguaggi di Programmazione per il calcolo scientifico
Formule di quadratura
Problema: Data la funzione f : [a, b]→ IR continua, calcolare il valore dell’integrale∫ b
a
f(x)dx
Siano assegnati in INPUT:
• f , funzione da integrare;
• a, b, estremi dell’intervallo;
• n, numero di suddivisioni dell’intervallo [a, b];
e sia
• h = (b− a)/n
• xi = a+ ih, i = 0, . . . , n
una formula di quadratura ci permette di ottenere un valore approssimato dell’integraledella funzione a partire dai valori di f nei nodi xi, i = 0, . . . , n
Formula composita del punto medio
Int(f, a, b, n) = hn∑i=1
f
(xi−1 + xi
2
)
Formula composita dei trapezi
Int(f, a, b, n) = h
(f(a)
2+
n−1∑i=1
f(xi) +f(b)
2
)
Formula composita di Cavalieri-Simpson
Int(f, a, b, n) =h
6
(f(a) + 2
n−1∑i=1
f(xi) + 4n∑i=1
f
(xi−1 + xi
2
)+ f(b)
)
1
Scrivere una function che calcoli il valore approssimato dell’integrale di una funzionemediante le formule composite del punto medio, dei trapezi e di Cavalieri-Simpson.La function quadratura deve ricevere in INPUT
• a,b estremi dell’intervallo;
• n numero degli intervalli di suddivisione;
• f funzione da integrare;
• metodo (1 punto medio, 2 trapezi 3 cavalieri-simpson)
Testare la function quadratura sui seguenti esempi
1.
∫ π/2
0
cos(x)dx = 1
2.
∫ 2
1
3x2dx = 7
3.
∫ 1
0
xex = 1
2
!! E
sem
pio
di p
rog
ram
ma
zio
ne
in f
90
:!!
pro
gra
mm
a p
er
test
are
i m
eto
di d
i qu
ad
ratu
ra.
!! L
a f
un
ctio
n q
ua
dra
tura
imp
lem
en
ta le
fo
rmu
le c
om
po
site
!!
de
l pu
nto
me
dio
, d
ei t
rap
ezi
e d
i Ca
valie
ri−
Sim
pso
n.
!! I
l ma
in p
rog
ram
te
sta
la f
un
ctio
n q
ua
dra
tura
ca
lco
lan
do
!! g
li in
teg
rali
ap
pro
ssim
ati
di a
lcu
ne
fu
nzi
on
i di p
rova
!! e
co
nfr
on
tan
do
co
n le
so
luzi
on
i esa
tte
.!! !!
!!!!
!!!!
FU
NZ
ION
I T
ES
T !
!!!!
!!!!
!function
f(
x,e
sem
pio
)
implicit
none
real
(kind
=8
)::
f,x
integer
ese
mp
io
select case
(e
sem
pio
)
case
(1)
f=cos
(x)
case
(2)
f=3
*x*x
case
(3)
f=x*
exp
(x)
end
se
lect
return
end
function
f
!!!!
!!!!
!! M
AIN
PR
OG
RA
M !
!!!!
!!!!
!Program
te
st_q
uad
ratu
ra
implicit
none
real
(kind
=8
)::
a,b
integer
:: n
real
(kind
=8
),
external
::
f
integer
me
tod
o,
ese
mp
io
interface
function
q
uad
ratu
ra(a
,b,n
,f,m
eto
do
,ese
mp
io)
real
(kind
=8
)::
qu
ad
ratu
ra real
(kind
=8
)::
a,b
integer
:: n
real
(kind
=8
),
external
:: f
integer
:: m
eto
do
, e
sem
pio
end
function
q
uad
ratu
ra
end
interface
real
(kind
=8
) q
ua
d,s
ol_
esa
tta
,err
character
ris
po
sta
integer
, parameter
:: n
um
_m
eto
di=
3
integer
, parameter
:: n
um
_te
st=
3
character
(len
=4
0),
dimension
(nu
m_
me
tod
i) :
: d
ef_
me
tod
o
data
de
f_m
eto
do
/’
form
ula
com
posi
ta d
el p
unto
med
io’, &
’
form
ula
com
posi
ta d
ei tr
apez
i’,&
’
form
ula
com
posi
ta d
i Cav
alie
ri−S
imps
on’/
real
(kind
=8
),
parameter
:: p
ime
zzi=
asin
(1.)
*,
"C
alco
lo d
ell’i
nteg
rale
def
inito
di f
(x)
in [a
,b],
tram
ite fo
rmul
e di
qua
drat
ura
"
sel_
ese
mp
io:
do
*,
"S
celta
del
la fu
nzio
ne te
st:
"
*,
"1)
f(x)
=co
s(x)
co
n [a
,b]=
[0,p
i/2]
(sol
uzio
ne e
satta
= 1
)"
*,
"2)
f(x)
=3*
x^2
co
n [a
,b]=
[1,2
]
(sol
uzio
ne e
satta
= 7
)"
*,
"3)
f(x)
=x*
exp(
x) c
on [a
,b]=
[0,1
]
(sol
uzio
ne e
satta
= 1
)"
do
read
*,
ese
mp
io
if
((e
sem
pio
.ge.
1).and.
(ese
mp
io.le.
nu
m_
test
))
exit
*,
"S
celta
err
ata.
Inse
risci
un
valo
re fr
a 1
e ",
nu
m_
test
end
do
select case
(e
sem
pio
)
case
(1)
a=
0;
b=
pim
ezz
i; so
l_e
satt
a=
1.
case
(2)
a=
1;
b=
2;
sol_
esa
tta
=7
.
case
(3)
a=
0;
b=
1;
sol_
esa
tta
=1
.
end
se
lect
sel_
n:
do
do
*,
’n=
?’
read
*,n
if
(n
>0
) exit
end
do
do
me
tod
o=
1,n
um
_m
eto
di
*
*,
de
f_m
eto
do
(me
tod
o)
Jun
25, 1
2 11
:57
Pag
e 1/
2q
uad
ratu
ra.f
90
qu
ad
= q
ua
dra
tura
(a,b
,n,f
,me
tod
o,e
sem
pio
)
e
rr =
abs
(so
l_e
satt
a−
qu
ad
)
*,
"In
tegr
ale
appr
ossi
mat
o =", q
ua
d,
" e
rror
e=",
err
end
do
*
*,
"V
uoi r
ipet
ere
con
un a
ltro
valo
re d
i n?
"
read
*,
risp
ost
a
if
(risp
ost
a=
="
n")
exit
end
do
se
l_n
*,
"V
uoi c
ambi
are
esem
pio?
(s/
n)"
read
*,
risp
ost
a
if
(risp
ost
a=
="
n")
exit
end
do
se
l_e
sem
pio
stop
end
pro
gra
m
!!!!
!!!!
!! F
UN
CT
ION
QU
AD
RA
TU
RA
!!!
!!!!
!!!
function
q
uad
ratu
ra(a
,b,n
,f,m
eto
do
,ese
mp
io)
!!
[a
,b]
inte
rva
llo d
i in
teg
razi
on
e!!
h
= (
b−
a)/
np
ass
o d
i in
teg
razi
on
e!!
x
(i)
=
a+
i*h
,
i=1
,...
,n−
1 implicit
none
real
(kind
=8
)::
qu
ad
ratu
ra real
(kind
=8
)::
a,b
integer
:: n
real
(kind
=8
),
external
:: f
integer
:: m
eto
do
, e
sem
pio
real
(kind
=8
) h
,x integer
i,n
m1
real
(kind
=8
) xm
,s,s
m
h=
(b−
a)/
n
nm
1 =
n−
1
x=a
select case
(me
tod
o)
case
(1
)!
form
ula
co
mp
osi
ta d
el p
un
to m
ed
io
!
in o
gn
i in
terv
allo
[X
(i),
X(i+
1)]
si a
pp
ross
ima
l’in
teg
rale
co
n
!
la f
orm
ula
Q(f
) =
h *
f(
(X(i)+
X(i+
1))
/2 )
! si
ott
ien
e c
osi
’ la
fo
rmu
la c
om
po
sita
de
l pu
nto
me
dio
! h
*[f(
(X(0
)+X
(1))
/2)
+ f
((X
(1)+
X(2
))/2
) +
...
+f(
(X(n
−1
)+X
(n))
/2)]
x
m=
a+
h/2
; sm
=f(
xm,e
sem
pio
)
do
i =
1,n
m1
xm
=xm
+h
; sm
=sm
+f(
xm,e
sem
pio
)
end
do
q
ua
dra
tura
= h
*sm
case
(2
)!
form
ula
co
mp
osi
ta d
ei t
rap
ezi
! in
og
ni i
nte
rva
llo [
X(i),
X(i+
1)]
si a
pp
ross
ima
l’in
teg
rale
co
n
!
la f
orm
ula
Q(f
) =
h/2
* (
f(X
(i))
+ f
(X(i+
1))
! si
ott
ien
e c
osi
’ la
fo
rmu
la c
om
po
sita
de
i tra
pe
zi
!
h*[
f(a
)/2
+f(
X(1
))+
....
+f(
X(n
−1
))+
f(b
)/2
]
qu
ad
ratu
ra =
(f(
a,e
sem
pio
)+f(
b,e
sem
pio
))/2
do
i =
1,n
m1
x
= x
+h
q
ua
dra
tura
= q
ua
dra
tura
+ f
(x,e
sem
pio
)
end
do
q
ua
dra
tura
= q
ua
dra
tura
*h
case
(3
)!
form
ula
co
mp
osi
ta d
i Ca
valie
ri−
Sim
pso
n
!
in o
gn
i in
terv
allo
[X
(i),
X(i+
1)]
si a
pp
ross
ima
l’in
teg
rale
co
n
!
la f
orm
ula
Q(f
) =
h/6
* (
f(X
(i))
+ 4
f(
(X(i)+
X(i+
1))
/2 )
+ f
(X(i+
1))
! si
ott
ien
e c
osi
’ la
fo
rmu
la c
om
po
sita
di C
ava
lieri−
Sim
pso
n
!
h/6
*[f(
a)+
4f(
(X(0
)+X
(1))
/2)
+ 2
f(X
(1))
+ 4
f((X
(1)+
X(2
))/2
) +
2f(
X(2
)) +
!
+
...
. 2
f(X
(n−
1)
)+ 4
f((X
(n−
1)+
X(n
))/2
) +
f(x
(n))
]
xm
=a
+h
/2
s=
0;
sm=
f(xm
,ese
mp
io)
do
i =
1,n
m1
x=
x+h
;
s=s+
f(x,
ese
mp
io)
xm
=xm
+h
; sm
=sm
+f(
xm,e
sem
pio
)
end
do
q
ua
dra
tura
= h
*(f(
a,e
sem
pio
)+4
*sm
+2
*s+
f(b
,ese
mp
io))
/6.
end
se
lect
return
end
function
q
uad
ratu
ra
Jun
25, 1
2 11
:57
Pag
e 2/
2q
uad
ratu
ra.f
90P
rinte
d by
Seg
hini
Mon
day
June
25,
201
21/
1qu
adra
tura
.f90
6. LE VARIABILI GLOBALI
Il passaggio di "informazioni" tra una subroutine ed il
programma chiamante avviene tramite la lista dei parametri
passati come argomenti, o attraverso le variabili globali.
In fortran 90 la condivisione delle variabili fra più unità di
programma si può realizzare utilizzando i MODULI.
ESEMPIO: module dati_condivisi type persona
character(len=20) cognome, nome integer eta end type persona
integer, parameter:: nmax=1000 type(persona), dimension(nmax):: gruppo real p,q END MODULE dati_condivisi
Qualsiasi unità di programma (main program, subroutine,
function) che voglia utilizzare il tipo persona, la costante
nmax, le variabili gruppo, p e q dovrà semplicemente
utilizzare il comando:
USE dati_condivisi
Questa direttiva deve essere inserita all'inizio della sezione
dichiarativa dell'unità di programma, prima di eventuali
direttive IMPLICIT o di qualsiasi dichiarazione esplicita di
variabili.
Vedi esempio di utilizzo di MODULE per la condivisione di
variabili fra main e sottoprogrammi e esercizio1 del foglio
esercizi 7
In fortran 77 l'unità di programma MODULE non esiste.
In questo caso, per poter disporre di blocchi di memoria
condivisi da più unità di programma, si utilizzano le aree
COMMON. Le aree COMMON vengono dichiarate nella
sezione dichiarativa del programma con la seguente sintassi:
COMMON /area1/lista variabili
COMMON /area2/lista variabili
Un'area COMMON è identificata da un unico nome globale al
quale devono riferirsi tutte le unità di programma che
vogliono accedervi.
Se nel programma si utilizza una sola area COMMON, il nome
può essere omesso:
COMMON lista variabili
L'accesso alle variabili contenute nell'area COMMON avviene
in base alla locazione di memoria all'interno del blocco:
differenti unità di programma possono utilizzare nomi diversi
per le variabili all'interno del blocco pur di rispettarne il tipo,
l'ordine ed il numero.
ESEMPIO: REAL X,Y,Z,A(10) <---- nel main COMMON /area/X,Y,Z,A
REAL P,Q(12) <---- nella subroutine COMMON /area/P,Q
Variabili di tipo numerico e di tipo character devono essere
dichiarate in aree COMMON diverse.
In fortran 90, l'area COMMON definita nell'esempio
precedente può essere realizzata utilizzando un MODULE:
MODULE area REAL x,y,z,a(10)END MODULE area
Qualsiasi unità di programma che voglia utilizzare le variabili
x, y, z, a dovrà includere la direttiva:
USE area
Esempio di utilizzo MODULE
Si propone esempio di utilizzo dell'unità di programma MODULE per la condivisione di variabili
fra main e sottoprogrammi.
Esercizio
Scrivere un programma che legga un numero dispari positivo n <=79 e disegni un triangolo
isoscele di base n. Ad esempio per n=7 il programma dovrà disegnare:
* *** ***** *******
Svolgimento
Module dati integer, parameter :: maxbase = 79 integer n character, dimension(maxbase):: lineaend module dati
Program esempio_uso_module use dati implicit none call leggi_len_base call disegna_triangolo stopend program esempio_uso_module
Subroutine leggi_len_base use dati implicit none do print 100, maxbase100 format('Base del triangolo = ? (numero dispari positivo <= ', i2,')') read *, n if ((n.gt.0).and.(n.le.maxbase).and.(mod(n,2).eq.1)) exit end do returnend subroutine leggi_len_base
Subroutine disegna_triangolo use dati implicit none integer num,i,j do i=1,n,2 linea= ' ' num = (n-i)/2 linea(num+1:num+i)='*' print *, linea ! o anche "print *, (linea(j), j=1,n)" end do returnend subroutine disegna_triangolo
7. FUNZIONI DI TIPO ARRAY E DI TIPO DERIVATO
Una function può restituire al programma chiamante non soltantouno scalare, ma anche un array (array valued function) o unavariabile di tipo derivato, come nei seguenti esempi.
ESEMPIO 1: funzione di tipo array !! Dato un punto p0=(x0,y0) e una retta r: y = m*x + q calcolare ! la proiezione ortogonale di p0 su r !! La proiezione p1 si calcola come intersezione della retta r e ! della retta r1, perpendicolare a r passante per p0! r1: y = -1/m*(x-x0) + y0 !! La proiezione p1 e' il punto di coordinate! x1 = (x0-m*q+m*y0)/(m2+1)! y1 = m*x1 + q!function proiezione(p0,m,q) result(p1) real, dimension(2):: p0,p1 real m,q p1(1) = (p0(1) - q*m + m*p0(2))/(m*m+1) p1(2) = m*p1(1) + q returnend function proiezione
program esempio_uso_array_valued_function implicit none real, dimension(2):: p real:: m,q interface function proiezione(p0,m,q) result(p1) real, dimension(2):: p0,p1 real m,q end function proiezione end interface
print *, 'coordinate del punto P ?' read *, p print *, 'retta su r cui proiettare: m? q?' read *, m,q print *, 'Proiezione di P su r: ', proiezione(p,m,q)end program
ESEMPIO 2: funzione di tipo derivato !! Dato un punto p0=(x0,y0) e una retta r: y = m*x + q calcolare ! la proiezione ortogonale di p0 su r !! La proiezione p1 si calcola come intersezione della retta r e ! della retta r1, perpendicolare a r passante per p0! r1: y = -1/m*(x-x0) + y0 !! La proiezione p1 e' il punto di coordinate! x1 = (x0-m*q+m*y0)/(m2+1)! y1 = m*x1 + q!module MieDef type punto real x,y end type punto contains function proiezione(p0,m,q) result(p1) type (punto):: p0,p1 real m,q p1%x = (p0%x - q*m + m*p0%y)/(m*m+1) p1%y = m*p1%x + q return end function proiezioneend module
program esempio_uso_funzione_tipo_derivato use MieDef implicit none type(punto):: p real:: m,q
print *, 'coordinate del punto P ?' read *, p print *, 'retta su r cui proiettare: m? q?' read *, m,q print *, 'Proiezione di P su r: ', proiezione(p,m,q)end program
ISTRUZIONI DI INPUT/OUTPUT
Le istruzioni di I/O più semplici sono:
READ *, lista di input
PRINT *, lista di output
In queste istruzioni le unità di ingresso/uscita sono le unità standard,normalmente la tastiera in input ed il video in output. Il formato diingresso/uscita è guidato da lista: in input i dati devono essere separati dauno spazio o da una virgola, in output viene utilizzato un "formatoragionevole" per il tipo di dati da stampare, ma non è possibile controllarnein maniera precisa la disposizione. Se si desidera utilizzare un formatodefinito dal programmatore, è necessario specificare nell'istruzione di I/Ola label di un'istruzione FORMAT:
READ label, lista di input
PRINT label, lista di output
Nelle istruzioni di I/O è inoltre possibile indicare altri controlli chepermettono di specificare unità di ingresso/uscita diverse dalle unitàstandard e di gestire eventuali errori.In questo caso la sintassi delle instruzioni di I/O diventa:
READ (lista controlli) lista di input
WRITE (lista controlli) lista di output
Vediamo più in dettaglio le possibili varianti delle istuzioni READ , PRINT ,WRITE e la sintassi dell'istruzione FORMAT
1. ISTRUZIONE READ
READ *, lista di inputlettura da unità standard (di solito la tastiera) con formato diretto dalista (indicato dall'asterisco *)
ESEMPIO: READ *, A, B, C
READ label, lista di inputlettura da unità standard con formato guidato dall'istruzioneFORMAT individuata dall'etichetta label
ESEMPIO: READ 100, A, B, C 100 FORMAT ( ..... )
READ ([UNIT=] u, [FMT=] label1, ERR=label2, END=label3, IOSTAT=ios,...) lista diinput
UNIT = u individua il dispositivo di inputu = * unità di ingresso standard (normalmente latastiera)la tastiera è normalmente indicata anche da u = 5altri numeri di dispositivo possono essere associati afile esterni aperti con un'istruzione OPEN ([UNIT=] u,...).
FMT = label1 label1 identifica l'istruzione FORMAT che guida ilformato dei dati in ingresso (FMT = * indica formatoguidato da lista).
ERR = label2 qualora si verifichi un errore in input, l'esecuzione delprogramma salta all'istruzione con etichetta label2.
END = label3 qualora si incontri il marcatore di EOF (End Of File),l'esecuzione del programma salta all'istruzione conetichetta label3.
IOSTAT = ios ios è una variabile intera nella quale vienememorizzato il risultato dell'operazione di input:ios=0 non ci sono errori e non si incontra EOF
>0 si è verificato un errore<0 in caso di EOF senza errori
ESEMPIO: READ (5,100) A, B, C READ (*,*) P,Q ! lettura di un array con DO implicito READ (3,200,err=20,end=30) (x(i), i=1,n) READ (1,150, IOSTAT=I) Y,Z IF (I .LT. 0) THEN ! fine del file . . ELSE IF (I .GT. 0) THEN ! errore in input . . END IF . . STOP 100 FORMAT ( ..... ) 150 FORMAT ( ..... ) 200 FORMAT ( ..... )
2. ISTRUZIONI PRINT e WRITE
PRINT *, lista di outputscrittura su unità standard (di solito il video) con formato diretto dalista (indicato dall'asterisco *)
ESEMPIO: PRINT *, A, B, C
PRINT label, lista di outputscrittura su unità standard con formato guidato dall'istruzioneFORMAT individuata dall'etichetta label
ESEMPIO: PRINT 200, A, B, C . . 200 FORMAT ( ..... )
WRITE ([UNIT=] u,[FMT=] label) lista di outputUNIT = u individua il dispositivo di output
u = * unità di uscita standard (normalmente il video)la stampante è normalmente indicata da u = 6altri numeri di dispositivo possono essere associati a fileesterni aperti con un'istruzione OPEN ([UNIT=] u, ...).
FMT = label label identifica l'istruzione FORMAT che guida il formatodei dati in uscita (FMT = * corrisponde a formatoguidato da lista).
ESEMPIO: WRITE (*,300) A, B, C 300 FORMAT ( ..... )
! scrittura di una matrice con un DO implicito WRITE (*,*) ((Y(I,J), J=1,M), I=1,N)
3. ISTRUZIONE FORMAT
L'istruzione FORMAT permette di controllare il formato dei dati iningresso/uscita. È un'istruzione non eseguibile, utilizzata da un'altraistruzione (READ o PRINT/WRITE) che la identifica tramite la sua label(deve quindi essere sempre preceduta da una label). Può trovarsi inqualsiasi punto del programma, purchè prima dell'END. Normalmente leistruzioni FORMAT si trovano subito dopo l'istruzione di I/O che leutilizza, oppure tutte in fondo al programma, generalmente dopo loSTOP.La sintassi dell'istruzione è la seguente:
label FORMAT (lista descrittori di formato)
ESEMPIO: WRITE (*,300) J,A 300 FORMAT ('J=', I3, 5X, 'A=', F10.3)
Riportiamo alcuni fra i decrittori di formato usati più comunemente:Iw numero intero con un "campo" di w caratteriFw.d numero reale con un "campo" di w caratteri (compreso segno e virgola) e d cifre
decimaliEs. -15.53478 si può rappresentare con un formato F9.5
Ew.d
numero reale con un "campo" di w caratteri, con d cifre decimali per la mantissa e 4caratteri per l'esponente Es. 3.1416 scitto in formato E12.5 diventa 0.31416E+01 ( = 0.31416*10)
nX lascia n spazi bianchi in output, o ignora n caratteri in input.Tc il prossimo carattere da leggere/scrivere è in colonna cAw variabile di tipo character in un "campo" di w caratteri'...' le stringe devono essere inserite fra apici. Per scrivere il carattere apostrofo (')
usare due apici consecutivi ('')./ sposta alla riga successiva.$ continua sulla stessa riga.
ESEMPI: WRITE (*,400) I,J,IPJ 400 FORMAT ('La somma di ',I3,' e di',I3,' e'' ',I5) WRITE (*,100) soluzione 100 FORMAT (3X, 'la soluzione e'' ',F12.5) WRITE (*,300) j,x(j) 300 FORMAT (5X, 'x(', I3, ')=', F10.3) WRITE (*,350) i, A(i), B(i) 350 FORMAT (T6, I4, T15, F12.5, T30, F12.5) PRINT 380, eps 380 FORMAT ('eps=',e10.3)
! esempi di ripetizione di formato WRITE (*,120) I,J,K 120 FORMAT (3I5) WRITE (*,200) (I, A(I), I=1,10) 200 FORMAT (10(I3, 2X, F10.3, 5X)) WRITE (*,250) (j, x(j), j=1,3) 250 FORMAT (T3, 3(I3, 2X, F15.5, 5X))
! esempio di richiesta di input, senza andare a riga nuova PRINT "('dammi n: ',$)" READ *, n
GESTIONE DEI FILE
Un file è una sequenza di record.
Quando si memorizzano dati in un file, questi possono essereconvertiti dalla loro "rappresentazione interna", in un formasimile a quella usata a video o sulla stampante. In questocaso il file è formato da record formattati.Se i dati sono lasciati nella loro "rappresentazione interna" ilfile è formato da record non formattati. In questo caso il file èessenzialmente una copia della memoria ed i dati vengonoscritti in una forma dipendente dal processore. I file nonformattati possono quindi essere utilizzati da programmi chegirano sullo stesso computer o su computer identici.Se i dati devono essere trasferiti su computer diversi, èpreferibile utilizzare file formattati.
Nei file formattati, ogni record è una sequenza formattata dicaratteri e la lunghezza dei record è misurata in caratteri.Nei file non formattati, ogni record è una sequenza nonformattata di valori e la lunghezza dei record è misurata inbyte o word.
ESEMPIO: le due istruzioni seguenti:WRITE (9,200) (I,A(I),B(I), I=1,N)
200 FORMAT(I3,2F10.4)
producono record formattati di lunghezza 23 caratteri.
L'istruzione WRITE (8) X,Y,Z nella quale non viene specificato il formato,
produce un record non formattato.
I file possono essere di tipo sequenziale o ad accesso diretto.In un file di tipo sequenziale, la scrittura di un record provocala perdita di tutte le informazioni successive.I file ad accesso diretto sono utili quando è necessarioscrivere o leggere record in ordine casuale o quando si vuolesovrascrivere un singolo record. Nei file ad accesso diretto ènecessario che tutti i record abbiano la stessa lunghezza.
Per collegare un file esterno ad una unità di I/O:
OPEN (lista specificatori di apertura)
ESEMPIO: OPEN (9,FILE='risultati.dat',STATUS='old',ERR=50)
Riportiamo alcuni fra i più comuni specificatori di apertura:UNIT=u è l'unico specificatore indispensabile (tutti gli
altri sono facoltativi). Individua il numero diunità di I/O associata al file. La stringa"UNIT=" può essere omessa.
FILE='nome' indica il nome del file
STATUS='st' dove st è una stringa di caratteri che puòassumere uno dei seguenti valori:oldnewreplacescratch il file viene automaticamente cancellato al termine
dell'esecuzione del programma.unknown usato come default in mancanza di specificazione
esplicita.
ACCESS='acc' dove acc è una stringa di caratteri che puòassumere uno dei seguenti valori:sequential l'accesso al file è di tipo sequenziale. Questo tipo di
accesso è usato come default in mancanza dispecificazione esplicita.
direct l'accesso al file è di tipo diretto. In questo caso ènecessario che tutti i record abbiano una lungezzache non superi quella indicata con lo specificatoredi apertura RECL.
RECL=lun indica la lunghezza dei record contenuti nelfile. La lunghezza dei record formattati èmisurata in caratteri. Quella dei record nonformattati è misurata in byte o word.
FORM='fm' dove fm è una stringa di caratteri che puòassumere uno dei seguenti valori:formatted formato di default per i file di tipo sequenziale.unformatted formato di default per i file ad accesso diretto.
ERR = label qualora si verifichi un errore, l'esecuzione delprogramma salta all'istruzione con etichettalabel.
Per scollegare un file esterno, prima del termine
dell'esecuzione del programma:
CLOSE (lista specificatori di chiusura)
ESEMPIO: CLOSE (9, STATUS='keep',ERR=50)
Gli specificatori di chiusura normalmente utilizzati sono:UNIT=u è l'unico specificatore indispensabile (tutti gli
altri sono facoltativi). Individua il numero diunità di I/O associata al file. La stringa"UNIT=" può essere omessa.
STATUS='st' dove st è una stringa di caratteri che puòassumere uno dei seguenti valori:delete il file viene cancellato ed il programma non potrà più
accedervi.keep il file continua ad esistere anche dopo essere stato
scollegato dal programma.
In mancanza di specificazione un file vienechiuso con STATUS='keep', a meno che non siastato aperto con STATUS='scratch', nel qualcaso la chiusura avviene necessariamente conSTATUS='delete'
ERR = label qualora si verifichi un errore, l'esecuzione delprogramma salta all'istruzione con etichettalabel.
Per posizionare il file all'inizio del record precedente:
BACKSPACE u
Per posizionare il file all'inizio del primo record:
REWIND u
Per inserire il record di fine-file (EOF) e posizionare il filedopo quel record:
ENDFILE u
ESEMPI:
1) Inserimento di nuove informazioni in fondo ad un file sequenziale scritto in precedenza
! leggere fino a EOF DO
READ (9, ERR=50, END=21) END DO
! inserire nuove informazioni21 WRITE (9) ......
..........
..........
! chiudere il file con EOFENDFILE 9
2) Scrittura su un file formattato ad accesso diretto
OPEN(7,ACCESS='direct',FORM='formatted',RECL=60)............................................................................
WRITE (7,150,REC=20) (X(I), I=1,50)150 FORMAT (5(F10.3,2X))
Vengono scritti 10 record, ciascuno contenente 5 numeri reali. I record saranno numerati da 20 a 29 e avranno lunghezza pari a 60 caratteri.
Per avere tutte le informazioni relative alle caratteristiche diun file (formattazione, accesso, lunghezza record, etc.):
INQUIRE (lista specificatori)
ESEMPIO 1: INQUIRE (9, ACCESS=acc, FORM=fm, RECL=len)
Nell' esempio 1 si richiedono informazioni sul file associatoall'unità 9.acc e fm sono variabili di tipo carattere, che riporterannorispettivamente i valori 'sequential' o 'direct', per la variabileacc, e 'formatted' o 'unformatted, per la variabile fm. Sesull'unità 9 non è aperto nessun file le due variabiliresteranno indefinite.len è una variabile intera: se sull'unità 9 è aperto un file ad
accesso diretto, len riporterà la lunghezza del record,altrimenti diventerà indefinita.
ESEMPIO 2: INQUIRE (FILE='dati',OPENED=op,NUMBER=n)
Nell'esempio 2 si richiedono informazioni sul file "dati".op è una variabile logica che riporterà il valore .TRUE. se ilfile è collegato ad una certa unità e .FALSE. altrimenti. Ilnumero di unità collegata al file "dati" verrà assegnato allavariabile intera n.
ESEMPIO 3: INQUIRE (FILE='dati',OPENED=op,NUMBER=n) IF (.NOT.op) THEN
OPEN (8,FILE='dati')n = 8
END IF READ (n, ERR=20, END=21) ...... ...............................
Foglio esercizi n.7
Esercizio su tipi derivati e di variabili condivise tramite MODULE:
un magazzino gestisce n prodotti diversi. Ciascun prodotto è identificato dal codice
(integer), dalla descrizione (stringa di 15 caratteri) e dal prezzo (real). Il magazzino,
periodicamente stabilisce una cifra massima (budget) utilizzabile per l'acquisto di
ciascun singolo prodotto (il budget è uguale per tutti i prodotti; se ad esempio il
budget fissato è pari a 100 €, allora per l'acquisto di ciascun tipo di prodotto non si
potranno superare i 100 € di spesa).
Scrivere un'unità di programma di tipo MODULE contenente:
- una direttiva TYPE che definisca una struttura dati idonea a descrivere un
prodotto,
- una variabile reale, rappresentante il budget.
a.
Scrivere un programma che legga in input:
- un intero positivo n
- codice, descrizione e prezzo di n prodotti
- il budget
e poi, tramite un'apposita subroutine, stampi a video una tabella contenente
per ciascun prodotto codice, descrizione, prezzo e numero di pezzi
acquistabili con il budget fissato.
b.
1.
Esercizio 1 della prova d'esame 2/20052.
Fattorizzazione LU di una matrice quadrata con il metodo di Crout (vedi schema
numerico con testo dell'esercizio e svolgimento)
3.
Polinomio interpolante nella forma di Newton (vedi schema numerico con testo
dell'esercizio e svolgimento)
4.
Svolgimento
module dati_comuni type prodotto integer code character(len=15) descrizione real prezzo end type prodotto real budgetend module
Program esempio use dati_comuni implicit none integer n type (prodotto), dimension(:), allocatable :: magazzino integer i
1.
do print *, 'numero dei prodotti contenuti in magazzino ?' read *, n if (n>0) exit print *, 'devi darmi un numero positivo!' end do allocate(magazzino(n)) do i=1,n print *, 'codice, descrizione e prezzo del prodotto ', i read *, magazzino(i) end do do print *, 'budget ?' read *, budget if (budget>0) exit print *, 'il budget deve essere positivo!' end do call stampa_elenco(n,magazzino) stopend program esempio
subroutine stampa_elenco (n, magazzino) use dati_comuni implicit none integer n type (prodotto), dimension(n) :: magazzino integer i, numpezzi do i=1,n numpezzi = budget/magazzino(i)%prezzo print *, magazzino(i), numpezzi end do returnend subroutine stampa_elenco
Linguaggi di Programmazione per il calcolo scientifico
Fattorizzazione LU di una matrice quadrata
Esercizio
Sia A ∈ Rnxn una matrice non singolare che ammette fattorizzazione LU .Calcolare la fattorizzazione LU di A tramite il metodo di Crout:
per i = 1, . . . , n
calcolo i-esima colonna di Llji = aji −i−1∑k=1
ljkuki
j = i, . . . , n
calcolo i-esima riga di Uuii = 1
uij =1
lii(aij −
i−1∑k=1
likukj)
j = i + 1, . . . , n
Scrivere una subroutine in linguaggio fortran che riceva in input un intero n ed unamatrice A ∈ Rnxn non singolare e restituisca al programma chiamante le matrici L e Uottenute con la fattorizzazione di Crout.
Scrivere un main program che
• legga in input un intero n > 0 (controllare che in input sia immesso n > 0);
• legga in input la matrice A ∈ Rnxn (si richiede di leggere la matrice A per righe);
• richiami la subroutine Crout per calcolare le matrici L e U ;
• stampi su file la matrice A e le matrici L e U .
Per testare il programma, utilizzare le matrici
A =
5 0 11 1 11 0 2
da cui L =
5 0 01 1 01 0 9/5
U =
1 0 1/50 1 4/50 0 1
A =
3 0 1−1 2 02 −1 4
da cui L =
3 0 0−1 2 02 −1 7/2
U =
1 0 1/30 1 1/60 0 1
A =
5 0 1 21 3 1 02 0 8 20 1 1 4
da cui L =
5 0 0 01 3 0 02 0 38/5 00 1 11/15 229/57
U =
1 0 1/5 2/50 1 4/15 −2/150 0 1 3/190 0 0 1
Lavorare in doppia precisione e dichiarare le tutte matrici con l’attributo allocatable.
program
te
st_c
rout
integer
n,i,
j
real
(kind
=8
),
dimension
(:,:
),
allocatable
:: A
,L,U
character
:: r
isp
ost
a
*,
’C
alco
lo d
ella
fatto
rizza
zion
e di
Cro
ut d
i una
mat
rice
A(n
,n)
’open
(3
, fil
e=
"ris
ulta
ti.tx
t")
iniz
io_
test
: do
do
"(’n
>0,
n=
? ’,$
)"; read
*,
n
if
(n
>0
) exit
end
do
allocate
(A
(n,n
), L
(n,n
), U
(n,n
))
L=
0
*,
"C
oeffi
cien
ti de
lla m
atric
e A
, per
rig
a"
do
i=1
,n
read
*,
(a(i,j)
, j=
1,n
)
end
do
call
cr
out (
n,A
,L,U
)
write
(3
,*)
"m
atric
e A"
; call
st
ampa
_mat
rice(
n,A
)
write
(3
,*)
"m
atric
e L"
; call
st
ampa
_mat
rice(
n,L
)
write
(3
,*)
"m
atric
e U"
; call
st
ampa
_mat
rice(
n,U
)
write
(3
,20
0)
! o
utp
ut
risu
ltati
de
l te
st c
om
ple
tato
"(’v
uoi f
are
un a
ltro
test
(y/
n)?’
,$)"; read
*,
risp
ost
a
if
(risp
ost
a =
= ’
n’)
exit
deallocate
(A
,L,U
)end
do
iniz
io_
test
close
(3
)stop
20
0 format
(/,
’−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−’,/)
end
pro
gra
m
Subroutine
cr
out
(n,A
,L,U
)
implicit
none
! d
ich
iara
zio
ne
pa
ram
etr
i fo
rma
li
integer
:: n
real
(kind
=8
),
dimension
(n,n
)::
A,L
,U!
dic
hia
razi
on
i va
ria
bili
loca
li
integer
i,j,k
,im1
real
(kind
=8
)::
s
L
=0
; U
=0
do
i=1
,n
im1
=i−
1
! ca
lco
lo d
ella
i−e
sim
a c
olo
nn
a d
i L
do
j=i,n
s=0
do
k=
1,im
1;
s=s+
l(j,k
)*u
(k,i)
; end
do
l(j,i
)=a
(j,i)
−s
end
do
!
calc
olo
de
lla i−
esi
ma
rig
a d
i U
u
(i,i)
=1
do
j=i+
1,n
s=0
do
k=
1,im
1;
s=s+
l(i,k
)*u
(k,j)
end
do
u(i,j)
= (
a(i,j)
−s)
/l(i,i
)
end
do
end
do
return
mag
05,
15
17:0
1P
age
1/2
solu
zion
e−es
erci
zio−
crou
t.f90
end
su
bro
utin
e
subroutine
st
ampa
_mat
rice
(n
,M)
implicit
none
integer
:: n
integer
:: i,
j
real
(kind
=8
),
dimension
(n,n
)::
M
do
i=1
,n
do
j=1
,n;
write
(3
,10
0)
m(i,j)
; end
do
write
(3
,*)
end
do
10
0 format
(f9
.5,$
)return
end
su
bro
utin
e
ma
tric
e A
5
.00
00
0
0.0
00
00
1
.00
00
0
1.0
00
00
1
.00
00
0
1.0
00
00
1
.00
00
0
0.0
00
00
2
.00
00
0 m
atr
ice
L
5.0
00
00
0
.00
00
0
0.0
00
00
1
.00
00
0
1.0
00
00
0
.00
00
0
1.0
00
00
0
.00
00
0
1.8
00
00
ma
tric
e U
1
.00
00
0
0.0
00
00
0
.20
00
0
0.0
00
00
1
.00
00
0
0.8
00
00
0
.00
00
0
0.0
00
00
1
.00
00
0
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−
ma
tric
e A
3
.00
00
0
0.0
00
00
1
.00
00
0 −
1.0
00
00
2
.00
00
0
0.0
00
00
2
.00
00
0 −
1.0
00
00
4
.00
00
0 m
atr
ice
L
3.0
00
00
0
.00
00
0
0.0
00
00
−1
.00
00
0
2.0
00
00
0
.00
00
0
2.0
00
00
−1
.00
00
0
3.5
00
00
ma
tric
e U
1
.00
00
0
0.0
00
00
0
.33
33
3
0.0
00
00
1
.00
00
0
0.1
66
67
0
.00
00
0
0.0
00
00
1
.00
00
0
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−
ma
tric
e A
5
.00
00
0
0.0
00
00
1
.00
00
0
2.0
00
00
1
.00
00
0
3.0
00
00
1
.00
00
0
0.0
00
00
2
.00
00
0
0.0
00
00
8
.00
00
0
2.0
00
00
0
.00
00
0
1.0
00
00
1
.00
00
0
4.0
00
00
ma
tric
e L
5
.00
00
0
0.0
00
00
0
.00
00
0
0.0
00
00
1
.00
00
0
3.0
00
00
0
.00
00
0
0.0
00
00
2
.00
00
0
0.0
00
00
7
.60
00
0
0.0
00
00
0
.00
00
0
1.0
00
00
0
.73
33
3
4.0
17
54
ma
tric
e U
1
.00
00
0
0.0
00
00
0
.20
00
0
0.4
00
00
0
.00
00
0
1.0
00
00
0
.26
66
7 −
0.1
33
33
0
.00
00
0
0.0
00
00
1
.00
00
0
0.1
57
89
0
.00
00
0
0.0
00
00
0
.00
00
0
1.0
00
00
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−−
−
mag
05,
15
17:0
1P
age
2/2
solu
zion
e−es
erci
zio−
crou
t.f90
Prin
ted
by S
tude
nte
(sen
za p
assw
ord)
mar
tedÃ
¬ m
aggi
o 05
, 201
51/
1so
luzi
one−
eser
cizi
o−cr
out.f
90
Linguaggi di Programmazione per il calcolo scientifico
Interpolazione polinomiale
Dato un insieme di n + 1 nodi t0, t1, . . . , tn appartenenti ad un intervallo [a, b] e i campionamenti yi = f(ti) di unafunzione f calcolata sui nodi ti, i = 0, . . . , n, si vuole trovare una funzione f che approssimi la funzione f , tale dasoddisfare le condizioni di interpolazione f(ti) = yi, i = 0, . . . , n.In particolare, dati i valori (ti, yi), i = 0, . . . , n, con
ti, i = 0, . . . , n nodi di interpolazioneyi, i = 0, . . . , n campionamenti sui nodi in interpolazione
si vuole costruire il polinomio interpolante di grado n che approssima la funzione f .
Polinomio interpolante nella forma di Lagrange
• li(x) =
n∏j=0,j 6=i
x− tjti − tj
, i = 0, . . . , n polinomi elementari di Lagrange
• pn(x) =
n∑i=0
li(x)yi polinomio interpolante di grado n
Polinomio interpolante nella forma di Newton
• di = f [t0, t1, ..., ti], i = 0, . . . , n differenza divisa di ordine i
• pn(x) = d0+(x−t0)d1+(x−t0)(x−t1)d2+ ...+(x−t0)(x−t1)...(x−tn−1)dn polinomio interpolante di grado n
Per costruire il polinomio interpolante nella forma di Newton e prima necessario calcolare il vettore delle dif-ferenze divise.d0 = f [t0] = y0 differenza divisa di ordine zero di f relativa al nodo t0
d1 = f [t0, t1] =f [t1]− f [t0]
t1 − t0differenza divisa di ordine uno di f relativa ai nodi t0, t1
.....
dn = f [t0, ..., tn] =f [t1, ..., tn]− f [t0, ..., tn−1]
tn − t0differenza divisa di ordine n di f relativa ai nodi t0, ..., tn
Per calcolare il vettore d si parte dalla tabella delle differenze divise
f [t0] ↘f [t1] → f [t0, t1] ↘f [t2] f [t1, t2] → f [t0, t1, t2] ↘f [t3] f [t2, t3] f [t1, t2, t3] → f [t0, t1, t2, t3] ↘. . . . .. . . . .. . . . .
f [tn] f [tn−1, tn] . → f [t0, t1, ..., tn]
con f [tj ] = f(tj) e f [tj , tj+1, ..., tk] =f [tj+1, ..., tk]− f [tj , ..., tk−1]
tk − tj
e si utilizza il seguente schema che restituisce in output la diagonale della tabella, ovvero il vettore d:
Calcolo del vettore delle differenze diviseper i = 0, 1, ..., n
di = yiendper i = 1, 2, ..., n
per k = n, n− 1, ..., idk = (dk − dk−1)/(tk − tk−i)
endend
Una volta calcolato il vettore d, il valore del polinomio interpolante nella forma di Newton in un punto x puoessere ottenuto con lo schema di Horner:
Schema di Horner per il calcolo del polinomio interpolante in xP = dnper i = n− 1, n− 2, ..., 0
P = di + (x− ti) ∗ Pend
ESERCIZIO
Scrivere in linguaggio fortran la function differenze divise che riceve dal programma chiamante:• n grado del polinomio interpolante• t vettore dei nodi di interpolazione t0, t1, . . . , tn• y vettore dei campionamenti y0, y1, . . . , yn
e restituisce il vettore delle differenze divise.
Scrivere in linguaggio fortran la function poli newton che riceve dal programma chiamante:• n grado del polinomio interpolante• t vettore dei nodi di interpolazione t0, t1, . . . , tn• d vettore delle differenze divise d0, d1, . . . , dn• x punto sul quale calcolare il valore del polinomio interpolante
e restituisce il valore del polinomio interpolante calcolato in x.
Scrivere in linguaggio fortran un programma che:
1. legge in input a, b estremi dell’intervallo di interpolazione ed n grado del polinomio interpolante
2. calcola i nodi ti = a+ i h, i = 0, . . . , n, con h = (b− a)/n
3. calcola i valori yi = f(ti), i = 0, . . . , n, con f external function
4. utilizzando la function differenze divise, calcola il vettore delle differenze divise
5. utilizzando la function poli newton, calcola il valore del polinomio interpolante su una griglia di (10n+ 1) punti,salva il risultato su file e restituisce la norma infinito della differenza fra f e poli sui punti della griglia.Piu in dettaglio:per j = 0, . . . ,m, con m = 10n e k = (b− a)/m- calcola xj = a+ j k e pj valore del polinomio interpolante in xj- stampa su file xj , pj , f(xj)Al termine del ciclo, stampa a video il max dell’errore |pj − f(xj)| con j = 0, . . . ,mSuggerimento: non servono vettori, tutto in un unico ciclo con xj e pj scalari
6. richiama il programma gnuplot per disegnare il grafico della funzione f e del polinomio interpolante
Testare il programma sulla funzione f(x) = exp(x) sin(2π x)
Lavorare in doppia precisione e dichiarare tutti gli array come allocatable.Nella funzione test f , definire π come costante di valore pari a arcos(−1).Utilizzare le seguenti funzioni intrinseche:
per calcolare arcos(−1) in doppia precisione dacos(−1.d0)per calcolare exp(x) in doppia precisione dexp(x)per calcolare sin(x) in doppia precisione dsin(x)per calcolare |x| (valore assoluto) in doppia precisione dabs(x)
function
di
ffere
nze_
divi
se (
n,t,y
) result
(d
)! C
alc
ola
il v
etto
re d
elle
diff
ere
nze
div
ise
d(i)=
f[t0
,t1
,...,ti],
i=0
...n
implicit
none
integer
, intent
(IN
):: n
! g
rad
o d
el p
olin
om
io in
terp
ola
nte
real
(kind
=8
),
dimension
(0:n
):: t
! ve
tto
re d
ei n
od
i di i
nte
rpo
lazi
on
e real
(kind
=8
),
dimension
(0:n
):: y
! ve
tto
re d
ei c
am
pio
na
me
nti
ne
i no
di
real
(kind
=8
),
dimension
(0:n
):: d
! ve
tto
re d
elle
diff
ere
nze
div
ise
integer
:: i,
k d
=y
do
i=1
,n
do
k=
n,i,
−1
d
(k)=
(d(k
)−d
(k−
1))
/(t(
k)−
t(k−
i))
end
do
end
do
return
end
fu
nct
ion
function
po
li_ne
wto
n (
n,t,d
,x)
result
(p
)! C
alc
ola
ne
l pu
nto
x il
va
lore
de
l po
lino
mio
inte
rpo
lan
te
! d
i gra
do
n c
ost
ruito
su
i no
di t
_i,
i=0
...n
, co
n! t ve
tto
re d
ei n
od
i di i
nte
rpo
lazi
on
e! d
ve
tto
re d
elle
diff
ere
nze
div
ise
! Il
po
lino
mio
inte
rpo
lan
te s
i esp
rim
e n
ella
fo
rma
di N
ew
ton
! P
(x)
= d
0+
d1
*(x−
t0)+
d2
*(x−
t0)(
x−t1
)+ ...+
dn
*(x−
t0)(
x−t1
)...(x
−t_
n−
1)
! P
er
valu
tare
il v
alo
re d
el p
olin
om
io in
un
pu
nto
, si
util
izza
lo s
che
ma
di H
orn
er
implicit
none
integer
, intent
(IN
):: n
! g
rad
o d
el p
olin
om
io in
terp
ola
nte
real
(kind
=8
),
dimension
(0:n
):: t
! ve
tto
re d
ei n
od
i di i
nte
rpo
lazi
on
e real
(kind
=8
),
dimension
(0:n
):: d
! ve
tto
re d
elle
diff
ere
nze
div
ise
real
(kind
=8
):: x
! p
un
to in
cu
i va
luta
re il
po
lino
mio
real
(kind
=8
):: p
! p
olin
om
io in
terp
ola
nte
ca
lco
lato
in x
integer
:: i
p
=d
(n)
do
i=n
−1
,0,−
1 p
=p
*(x−
t(i))+
d(i)
end
do
return
end
fu
nct
ion
Program
in
terp
ola
! p
rog
ram
ma
pe
r te
sta
re la
"fu
nct
ion
po
li_n
ew
ton
" ! Il
pro
gra
mm
a ....
! −
co
no
sce
f fu
nzi
on
e te
st! −
ric
eve
in in
pu
t! [a
,b] in
terv
allo
di i
nte
rpo
lazi
on
e! n
gra
do
de
l po
lino
mio
inte
rpo
lan
te! −
ca
lco
la! t ve
tto
re d
ei n
od
i di i
nte
rpo
lazi
on
e! y
vetto
re d
ei c
am
pio
na
me
nti
y_i=
f(t_
i), i=
0...n
! d
ve
tto
re d
elle
diff
ere
nze
div
ise
d_
i=f[t_
0,t_
1,...,t_
i], i=
0...n
! −
dis
eg
na
il g
rafic
o d
el p
olin
om
io in
terp
ola
nte
e d
ella
fu
nzi
on
e te
st! su
un
a g
rig
lia d
i m=
10
n+
1 p
un
ti, e
ca
lco
la la
no
rma
infin
ito d
ell’
err
ore
! (d
iffe
ren
za fra
f e
po
li_n
ew
ton
) n
ei p
un
ti d
ella
grig
lia implicit
none
integer
:: n
! g
rad
o d
el p
olin
om
io in
terp
ola
nte
real
(kind
=8
):: a
,b
! e
stre
mi i
nte
rva
llo in
terp
ola
zio
ne
real
(kind
=8
),dimension
(:),
allocatable
:: t
! ve
tto
re d
ei n
od
i di i
nte
rpo
lazi
on
e real
(kind
=8
),dimension
(:),
allocatable
:: y
! ve
tto
re d
ei v
alo
ri y
= f(t
) real
(kind
=8
),dimension
(:),
allocatable
:: d
! ve
tto
re d
elle
diff
ere
nze
div
ise
real
(kind
=8
),external
:: f
! fu
nzi
on
e te
st
interface
function
di
ffere
nze_
divi
se (
n,t,y
) result
(d)
integer
, intent
(IN
):: n
! g
rad
o d
el p
olin
om
io in
terp
ola
nte
real
(kind
=8
),
dimension
(0:n
):: t
! ve
tto
re d
ei n
od
i di i
nte
rpo
lazi
on
e
real
(kind
=8
),
dimension
(0:n
):: y
! ve
tto
re d
ei c
am
pio
na
me
nti
ne
i no
di
real
(kind
=8
),
dimension
(0:n
):: d
! ve
tto
re d
elle
diff
ere
nze
div
ise
end
fu
nct
ion
end
interface
real
(kind
=8
),external
:: p
oli_
ne
wto
n real
(kind
=8
):: x,
h,p
,v,e
rr,c
om
integer
:: i,
j,m character
:: r
isp
ost
a
apr
05, 1
8 13
:33
Pag
e 1/
2in
terp
olaz
ione
−new
ton−
v0.f9
0print
*, "
Cal
colo
del
pol
inom
io in
terp
olan
te n
ella
form
a di
New
ton
*, "
per
la fu
nzio
ne te
st e
xp(x
)*si
n(2p
igre
co*x
)"
s
el_
inte
rva
llo:
do
do
’("
estr
emi i
nter
vallo
di i
nter
pola
zion
e [a
,b]?
",$
)’;
read
*, a
,b
if
(a
>b
) then
co
m =
a; a
=b
; b
=co
m;
exit
elseif
(a
<b
) then
exit
end
if
end
do
sel_
gra
do
: do
do
’("
grad
o de
l pol
inom
io in
terp
olan
te (
n>0)
? ",
$)’; read
*, n
if
(n
>0
) exit
end
do
allocate
(t(
0:n
), y
(0:n
), d
(0:n
))
h
=(b
−a
)/n
do
i=0
,n; t(
i) =
a+
i*h
; y
(i)
= f(t
(i))
; end
do
! C
alc
ola
le d
iffe
ren
ze d
ivis
e
d
= d
iffe
ren
ze_
div
ise
(n,t,y
)
! D
ise
gn
a il
gra
fico
de
l po
lino
mio
inte
rpo
lan
te e
de
lla fu
nzi
on
e te
st
m
= 1
0*n
! m
+1
nu
me
ro d
i pu
nti
da
util
izza
re p
er
dis
eg
na
re il
gra
fico
h
= (
b−
a)/
m; x=
a;
err
= 0
.d0
open
(3, fil
e=
’gr
afic
o.tx
t’)
do
i=0
,m
x=
a+
i*h
; p
=p
oli_
ne
wto
n(n
,t,d
,x);
v=
f(x)
write
(3
,*)
x, p
, v
err
= max
(err
, dabs
(p−
v))
end
do
close
(3
)
*, "
erro
re m
ax n
ei p
unti
utili
zzat
i per
dis
egna
re il
gra
fico
", e
rr
call
pl
ot(’
graf
ico.
txt’)
deallocate
(t, y
, d
)
’("
vuoi
cam
biar
e il
grad
o de
l pol
inom
io in
terp
olan
te?
(s/n
) [n
] ",$
)’
read
*, risp
ost
a
if
((r
isp
ost
a.ne.
"s"
).and.
(ris
po
sta
.ne.
"S"
))
exit
end
do
se
l_g
rad
o
’("
vuoi
cam
biar
e in
terv
allo
di i
nter
pola
zion
e? (
s/n)
[n] "
,$)
’
read
*, risp
ost
a
if
((r
isp
ost
a.ne.
"s"
).and.
(ris
po
sta
.ne.
"S"
))
exit
end
do
se
l_in
terv
allo
end
pro
gra
m
subroutine
pl
ot(f
ile_
gra
fico
) implicit
none
character
(len
=*)
:: file
_g
rafic
o
! sc
rive
su
l file
"fil
e_
com
an
di_
gn
up
lot"
i co
ma
nd
i ch
e g
nu
plo
t d
ovr
a’ e
seg
uire
open
(3
,file
="
file_
com
andi
_gnu
plot"
) write
(3
,*)
’se
t titl
e "I
nter
pola
zion
e ne
lla fo
rma
di N
ewto
n"’ write
(3
,*)
’pl
ot "
’,file
_g
rafic
o,’
" w
ith li
nes,
"’,file
_g
rafic
o,’
" us
ing
1:3
with
poi
nts;’
! rich
iam
a g
nu
plo
t call
sy
stem
("
gnup
lot −
pers
ist f
ile_c
oman
di_g
nupl
ot") close
(3,s
tatu
s="
dele
te")
end
su
bro
utin
e
function
f(
x) implicit
none
real
(kind
=8
):: x,
f real
(kind
=8
),
parameter
:: p
i2 =
2.d
0*
dacos
(−1
.d0
) f =
dexp
(x)*
dsin
(pi2
*x)
end
fu
nct
ion
apr
05, 1
8 13
:33
Pag
e 2/
2in
terp
olaz
ione
−new
ton−
v0.f9
0P
rinte
d by
Ale
ssan
dra
giov
edÃ
¬ a
prile
05,
201
81/
1in
terp
olaz
ione
−ne
wto
n−v0
.f90
Foglio esercizi n.8
Implementazione dei metodi numerici espliciti ad un passo per EDO in R
1
1.
Implementazione dei metodi numerici espliciti ad un passo per EDO in R
2
2.
Vedi Metodi numerici espliciti ad un passo per EDO, Esercizio sul metodo di
Runge-Kutta in R
1
(testo e svolgimento).
Linguaggi di Programmazione per il calcolo scientifico
Metodi numerici espliciti ad un passo per EDO
Approssimazione numerica del problema di Cauchy{y′(t) = f(t, y(t)) t ∈ I, y ∈ IRn
y(t0) = y0
Siano assegnati in INPUT:
• f , funzione che descrive il campo vettoriale;
• t0, y0, condizione iniziale;
• tf , tempo finale;
• n, numero di passi;
e sia h = (tf − t0)/n.
Metodo di Eulero per i = 0, . . . , n− 1
yi+1 = yi + hf(ti, yi)
ti+1 = ti + h
Metodo di Eulero modificato (Collatz)per i = 0, . . . , n− 1
yi+1 = yi + hf(ti + h2, yi + h
2f(ti, yi))
ti+1 = ti + h
Metodo di Heunper i = 0, . . . , n− 1
yi+1 = yi + h2(f(ti, yi) + f(ti+1, yi + hf(ti, yi))
ti+1 = ti + h
1
Metodo di Runge Kutta
per i = 0, . . . , n− 1
k1 = f(ti, yi)
k2 = f(ti + h2, yi + h
2k1)
k3 = f(ti + h2, yi + h
2k2)
k4 = f(ti + h, yi + hk3)
yi+1 = yi + h6(k1 + 2k2 + 2k3 + k4)
ti+1 = ti + h
• per y ∈ IR1
Scrivere un programma che calcoli l’approssimazione numerica del problema diCauchy utilizzando i metodi ad un passo espliciti di Eulero in avanti, Eulero modi-ficato, Heun e Runge-Kutta (4 ordine).Si vuole avere in OUTPUT:
– grafico nel piano (t, y) della soluzione approssimata e, quando nota, dellasoluzione esatta;
– la norma infinito del vettore degli errori, quando e nota la soluzione esatta,calcolati sui tempi discreti ti = t0 + hi, i = 0, . . . , n, h = (tf − t0)/n;
Alcuni esempi in IR1 su cui testare il programma.
1. y′ = cos(t), y(0) = 0 sol. esatta: y(t) = sin(t)
2. y′ = −ylny, y(0) = 0.5, sol. esatta: y(t) = e−e(lnln2−t)
3. y′ = −e−(t+y), y(0) = 1, sol. esatta: y(t) = ln(e + e−t − 1)
4. y′ = y(1− y), y(0) = 0.5, sol. esatta: y(t) = et/(1 + et)
5. y′ = 16y(1−y), y(0) = 1/1024, sol. esatta: y(t) = e16t−ln1023/(1+e16t−ln1023)
6. y′ = Ry(1− y/k), y(0) = x0 > 0equazione logistica con tasso di crescita R e termine asintotico K,sol. esatta y(t) = k/(1 + q e−rt), con q = (K − x0)/x0.
• per y ∈ IR2
Scrivere un programma che calcoli l’approssimazione numerica del problema diCauchy utilizzando il metodo di Runge-Kutta (4 ordine).Si vuole avere in OUTPUT il grafico della traiettoria approssimata nel piano dellefasi (x, y).
Alcuni esempi in IR2 su cui testare il programma.
1. x′ = −y, y′ = x
2. x′ = −0.05x− y, y′ = x− 0.05y
3. x′ = y, y′ = −4x
2
Linguaggi di Programmazione per il calcolo scientifico
Esercizio
Scrivere una programma in linguaggio fortran che calcoli l’approssimazione numerica del problema diCauchy {
y′(t) = f(t, y) t ∈ [t0, tf ], y ∈ IR1
y(0) = y0
utilizzando il metodo di Runge Kutta.Testare il programma sul seguente esempio:y′(t) =
et − y cos(t)sin(t)
t ∈ [π
2, 3], y ∈ IR1
y(π2 ) = eπ2
Nota la soluzione esatta y(t) =et
sin(t), si vuole avere in OUTPUT:
• grafico nel piano (t, y) della soluzione approssimata e della soluzione esatta;
• la norma infinito del vettore degli errori calcolati sui tempi discretiti = t0 + i h, i = 0, . . . , ncon n numero di passi e h = (tf − t0)/n passo di discretizzazione nel tempo.
Piu in dettaglio il main program dovra:
a) conoscere
• f(t, y) = (et − y cos(t))/sin(t), funzione che descrive il campo vettoriale;
• t0 = π/2, y0 = eπ2 , condizione iniziale;
• tf ∈ [π/2, 3], tempo finale;
• n, numero di passi;
• sol(t) = et/sin(t), soluzione esatta;
b) calcolare h = (tf − t0)/n
c) richiamare un’apposita subroutine per calcolare la traiettoria approssimata utilizzando il metododi Runge-Kutta. La subroutine dovra ricevere in input t0, y0, n, h, f e dovra restituire in output ilvettore {yi, i = 0, . . . , n}, dove yi rappresenta la posizione all’istante ti.
d) salvare su file la seguente tabella:t0 y0 sol(t0)t1 y1 sol(t1)... ... ...... ... ...tn yn sol(tn)
Calcolare e stampare a video l’errore in norma infinito.
Lavorare in doppia precisione e definire π come costante di valore pari a arcos(−1) (utilizzare la funzioneintrinseca acos).
Per disegnare il grafico della soluzione approssimata e della soluzione esatta nel piano (t, y), utilizzarel’utility gnuplot ed inviare il comando:
gnuplot> plot ”traiettoria.out” with lines, ”traiettoria.out” using 1:3 with points;
dove traiettoria.out e il nome del file sul quale e stata salvata la tabella con la soluzione approssimata ela soluzione esatta.
Program
E
DO
implicit
none
real
(kind
=8
)::
t0,t
f,h
,t,
y0
integer
:: n
real
(kind
=8
),
dimension
(:),
allocatable
::
y
real
(kind
=8
),
external
::
f
integer
i
real
(kind
=8
) ::
so
luzi
on
e,
sol,
err
real
(kind
=8
),
parameter
:: p
igre
co =
acos
(−1
.)
*,
"S
oluz
ione
del
pro
blem
a di
Cau
chy:
"
*,
"dy
/dt =
(ex
p(t)
−y*
cos(
t))/
sin(
t)
co
n y(
pigr
eco/
2)=
exp(
pigr
eco/
2)"
! scelta della posizione
t0=
pig
reco
/2;
y0 =
exp
(pig
reco
/2)
*
*,
"S
celta
dei
par
amet
ri di
inpu
t:"
do
*,
’tf=
? c
on tf
in [p
igre
co/2
,3]’;
read
*,
tf
if
((t
f <
= 3
.d0
).and.
(tf
>=
pig
reco
/2))
exit
end
do
*,
’nu
mer
o di
pas
si, n
=?’;
read
*,n
allocate
(y(
0:n
))
y(
0)
= y
0
h
= (
tf−
t0)/
n
! Calcolo della traiettoria approssimata
call
ru
ngek
utta
(t0
,n,h
,y,f
)
! Salva su file la soluzione approssimata e la soluzione esatta
! e calcola l’errore in norma infinito
open
(3
,file
=’
trai
etto
ria.d
at’,s
tatu
s=’
unkn
own’)
t=t0
err
= 0
.
do
i=0
,n
so
l = s
olu
zio
ne
(t)
write
(3,2
00
) t,
y(i),s
ol
err
= max
(err
,dabs
(y(i)−
sol))
t
=t+
h
end
do
close
(3
)
*,
"er
rore
max
nei
nod
i",
err
! Richiama gnuplot per disegnare il grafico
call
pl
ot(’
trai
etto
ria.d
at’)
deallocate
(y)
stop
20
0 format
(3
(f3
0.1
5,2
x))
end
subroutine
ru
ngek
utta
(t0
,n,h
,y,f
) implicit
none
integer
n real
(kind
=8
) t0
, h
, y(
0:n
) real
(kind
=8
),
external
::f
integer
i, n
m1
real
(kind
=8
) t,
hm
ezz
i,ym
ezz
i,tm
ezz
i,t1
,k1
,k2
,k3
,k4
t=
t0 ;
nm
1=
n−
1;
hm
ezz
i = h
/2 do
i=0
,nm
1
t
me
zzi=
t+h
me
zzi;
t1=
t+h
k1
= f
(t,y
(i))
k2
= f
(tm
ezz
i,y(i)+
hm
ezz
i*k1
)
k
3 =
f(t
me
zzi,y
(i)+
hm
ezz
i*k2
)
k
4 =
f(t
1,y
(i)+
h*k
3)
y(i+
1)=
y(i)+
h*(
k1+
2*k
2+
2*k
3+
k4)/
6
t
=t1
May
09,
13
20:1
3P
age
1/2
solu
zion
e−es
erci
zio−
rung
e−ku
tta−R
1.f9
0 end
do
return
end
subroutine
ru
ngek
utta
subroutine
pl
ot(f
ile_
tra
iett
oria
) implicit
none
character
(len
=*)
:: f
ile_
tra
iett
oria
character
(len
=*)
, parameter
:: c
om
ma
nd
= "
/usr
/bin
/gnu
plot
−pe
rsis
t com
andi
_gnu
plot
"! scrive su file i comandi che gnuplot dovra’ eseguire
open
(3
,file
="
com
andi
_gnu
plot"
) write
(3
,*)
’se
t titl
e "T
raie
ttoria
"’ write
(3
,*)
’pl
ot "
’, fil
e_
tra
iett
oria
, ’
" w
ith li
nes,
"’,&
fil
e_
tra
iett
oria
,’"
usin
g 1:
3 w
ith p
oint
s;’
! richiama gnuplot
call
sy
stem
(co
mm
an
d)
close
(3
, st
atu
s="
dele
te")
end
su
bro
utin
e
function
f
(t,x
)! campo vettoriale
implicit
none
real
(kind
=8
)::
f,t,
x
f
= (
exp
(t)−
x*cos
(t))
/sin
(t)
return
end
function
f
function
so
luzi
one
(t)
! soluzione esatta
implicit
none
real
(kind
=8
)::
solu
zio
ne
, t
solu
zio
ne
=
exp
(t)/
sin
(t)
return
end
function
so
luzi
one
May
09,
13
20:1
3P
age
2/2
solu
zion
e−es
erci
zio−
rung
e−ku
tta−R
1.f9
0
Prin
ted
by S
eghi
ni
Thu
rsda
y M
ay 0
9, 2
013
1/1
solu
zion
e−es
erci
zio−
rung
e−ku
tta−
R1.
f90
PUNTATORI
Il fortran 90 introduce il concetto di puntatore, come attributo di un dato. I puntatori
permettono di gestire strutture dati come liste lineari, alberi e grafi.
Esempio di dichiarazione di puntatori:
! PT è il puntatore ad una variabile di tipo realeREAL, POINTER :: PT
! p è il puntatore ad una variabile di tipo "persona"TYPE (persona), POINTER :: p
! c è il puntatore ad una variabile di tipo "cerchio"TYPE (cerchio), POINTER :: c
Su una variabile con attributo pointer si possono utilizzare le seguenti istruzioni:
ALLOCATE (PT)
alloca uno spazio in memoria per una variabile del tipo puntato da PT; lo stato
del puntatore diventa associated.
DEALLOCATE (PT)
rilascia lo spazio in memoria puntato da PT; lo stato del puntatore diventa
disassociated.
NULLIFY (PT)
disassocia il puntatore dal target, lo spazio in memoria non viene rilasciato.
Questa istruzione può essere utilizzata anche per assegnare lo stato
disassociated ad un puntatore con stato indefinito.
ASSOCIATED (PT)
"inquiry intrinsic function" che riporta il valore .TRUE. se il puntatore PT è
associato, il valore .FALSE. altrimenti.
PT2 => PT1
operazione di assegnazione fra puntatori.
È importante tener presente che in un programma fortran lo stesso nome è utilizzato sia
per indicare il puntatore ad una variabile sia per indicare il valore della variabile puntata,
come si vede nel seguente esempio:
1) real, pointer:: p1, p22) real:: c3) allocate(p1)4) p1 = 4.55) p2 => p16) c = p1 + p2
Cosa fanno queste poche righe di codice?
riga 3) viene allocato in memoria uno spazio adatto a memorizzare una variabile reale in singola
precisione (4 byte) e il puntatore p1 viene associato alla locazione di memoria (operazione sul
puntatore p1);
riga 4)
nella locazione di memoria puntata da p1 viene scritto il valore 4.5 (operazione sulla variabile
puntata da p1);
riga 5) il puntatore p2 viene associato alla stessa locazione di memoria alla quale è associato p1; quindi
entrambi i puntatori punteranno alla "casella" di memoria contenente il valore 4.5 (operazione sui
puntatori p1 e p2);
riga 6) alla variabile reale c viene assegnato il valore dato dalla somma dei valori contenuti nelle locazioni
di memoria puntate da p1 e p2 (operazioni sulle variabili puntate da p1 e p2)
LE LISTE LINEARI
Una lista lineare è una successione ordinata di elementi omogenei (tutti dello stesso
tipo), ma, diversamente da un array, gli elementi che compongono la lista non occupano
locazioni di memoria consecutive, ma posizioni qualsiasi, è quindi necessario che ogni
elemento della lista contenga un puntatore che lo colleghi all'elemento successivo.
Un'altra importante differenza fra array e liste è che, mentre la dimensione di un array
deve essere nota a priori e non può essere modificata, la dimensione della lista cambia
dinamicamente ogni volta che si aggiunge o si cancella un elemento.
Un elemento della lista conterrà uno o più campi informazione ed il puntatore
all'elemento successivo, sarà quindi necessario definire un tipo derivato che descriva il
generico elemento della lista:
ESEMPI:1) Elemento di una lista di numeri interi type item integer :: index type (item), pointer :: next end type item
2) Elemento di una lista di punti nel piano R^2 type punto real :: x,y type (punto), pointer :: next end type punto
3) Elemento di una lista di persone type persona character(len=20) cognome, nome integer eta type (persona), pointer :: next end type persona
Una lista lineare è ben costruita e tutti gli elementi sono accessibili se:
si conosce il puntatore al primo elemento;1.
ogni elemento è collegato al successivo tramite il suo campo "puntatore al
successivo" (negli esempi sopra, campo next);
2.
il campo "puntatore al successivo" dell'ultimo elemento punta a NULL e così chiude
la lista.
3.
Riportatiamo di seguito un primo esempio per la costruzione di una lista di numeri interi.
Altri esempi sono disponibili in laboratorio nella cartella /corsi/seghini/LPCS.
ESEMPIO:! Esempio di costruzione e scorrimento di una lista! Costruzione lista "aggiungendo in testa"
Module definizione_lista implicit none
type item integer :: index type (item), pointer :: next end type itemend module definizione_lista
Program lista use definizione_lista implicit none type (item), pointer :: first interface subroutine costruisci_lista (first) use definizione_lista type (item), pointer :: first end subroutine costruisci_lista subroutine stampa_lista (first) use definizione_lista type (item), pointer :: first end subroutine stampa_lista end interface call costruisci_lista(first) call stampa_lista (first) stopend program lista
subroutine costruisci_lista(first) ! costruisce la lista, aggiungendo in testa use definizione_lista implicit none type (item), pointer :: first, current integer key nullify(first) ! inizializza a NULL la testa della lista do print *, 'dammi un elemento della lista (stop per terminare)' read (*,*, ERR=99) key allocate (current) current = item(key,first) ! current%index=key ; current%next => first first => current end do99 returnend subroutine costruisci_lista
subroutine stampa_lista (first) ! scorre e stampa la lista use definizione_lista implicit none type (item), pointer :: first, current current => first do while (associated(current)) print *, current%index current => current%next end do returnend subroutine stampa_lista
La subroutine "costruisci_lista" dell'esempio precedente potrebbe anche essere
strutturata nel seguente modo:
subroutine costruisci_lista(first) use definizione_lista implicit none type (item), pointer :: first integer key interface subroutine aggiungi_in_testa (first,key) use definizione_lista type (item), pointer :: first integer key end subroutine aggiungi_in_testa end interface nullify(first) ! inizializza a NULL la testa della lista do print *, 'dammi un elemento della lista (stop per terminare)' read (*,*,ERR=99) key call aggiungi_in_testa (first,key) end do99 returnend subroutine costruisci_lista
subroutine aggiungi_in_testa(first,key) use definizione_lista implicit none type (item), pointer :: first, current integer key allocate (current) current = item(key,first) ! current%index=key ; current%next => first first => current returnend subroutine aggiungi_in_testa
Foglio esercizi n.9
Alcune operazioni che dovreste saper fare sulle liste:
costruire la lista:
- aggiungere un elemento in testa
- aggiungere un elemento in coda
- inserire un nuovo elemento rispettando un criterio di ordinamento
- costruire la lista con metodo ricorsivo
1.
scorrere la lista per fare un'operazione su ogni elemento della lista (ad esempio
stampare ogni elemento della lista);
2.
eliminare un elemento dalla lista:
- eliminare il primo elemento
- eliminare l'ultimo elemento
- eliminare il primo elemento con una 'chiave' fissata
- eliminare tutti gli elementi con una 'chiave' fissata
3.
invertire una lista;4.
ordinare gli elementi di una lista.5.
Le soluzioni sono disponibli in laboratorio nella cartella /corsi/seghini/LPCS.
PRINCIPALI LIMITI DEL F77 RISPETTO AL F90/F95
rigidità del formato di una riga di programma;
nomi di variabili, procedure, etc. max 6 caratteri;
per variabili e costanti scalari solo i 6 tipi intrinseci.
Non sono ammessi real ed integer di tipo parametrizzato;
dati di tipo strutturato: solo array con gestione "statica" della
memoria. Non sono ammessi array rilocabili, puntatori, tipi di
dati derivati;
non ci sono le istruzioni: case, end do, exit, cycle, do while;
non è ammessa la ricorsività
non ci sono l'unità di programma module e la direttiva use.
NOTE PER UTILIZZO COMPILATORE FORTRAN CON LINUX
Queste pagine sono estratte dalle note del corso "Abilità Informatiche: Introduzione a Unix", Alessandra Seghini
Per stampare questo documento si consiglia di utilizzare la versione in formato PDF.
Alcuni termini da conoscere
FilesystemSu un sistema UNIX i file sono suddivisi in directory (cartelle). Le directory sono organizzategerarchicamente in una struttura ad albero che prende il nome di filesystem. La directory radice èindicata con il simbolo / e prende il nome di root directory.
Home directoryAl login ogni utente si trova posizionato sulla propria home directory.È possibile riferirsi alla home directory di un utente con "~nome_utente", ad esempio ~studente può essereutilizzato per indicare la directory /home/studente/. Ogni utente può riferirsi alla propria home directory semplicemente con il carattere ~, senza specificare lousername.
Directory correnteLa directory corrente di lavoro è quella sulla quale si è posizionati. È possibile conoscere il nome delladirectory corrente, utilizzando il comando pwd. Al login, la directory corrente di un utente è la sua homedirectory.La directory corrente è indicata con il simbolo "."La directory "genitore" della directory corrente è indicata con il simbolo ".."
PathnamePer individuare un file sul sistema, è necessario conoscere il suo pathname, costituito dal nome del file,preceduto dal nome della directory che lo contiene.
/____ .... |__ .... |__ home/ ____ .... | |__ giulia/ ___ .... | | |__ immagini/ ____ .... | | | |__ foto.jpg | | | |__ .... | | |__ .... | |__ paolo/ | |__ .... |__ ... |__ ...
Ad esempio, il nome completo del file foto.jpg contenuto nella directory /home/giulia/immagini/ è/home/giulia/immagini/foto.jpg. Abbiamo così specificato il percorso assoluto, che permette diraggiungere il file foto.jpg a partire dalla radice (/) del filesystem e che, pertanto, è valido qualunque siala directory corrente.È possibile individuare un file anche specificando il percorso relativo, rispetto alla directory sulla quale ci sitrova posizionati, ovvero rispetto alla directory corrente. Se ad esempio siamo sulla directory/home/giulia/, possiamo riferirci al file /home/giulia/immagini/foto.jpg semplicemente indicandoimmagini/foto.jpg (senza il carattere / iniziale). In questo caso, il percorso per raggiungere il filefoto.jpg non parte dalla radice del filesystem, ma dalla directory corrente e, pertanto, è valido solo se ladirectory corrente è /home/giulia/. Nello specificare il pathname di un file, si possono utilizzare i caratteri . , .. e ~ per indicare rispettivamentela directory corrente, la directory di livello superiore rispetto alla directory corrente e la home directory diun utente. Ad esempio, un percorso assoluto per individuare il nostro solito file foto.jpg, è anche~giulia/immagini/foto.jpg.Se la directory corrente è la home directory dell'utente paolo /home/paolo/ (o ~paolo), il percorso relativoper individuare il file foto.jpg sarà ../giulia/immagini/foto.jpg.
Alcuni comandi utili
ls [nome-dir]riporta l'elenco dei file contenuti nella directory nome-dir. Se non è specificato il nome di una directory,riporta l'elenco dei file contenuti nella directory corrente.
archimede%lsMail bookmarks.html help help-alex lq
Qualche opzione del comando ls (è possibile combinare insieme più opzioni):
ls -a [nome-dir]riporta l'elenco di tutti (all) i file contenuti nella directory nome-dir, compresi i file nascosti il cui nomeinizia con il carattere ".". Nell'elenco sono compresi anche i file . e .. , che indicano rispettivamente, ladirectory corrente e la directory "genitore" della directory corrente.
archimede%ls -a. .Mathematica .history bookmarks.html help-alex.. .cshrc Mail help lq
ls -l [nome-dir]riporta l'elenco dei file contenuti nella directory nome-dir, in formato esteso (long).
archimede%ls -latotal 84drwxr-xr-x 5 giulia users 512 Jan 26 08:52 .drwxr-xr-x 31 root root 2560 Jan 26 09:11 ..drwxr-xr-x 8 giulia users 512 Jun 7 2004 .Mathematica-rw-r--r-- 1 giulia users 1487 Nov 29 08:52 .cshrc-rw------- 1 giulia users 2607 Jan 25 15:23 .historydrwx------ 2 giulia users 512 Apr 13 2000 Mail-rw------- 1 giulia users 28244 Jul 17 2002 bookmarks.htmldrwxr-xr-x 2 giulia users 512 Jan 12 2004 helplrwxrwxrwx 1 giulia users 15 Jan 26 08:52 help-alex -> /home/alex/help-rwxr-xr-x 1 giulia users 280 Jun 15 2004 lq
mkdir nome-dircrea una nuova directory
rmdir nome-dirrimuove la directory specificata (deve essere vuota)
cd [nome-dir]cambia directory, spostandosi nella directory indicata. Se nome-dir non è specificato, si sposta nella homedirectory dell'utente
cp file1 file2copia il file file1 sul file file2. Se file2 non esiste, crea un nuovo file, altrimenti lo sovrascrive. Nell'indicare file1 e file2 è necessario specificare, ove necessario, il pathname completo.
mv file1 file2sposta il file file1 sul file file2. Se file2 non esiste, crea un nuovo file, altrimenti lo sovrascrive. Questocomando può essere utilizzato per cambiare il nome di un file o per spostarlo in un'altra directory. Nell'indicare file1 e file2 è necessario specificare, ove necessario, il pathname completo.
rm file1 [file2 file3 ...]elimina il/i file indicati.
more nome-filevisualizza sul terminale il contenuto di un file di testo, mostrando una schermata alla volta. Per scorrereall'interno del documento utilizzare i tasti:
[INVIO] - avanza di una rigabarra spaziatrice - avanza di una schermata
b - torna indietro di una schermataq - esce
Stampa di un file
Il comando lpr nome-file invia il file nome-file alla stampante principale collegata al sistema.Se il file da stampare è un file in formato testo, come ad esempio il sorgente di un programma C o fortran, potràessere necessario trasformare il file in formato postscript, prima di mandarlo in stampa. Ad esempio, perstampare il file mioprog.f90, si potrà utilizzare la sequenza di comandi:
a2ps mioprog.f90 -o mioprog.pslpr mioprog.ps
Il comando a2ps trasforma il file testo ricevuto in input in formato postscript. Se non vengono specificate opzioni,i fogli del file di output saranno orientati in senzo orizzontale e su ogni foglio saranno stampate due pagine. Se sidesidera che il file di output abbia i fogli orientati in senso verticale e che su ogni foglio venga stampata una solapagina, si dovrà utilizzare il comando:
a2ps mioprog.f90 -o mioprog.ps --chars-per-line=80 --columns=1 --portrait
Prima di inviare in stampa il file mioprog.ps, è possibile visualizzarlo a schermo utilizzando il comando:
gv mioprog.ps &
Cenni sull'utilizzo dell'editor emacs
Per editare un file con emacs, inviare il comando:
emacs nome-file &
Il file nome-file sarà caricato nella finestra di editing.
Per uscire da emacs, selezionare "Exit Emacs" alla voce "Files" del pop menù, oppure digitare la sequenza di tasti<CTRL>x <CTRL>c. Se sono state apportate modifiche al file aperto, emacs chiederà la conferma, prima disalvare il file.
Per salvare le modifiche, senza uscire dall'editor, selezionare "Save Buffer" alla voce "Files" del pop menù, oppuredigitare la sequenza di tasti <CTRL>x <CTRL>s.
emacs è un editor di facile utilizzo. Tutto funziona in maniera molto semplice. Il testo viene inseritoautomaticamente nel punto in cui si trova posizionato il cursore. È possibile spostarsi nel testo utilizzando sia ilmouse sia la tastiera. Dai pop menù sono disponibili la maggior parte dei comandi tipici dei programmi di editing(copy, cut, paste, search, etc.)Per maggiori informazioni si rimanda all'help in linea, richiamabile dal pop menù di emacs alla voce "Help".
Editare, compilare ed eseguire un programma fortran
La creazione di un programma scritto in un linguaggio ad alto livello, come il C ed il fortran, prevede diversefasi per arrivare ad ottenere un codice eseguibile:
Creazione del codice sorgente, ovvero scrittura, tramite un editor, del/dei files contenenti le istruzioniche il programma dovrà eseguire.
Compilazione del codice sorgente. In questa fase, il compilatore individua e segnala gli eventuali errori disintassi. È allora necessario utilizzare l'editor per correggere gli errori, salvare il file corretto e quindiricompilare il programma. Una volta eliminati tutti gli errori, il compilatore traduce il codice sorgente incodice oggetto.
Linking (collegamento) di tutti i file oggetto e delle librerie che concorrono a formare il programmaeseguibile.
A questo punto, sarà possibile eseguire il programma.
Vediamo un esempio.
1. Utilizzando un editor creare il file rad2gr.f90, contenente le seguenti righe di codice sorgente:
! Questo programma converte la misura di un angolo da radianti a gradiProgram rad2gr implicit none real, parameter :: Pi = 3.14159 real :: gradi, radianti print *, "Misura dell'angolo in radianti? " read *, radianti gradi = 180.*radianti/Pi print *, radianti, " radianti = ",gradi," gradi"end program rad2gr
Può essere conveniente aprire la finestra di editing in background, utilizzando, ad esempio, il comando
emacs rad2gr.f90&
In questo modo, la shell resterà attiva e sullo schermo saranno disponibili due finestre: la finestra diediting, per correggere gli errori e salvare il file modificato e la shell per compilare.
2. Per compilare, inviare il comando:
gfortran rad2gr.f90
Verranno segnalati eventuali errori, che dovranno essere corretti.f90 eseguirà quindi le operazioni di compilazione e di linking e salverà il programma eseguibile nel filea.out.È possibile assegnare un nome diverso da a.out al programma eseguibile, utilizzando l'opzione -o(output) nel comando di compilazione:
gfortran rad2gr.f90 -o rad2gr
In questo caso, il programma eseguibile verrà salvato nel file rad2gr.
3. Per eseguire il programma, digitare il nome del file completo del percorso:
./rad2gr
Riepilogo delle operazioni da effettuare per l'esercitazione in laboratorio
L'esercitazione si svolge nel Laboratorio didattico di Calcolo, utilizzando il GNU Fortran Compiler in ambienteLinux.
OPERAZIONI INZIALI
1. Accendere il computer, attivare il s.o. linux e collegarsi al sistema.Aprire una shell, ovvero una finestra nella quale è attivo l'interprete dei comandi (shell) checonsente di interagire con il sistema operativo.
2. Creare sull'hard disk una directory di lavoro e posizionarcisi:
mkdir miadir cd miadir
3. Se necessario, montare la pendrive usb e copiare il sorgente del programma sul quale si develavorare sulla directory di lavoro miadir:
cp /media/nome_usb_device/mioprog.f90 .
ESERCITAZIONE
4. Editare, compilare ed eseguire il programma:
emacs mioprog.f90 & per editare
gfortran mioprog.f90 -o mioprog per compilare
./mioprog per eseguire
Attenzione: ogni volta che si modifica il sorgente con l'editor, è necessario salvare il file modificato epoi ricompilare.
OPERAZIONI FINALI
5. Se necessario, copiare il sorgente del programma sul quale si è lavorato, dalla directory di lavoro allapendrive usb:
cp mioprog.f90 /media/nome_usb_device
Per salvare il file sulla pendrive usb, assegnandogli un nuovo nome:
cp mioprog.f90 /media/nome_usb_device/newprog.f90
Per copiare tutti i file con estensione .f90 dalla directory di lavoro alla pendrive usb:
cp *.f90 /media/nome_usb_device
6. Prima di estrarre la pendrive usb smontarla dal filesystem: con il tasto destro del mouse cliccaresull'icona della pendrive che si trova sul desktop e selezionare la voce Eject.
7. Spegnere il computer utilizzando l'apposito bottone che appare sulla barra nella parte bassa delmonitor.
top related