fortran - rip tutorial · 2019-01-18 · fortran 95 procedure pure ed elementali 1997/06/15 fortran...
TRANSCRIPT
Fortran
#fortran
Sommario
Di 1
Capitolo 1: Iniziare con Fortran 2
Osservazioni 2
Versioni 2
Examples 2
Installazione o configurazione 2
Ciao mondo 3
Equazione quadrata 4
Case insensibilità 5
Capitolo 2: Alternative moderne a caratteristiche storiche 6
Examples 6
Tipi di variabili implicite 6
Aritmetica se dichiarazione 7
Costrutti DO non bloccanti 8
Ritorno alternativo 8
Modulo Fisso 10
Blocchi comuni 11
GOTO assegnato 13
GOTO calcolato 14
Specificatori di formato assegnati 14
Funzioni di dichiarazione 15
Capitolo 3: Array 17
Examples 17
Notazione di base 17
Matrici allocative 18
Costruttori di array 18
Specifica della natura della matrice: rango e forma 20
Forma esplicita 21
Forma assunta 21
Dimensione presunta 21
Forma differita 22
Forma implicita 22
Intere matrici, elementi di array e sezioni di array 22
Interi array 23
Elementi di matrice 23
Sezioni di matrice 23
Componenti dell'array di array 24
Operazioni di matrice 25
Addizione e sottrazione 25
Funzione 25
Moltiplicazione e divisione 25
Operazioni con matrici 26
Sezioni di array avanzate: triplet di pedici e pedici vettoriali 26
Triplette degli abbonati 26
Sottoscrizioni del vettore 27
Sezioni dell'array di rank più alto 27
Capitolo 4: Controllo dell'esecuzione 29
Examples 29
Se costrutto 29
SELEZIONA il costrutto CASE 30
Costruisci il blocco DO 31
DOVE costruisci 33
Capitolo 5: Estensioni di file di origine (.f, .f90, .f95, ...) e in che modo sono correla 35
introduzione 35
Examples 35
Estensioni e significati 35
Capitolo 6: I / O 37
Sintassi 37
Examples 37
I / O semplice 37
Leggi con alcuni errori di controllo 37
Passando gli argomenti della riga di comando 38
Capitolo 7: Interfacce esplicite e implicite 41
Examples 41
Sottoprogrammi interni / moduli e interfacce esplicite 41
Sottoprogrammi esterni e interfacce implicite 42
Capitolo 8: Interoperabilità C 44
Examples 44
Chiamando C da Fortran 44
C structs in Fortran 45
Capitolo 9: Procedure intrinseche 46
Osservazioni 46
Examples 46
Usando PACK per selezionare elementi che soddisfano una condizione 46
Capitolo 10: Procedure: funzioni e subroutine 48
Osservazioni 48
Examples 48
Sintassi della funzione 48
Dichiarazione di ritorno 49
Procedure ricorsive 49
L'intento di argomenti fittizi 50
Fare riferimento a una procedura 51
Capitolo 11: Programmazione orientata agli oggetti 54
Examples 54
Definizione del tipo derivato 54
Digitare le procedure 54
Tipi derivati astratti 55
Digita estensione 56
Tipo costruttore 57
Capitolo 12: Tipi di dati 59
Examples 59
Tipi intrinseci 59
Tipi di dati derivati 60
Precisione dei numeri in virgola mobile 61
Parametri di tipo lunghezza presunta e differita 63
Costanti letterali 64
Accesso alle sottostringhe dei caratteri 66
Accesso a componenti complessi 67
Dichiarazione e attributi 67
Capitolo 13: Unità di programma e layout di file 69
Examples 69
Programmi Fortran 69
Moduli e sottomoduli 70
Procedure esterne 70
Blocca le unità del programma di dati 71
Sottoprogrammi interni 71
File di codice sorgente 72
Capitolo 14: Utilizzo dei moduli 74
Examples 74
Sintassi del modulo 74
Utilizzo di moduli da altre unità di programma 74
Moduli intrinseci 76
Controllo di accesso 76
Entità modulo protetto 78
Titoli di coda 79
Di
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version from: fortran
It is an unofficial and free Fortran ebook created for educational purposes. All the content is extracted from Stack Overflow Documentation, which is written by many hardworking individuals at Stack Overflow. It is neither affiliated with Stack Overflow nor official Fortran.
The content is released under Creative Commons BY-SA, and the list of contributors to each chapter are provided in the credits section at the end of this book. Images may be copyright of their respective owners unless otherwise specified. All trademarks and registered trademarks are the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/it/home 1
Capitolo 1: Iniziare con Fortran
Osservazioni
Fortran è un linguaggio ampiamente utilizzato nella comunità scientifica per la sua idoneità al calcolo numerico. Particolarmente interessante è la notazione intuitiva degli array, che semplifica la scrittura di calcoli vettoriali veloci.
Nonostante la sua età, Fortran è ancora attivamente sviluppato, con numerose implementazioni, tra cui GNU, Intel, PGI e Cray.
Versioni
Versione Nota pubblicazione
FORTRAN 66 Prima standardizzazione di ASA (ora ANSI) 1966/03/07
FORTRAN 77 Fixed Form, Historic 1978/04/15
Fortran 90 Forma libera, standard ISO, operazioni di matrice 1991/06/15
Fortran 95 Procedure pure ed elementali 1997/06/15
Fortran 2003 Programmazione orientata agli oggetti 2004/04/04
Fortran 2008 Co-Array 2010-09-10
Examples
Installazione o configurazione
Fortran è un linguaggio che può essere compilato utilizzando i compilatori forniti da molti fornitori. Sono disponibili diversi compilatori per diverse piattaforme hardware e sistemi operativi. Alcuni compilatori sono software gratuiti, alcuni possono essere utilizzati gratuitamente e alcuni richiedono l'acquisto di una licenza.
Il compilatore Fortran gratuito più comune è GNU Fortran o gfortran. Il codice sorgente è disponibile da GNU come parte di GCC, la raccolta del compilatore GNU. I binari per molti sistemi operativi sono disponibili su https://gcc.gnu.org/wiki/GFortranBinaries . Le distribuzioni Linux contengono spesso gfortran nel loro gestore di pacchetti.
Ulteriori compilatori sono disponibili ad esempio:
EKOPath di PathScale•LLVM (backend via DragonEgg)•
https://riptutorial.com/it/home 2
Oracle Developer Studio•
Absoft Fortran Compiler•Intel Fortran Compiler•NAG Fortran Compiler•Compilatori IGP•
Sui sistemi HPC esistono spesso compilatori specializzati disponibili dal fornitore del sistema come ad esempio i compilatori IBM o Cray .
Tutti questi compilatori supportano lo standard Fortran 95. Una panoramica sullo stato di Fortran 2003 e lo stato di Fortran 2008 da parte di vari compilatori è offerta dal forum Fortran ACM e disponibile in Fortran Wiki.
Ciao mondo
Qualsiasi programma Fortran deve includere la end come ultima dichiarazione. Pertanto, il programma Fortran più semplice ha il seguente aspetto:
end
Ecco alcuni esempi di programmi "ciao, mondo":
print *, "Hello, world" end
Con la dichiarazione di write :
write(*,*) "Hello, world" end
Per chiarezza ora è comune usare l'istruzione del program per avviare un programma e dargli un nome. L'istruzione end può quindi fare riferimento a questo nome per rendere evidente ciò a cui si riferisce e lasciare che il compilatore verifichi il codice per la correttezza. Inoltre, tutti i programmi Fortran dovrebbero includere implicit none dichiarazione implicit none . Pertanto, un programma Fortran minimamente dovrebbe apparire come segue:
program hello implicit none write(*,*) 'Hello world!' end program hello
Il prossimo passo logico da questo punto è come vedere il risultato del programma Hello World. Questa sezione mostra come ottenerlo in un ambiente simile a Linux. Assumiamo che tu abbia alcune nozioni di base sui comandi della shell , principalmente sai come arrivare al terminale della shell. Supponiamo anche che tu abbia già configurato il tuo ambiente fortran . Usando il tuo editor di testo preferito (notepad, notepad ++, vi, vim, emacs, gedit, kate, ecc.), Salva il programma ciao sopra (copia e incolla) in un file chiamato hello.f90 nella tua home directory. hello.f90 è il tuo file
https://riptutorial.com/it/home 3
sorgente. Quindi vai alla riga di comando e vai alla directory (home directory?) In cui hai salvato il file sorgente, quindi digita il seguente comando:
>gfortran -o hello hello.f90
Hai appena creato il tuo programma Hello World eseguibile. In termini tecnici, hai appena compilato il tuo programma. Per eseguirlo, digitare il seguente comando:
>./hello
Dovresti vedere la seguente riga stampata sul tuo terminale shell.
> Hello world!
Congratulazioni, hai appena scritto, compilato e eseguito il programma "Hello World".
Equazione quadrata
Oggi Fortran è utilizzato principalmente per il calcolo numerico. Questo esempio molto semplice illustra la struttura di base del programma per risolvere equazioni di secondo grado:
program quadratic !a comment !should be present in every separate program unit implicit none real :: a, b, c real :: discriminant real :: x1, x2 print *, "Enter the quadratic equation coefficients a, b and c:" read *, a, b, c discriminant = b**2 - 4*a*c if ( discriminant>0 ) then x1 = ( -b + sqrt(discriminant)) / (2 * a) x2 = ( -b - sqrt(discriminant)) / (2 * a) print *, "Real roots:" print *, x1, x2 ! Comparison of floating point numbers for equality is often not recommended. ! Here, it serves the purpose of illustrating the "else if" construct. else if ( discriminant==0 ) then x1 = - b / (2 * a) print *, "Real root:" print *, x1 else print *, "No real roots." end if
https://riptutorial.com/it/home 4
end program quadratic
Case insensibilità
Le lettere maiuscole e minuscole dell'alfabeto sono equivalenti nel set di caratteri di Fortran. In altre parole, Fortran non fa distinzione tra maiuscole e minuscole . Questo comportamento è in contrasto con i linguaggi case-sensitive, come C ++ e molti altri.
Di conseguenza, le variabili a e A sono la stessa variabile. In linea di principio si potrebbe scrivere un programma come segue
pROgrAm MYproGRaM .. enD mYPrOgrAM
È per il buon programmatore evitare queste brutte scelte.
Leggi Iniziare con Fortran online: https://riptutorial.com/it/fortran/topic/904/iniziare-con-fortran
https://riptutorial.com/it/home 5
Capitolo 2: Alternative moderne a caratteristiche storiche
Examples
Tipi di variabili implicite
Quando Fortran era originariamente sviluppato, la memoria era un premio. Le variabili e i nomi delle procedure potevano avere un massimo di 6 caratteri e le variabili venivano spesso digitate implicitamente . Ciò significa che la prima lettera del nome della variabile determina il suo tipo.
le variabili che iniziano con i, j, ..., n sono integer•tutto il resto (a, b, ..., h, e o, p, ..., z) sono real•
Programmi come il seguente sono accettabili Fortran:
program badbadnotgood j = 4 key = 5 ! only the first letter determines the type x = 3.142 print*, "j = ", j, "key = ", key, "x = ", x end program badbadnotgood
Potresti anche definire le tue regole implicite con la dichiarazione implicit :
! all variables are real by default implicit real (a-z)
o
! variables starting with x, y, z are complex ! variables starting with c, s are character with length of 4 bytes ! and all other letters have their default implicit type implicit complex (x,y,z), character*4 (c,s)
La tipizzazione implicita non è più considerata la migliore pratica. È molto facile commettere un errore utilizzando la digitazione implicita, poiché gli errori di battitura possono passare inosservati, ad es
program oops real :: somelongandcomplicatedname ... call expensive_subroutine(somelongandcomplEcatedname) end program oops
Questo programma funzionerà felicemente e farà la cosa sbagliata.
https://riptutorial.com/it/home 6
Per disattivare la digitazione implicita, è possibile utilizzare l'istruzione implicit none .
program much_better implicit none integer :: j = 4 real :: x = 3.142 print*, "j = ", j, "x = ", x end program much_better
Se avessimo usato implicit none nel programma oops sopra, il compilatore si sarebbe accorto immediatamente e avrebbe prodotto un errore.
Aritmetica se dichiarazione
L'istruzione aritmetica if consente di utilizzare tre rami in base al risultato di un'espressione aritmetica
if (arith_expr) label1, label2, label3
Questa istruzione if trasferisce il flusso di controllo a una delle etichette in un codice. Se il risultato di arith_expr è negativo, l' label1 è coinvolta, se il risultato è zero label2 viene utilizzato e se il risultato è positivo, viene applicata l'ultima label3 . Aritmetica if richiede tutte e tre le etichette ma consente il riutilizzo di etichette, quindi questa affermazione può essere semplificata in due rami if .
Esempi:
if (N * N - N / 2) 130, 140, 130 if (X) 100, 110, 120
Ora, questa funzione è obsoleta con la stessa funzionalità offerti dal if dichiarazione e if-else costrutto. Ad esempio, il frammento
if (X) 100, 110, 120 100 print*, "Negative" goto 200 110 print*, "Zero" goto 200 120 print*, "Positive" 200 continue
può essere scritto come il costrutto if-else
if (X<0) then print*, "Negative" else if (X==0) then print*, "Zero" else print*, "Positive" end if
https://riptutorial.com/it/home 7
Una sostituzione di dichiarazione if per
if (X) 100, 100, 200 100 print *, "Negative or zero" 200 continue
può essere
if (X<=0) print*, "Negative or zero"
Costrutti DO non bloccanti
La non-blocco do costruire assomiglia
integer i do 100, i=1, 5 100 print *, i
Cioè, dove la dichiarazione di terminazione etichettata non è una dichiarazione continue . Ci sono varie restrizioni sulla dichiarazione che può essere usata come dichiarazione di terminazione e l'intera faccenda è generalmente molto confusa.
Tale costrutto non blocco può essere riscritto in forma di blocco come
integer i do 100 i=1,5 print *, i 100 continue
o meglio, usando una dichiarazione di end do ,
integer i do i=1,5 print *, i end do
Ritorno alternativo
Il ritorno alternativo è una funzione per controllare il flusso di esecuzione al ritorno da una subroutine. È spesso usato come una forma di gestione degli errori:
real x call sub(x, 1, *100, *200) print*, "Success:", x stop 100 print*, "Negative input value" stop 200 print*, "Input value too large"
https://riptutorial.com/it/home 8
stop end subroutine sub(x, i, *, *) real, intent(out) :: x integer, intent(in) :: i if (i<0) return 1 if (i>10) return 2 x = i end subroutine
Il ritorno alternativo è contrassegnato dagli argomenti * nell'elenco degli argomenti fittizi subroutine.
Nell'istruzione di call sopra *100 e *200 riferiscono rispettivamente alle dichiarazioni 100 e 200 .
Nella subroutine stessa le dichiarazioni di return corrispondenti al ritorno alternativo hanno un numero. Questo numero non è un valore di ritorno, ma indica l'etichetta fornita a cui viene trasmessa l'esecuzione al reso. In questo caso, return 1 passa l'esecuzione all'istruzione 100 e return 2 passaggi all'esecuzione etichettata 200 . Una dichiarazione di return senza ornamenti, o il completamento dell'esecuzione di subroutine senza una dichiarazione di return , l'esecuzione della passata immediatamente dopo l'istruzione di chiamata.
La sintassi di ritorno alternativa è molto diversa dalle altre forme di associazione degli argomenti e la struttura introduce il controllo del flusso contrario ai gusti moderni. Un controllo di flusso più gradevole può essere gestito con la restituzione di un codice di "stato" intero.
real x integer status call sub(x, 1, status) select case (status) case (0) print*, "Success:", x case (1) print*, "Negative input value" case (2) print*, "Input value too large" end select end subroutine sub(x, i, status) real, intent(out) :: x integer, intent(in) :: i integer, intent(out) :: status status = 0 if (i<0) then status = 1 else if (i>10) status = 2 else x = i
https://riptutorial.com/it/home 9
end if end subroutine
Modulo Fisso
Originariamente Fortran è stato progettato per un formato di formato fisso basato su una scheda perforata a 80 colonne:
Sì: questa è una riga del codice dell'autore
Questi sono stati creati su una macchina punch card, molto simile a questo:
Le immagini sono fotografie originali dell'autore
Il formato, come mostrato nella scheda campione illustrata, aveva le prime cinque colonne riservate per le etichette di istruzioni. La prima colonna è stata utilizzata per denotare i commenti con una lettera C. La sesta colonna è stata utilizzata per indicare una continuazione dell'istruzione (inserendo un carattere diverso da zero '0'). Le ultime 8 colonne sono state utilizzate per l'identificazione e il sequenziamento delle carte, il che è stato di grande valore se hai lasciato cadere il mazzo di carte sul pavimento! La codifica dei caratteri per le schede perforate aveva solo un numero limitato di caratteri ed era solo in maiuscolo. Di conseguenza, i programmi Fortran
https://riptutorial.com/it/home 10
assomigliavano a questo:
DIMENSION A(10) 00000001 C THIS IS A COMMENT STATEMENT TO EXPLAIN THIS EXAMPLE PROGRAM 00000002 WRITE (6,100) 00000003 100 FORMAT(169HTHIS IS A RATHER LONG STRING BEING OUTPUT WHICH GOES OVE00000004 1R MORE THAN ONE LINE, AND USES THE STATEMENT CONTINUATION MARKER IN00000005 2COLUMN 6, AND ALSO USES HOLLERITH STRING FORMAT) 00000006 STOP 00000007 END 00000008
Anche il carattere dello spazio è stato ignorato ovunque, tranne all'interno di una costante di carattere di Hollerith (come mostrato sopra). Ciò significava che gli spazi potevano verificarsi all'interno di parole e costanti riservate, o completamente persi. Ciò ha avuto l'effetto collaterale di alcune affermazioni piuttosto fuorvianti come:
DO 1 I = 1.0
è un compito assegnato alla variabile DO1I mentre:
DO1I = 1,0
è in realtà un ciclo DO sulla variabile I
Il moderno Fortran non richiede ora questa forma di input fissa e consente la forma libera utilizzando qualsiasi colonna. I commenti ora sono indicati da un ! che può anche essere aggiunto a una riga di istruzioni. Gli spazi ora non sono consentiti da nessuna parte e devono essere usati come separatori, proprio come nella maggior parte delle altre lingue. Il suddetto programma potrebbe essere scritto in Fortran moderno come:
! This is a comment statement to explain this example program Print *,"THIS IS A RATHER LONG STRING BEING OUTPUT WHICH no longer GOES OVER MORE THAN ONE LINE, AND does not need to USE THE STATEMENT CONTINUATION MARKER IN COLUMN 6, or the HOLLERITH STRING FORMAT"
Sebbene la continuazione vecchio stile non sia più utilizzata, l'esempio sopra illustra che si verificano ancora dichiarazioni molto lunghe. Il Fortran moderno usa un simbolo & alla fine e all'inizio della continuazione. Ad esempio, potremmo scrivere quanto sopra in una forma più leggibile:
! This is a comment statement to explain this example program Print *,"THIS IS A RATHER LONG STRING BEING OUTPUT WHICH still & &GOES OVER MORE THAN ONE LINE, AND does need to USE THE STATEMENT & &CONTINUATION notation"
Blocchi comuni
Nelle prime versioni di Fortran, l'unico meccanismo per la creazione di archivi di variabili globali visibili da subroutine e funzioni consiste nell'utilizzare il meccanismo di blocco COMMON . Questo
https://riptutorial.com/it/home 11
consentiva che le sequenze di variabili fossero nomi e condivisi in comune.
Oltre ai blocchi comuni denominati potrebbe esserci anche un blocco comune vuoto (senza nome).
Un blocco comune vuoto potrebbe essere dichiarato come
common i, j
mentre le variables blocco nominate potrebbero essere dichiarate come
common /variables/ i, j
Come esempio completo, possiamo immaginare un archivio di heap che viene utilizzato da routine che possono aggiungere e rimuovere valori:
PROGRAM STACKING COMMON /HEAP/ ICOUNT, ISTACK(1023) ICOUNT = 0 READ *, IVAL CALL PUSH(IVAL) CALL POP(IVAL) END SUBROUTINE PUSH(IVAL) COMMON /HEAP/ ICOUNT, ISTACK(1023) ICOUNT = ICOUNT + 1 ISTACK(ICOUNT) = IVAL RETURN END SUBROUTINE POP(IVAL) COMMON /HEAP/ ICOUNT, ISTACK(1023) IVAL = ISTACK(ICOUNT) ICOUNT = ICOUNT - 1 RETURN END
È possibile utilizzare dichiarazioni comuni per dichiarare implicitamente il tipo di una variabile e specificare l'attributo della dimension . Questo comportamento da solo è spesso una fonte sufficiente di confusione. Inoltre, l'associazione di memorizzazione implicita ei requisiti per le definizioni ripetute su unità di programma rendono l'uso di blocchi comuni inclini all'errore.
Infine, i blocchi comuni sono molto limitati negli oggetti che contengono. Ad esempio, una matrice in un blocco comune deve essere di dimensioni esplicite; gli oggetti allocabili potrebbero non verificarsi; i tipi derivati non devono avere l'inizializzazione predefinita.
Nel moderno Fortran questa condivisione di variabili può essere gestita mediante l'uso di moduli . L'esempio sopra può essere scritto come:
module heap implicit none
https://riptutorial.com/it/home 12
! In Fortran 2008 all module variables are implicitly saved integer, save :: count = 0 integer, save :: stack(1023) end module heap program stacking implicit none integer val read *, val call push(val) call pop(val) contains subroutine push(val) use heap, only : count, stack integer val count = count + 1 stack(count) = val end subroutine push subroutine pop(val) use heap, only : count, stack integer val val = stack(count) count = count - 1 end subroutine pop end program stacking
I blocchi comuni nominati e vuoti presentano comportamenti leggermente diversi. Di nota:
gli oggetti in blocchi comuni denominati possono essere inizialmente definiti; gli oggetti in bianco comune non devono essere
•
gli oggetti nei blocchi comuni vuoti si comportano come se il blocco comune avesse l'attributo di save ; gli oggetti nei blocchi comuni denominati senza l'attributo di save potrebbero non essere definiti quando il blocco non si trova nell'ambito di un'unità di programma attiva
•
Quest'ultimo punto può essere contrapposto al comportamento delle variabili del modulo nel codice moderno. Tutte le variabili del modulo in Fortran 2008 vengono salvate in modo implicito e non diventano indefinite quando il modulo esce dal campo di applicazione. Prima che le variabili del modulo di Fortran 2008, come le variabili nei blocchi comuni denominati, diventassero indefinite anche quando il modulo usciva dall'ambito.
GOTO assegnato
GOTO assegnato utilizza la variabile intera a cui è assegnata un'etichetta di istruzione utilizzando l'istruzione ASSIGN.
100 CONTINUE ... ASSIGN 100 TO ILABEL
https://riptutorial.com/it/home 13
... GOTO ILABEL
GOTO assegnato è obsoleto in Fortran 90 e eliminato in Fortran 95 e versioni successive. Può essere evitato nel codice moderno utilizzando procedure, procedure interne, indicatori di procedura e altre funzionalità.
GOTO calcolato
GOTO calcolato consente la diramazione del programma in base al valore di un'espressione intera.
GOTO (label_1, label_2,... label_n) scalar-integer-expression
Se l' scalar-integer-expression è uguale a 1, il programma continua con l'etichetta label_1 , se è uguale a 2 va a label_2 e così via. Se è inferiore a 1 o maggiore di n programma continua sulla riga successiva.
Esempio:
ivar = 2 ... GOTO (10, 20, 30, 40) ivar
salterà all'etichetta dell'istruzione 20.
Questa forma di goto è obsoleta in Fortran 95 e successivi, essendo sostituita dal costrutto di select case .
Specificatori di formato assegnati
Prima di Fortran 95 era possibile utilizzare i formati assegnati per l'input o l'output. Tenere conto
integer i, fmt read *, i assign 100 to fmt if (i<100000) assign 200 to fmt print fmt, i 100 format ("This is a big number", I10) 200 format ("This is a small number", I6) end
L'istruzione assign assegna un'etichetta di istruzione a una variabile intera. Questa variabile intera
https://riptutorial.com/it/home 14
viene in seguito utilizzata come identificatore di formato nell'istruzione print .
Tale attribuzione di identificatori di formato è stata eliminata in Fortran 95. Invece, un codice più moderno può utilizzare un'altra forma di controllo del flusso di esecuzione
integer i read *, i if (i<100000) then print 100, i else print 200, i end if 100 format ("This is a big number", I10) 200 format ("This is a small number", I6) end
o una variabile di carattere può essere usata come specificatore di formato
character(29), target :: big_fmt='("This is a big number", I10)' character(30), target :: small_fmt='("This is a small number", I6)' character(:), pointer :: fmt integer i read *, i fmt=>big_fmt if (i<100000) fmt=>small_fmt print fmt, i end
Funzioni di dichiarazione
Considera il programma
implicit none integer f, i f(i)=i print *, f(1) end
Qui f è una funzione di dichiarazione. Ha un tipo di risultato intero, prendendo un argomento fittizio intero. 1
Tale funzione di dichiarazione esiste all'interno dell'ambito in cui è definita. In particolare, ha accesso a variabili e costanti con nome accessibili in tale ambito.
Tuttavia, le funzioni di dichiarazione sono soggette a molte restrizioni e sono potenzialmente confuse (guardando un'occhiata casuale come una dichiarazione di assegnazione di elementi
https://riptutorial.com/it/home 15
dell'array). Restrizioni importanti sono:
il risultato della funzione e gli argomenti fittizi devono essere scalari•gli argomenti fittizi sono nella stessa portata della funzione•le funzioni di istruzione non hanno variabili locali•le funzioni di istruzioni non possono essere passate come argomenti reali•
I principali vantaggi delle funzioni di statement sono ripetuti dalle funzioni interne
implicit none print *, f(1) contains integer function f(i) integer i f = i end function end
Le funzioni interne non sono soggette alle restrizioni sopra menzionate, anche se è forse interessante notare che un sottoprogramma interno non può contenere ulteriori sottoprogrammi interni (ma può contenere una funzione di istruzione).
Le funzioni interne hanno il loro ambito ma hanno anche un'associazione host disponibile.
1 Negli esempi di codice vecchio e reale, non sarebbe inusuale vedere gli argomenti fittizi di una funzione di istruzione digitati implicitamente, anche se il risultato ha un tipo esplicito.
Leggi Alternative moderne a caratteristiche storiche online: https://riptutorial.com/it/fortran/topic/2103/alternative-moderne-a-caratteristiche-storiche
https://riptutorial.com/it/home 16
Capitolo 3: Array
Examples
Notazione di base
Qualsiasi tipo può essere dichiarato come matrice utilizzando l'attributo dimensione o semplicemente indicando direttamente la dimension (o le dimension ) dell'array:
! One dimensional array with 4 elements integer, dimension(4) :: foo ! Two dimensional array with 4 rows and 2 columns real, dimension(4, 2) :: bar ! Three dimensional array type(mytype), dimension(6, 7, 8) :: myarray ! Same as above without using the dimension keyword integer :: foo2(4) real :: bar2(4, 2) type(mytype) :: myarray2(6, 7, 8)
Quest'ultimo modo di dichiarare array multidimensionali, consente la dichiarazione di array di rango / dimensioni di stesso tipo in una riga, come segue
real :: pencil(5), plate(3,-2:4), cuboid(0:3,-10:5,6)
Il rango massimo (numero di dimensioni) consentito è 15 nello standard Fortran 2008 ed era 7 prima.
Fortran memorizza gli array nell'ordine delle colonne . Cioè, gli elementi della bar sono memorizzati nella memoria come segue:
bar(1, 1), bar(2, 1), bar(3, 1), bar(4, 1), bar(1, 2), bar(2, 2), ...
In Fortran, la numerazione degli array inizia da 1 di default, in contrasto con C che inizia da 0 . Infatti, in Fortran, è possibile specificare i limiti superiore e inferiore per ogni dimensione in modo esplicito:
integer, dimension(7:12, -3:-1) :: geese
Questo dichiara una matrice di forma (6, 3) , il cui primo elemento è geese(7, -3) .
I limiti inferiore e superiore lungo le 2 (o più) dimensioni sono accessibili dalle funzioni intrinseche ubound e lbound . Infatti lbound(geese,2) ritornerebbe -3 , mentre ubound(geese,1) ritornerebbe 12 .
È possibile accedere alle dimensioni di una matrice per size funzione intrinseca. Ad esempio,
https://riptutorial.com/it/home 17
size(geese, dim = 1) restituisce la dimensione della prima dimensione che è 6.
Matrici allocative
Le matrici possono avere l'attributo allocatable :
! One dimensional allocatable array integer, dimension(:), allocatable :: foo ! Two dimensional allocatable array real, dimension(:,:), allocatable :: bar
Questo dichiara la variabile ma non alloca alcuno spazio per essa.
! We can specify the bounds as usual allocate(foo(3:5)) ! It is an error to allocate an array twice ! so check it has not been allocated first if (.not. allocated(foo)) then allocate(bar(10, 2)) end if
Una volta che una variabile non è più necessaria, può essere deallocata :
deallocate(foo)
Se per qualche ragione un'istruzione allocate fallisce, il programma si fermerà. Questo può essere evitato se lo stato è controllato tramite la parola chiave stat :
real, dimension(:), allocatable :: geese integer :: status allocate(geese(17), stat=status) if (stat /= 0) then print*, "Something went wrong trying to allocate 'geese'" stop 1 end if
Anche l'istruzione deallocate ha una parola chiave stat :
deallocate (geese, stat=status)
status è una variabile intera il cui valore è 0 se l'allocazione o deallocazione ha avuto esito positivo.
Costruttori di array
Un valore dell'array rank-1 può essere creato utilizzando un costruttore di array , con la sintassi
(/ ... /) [ ... ]
https://riptutorial.com/it/home 18
Il modulo [...] stato introdotto in Fortran 2003 ed è generalmente considerato più chiaro da leggere, specialmente nelle espressioni complesse. Questo modulo è utilizzato esclusivamente in questo esempio.
I valori che caratterizzano un costruttore di array possono essere valori scalari, valori di array o loop impliciti.
I parametri di tipo e tipo dell'array costruito corrispondono a quelli dei valori nel costruttore di array
[1, 2, 3] ! A rank-1 length-3 array of default integer type [1., 2., 3.] ! A rank-1 length-3 array of default real type ["A", "B"] ! A rank-1 length-2 array of default character type integer, parameter :: A = [2, 4] [1, A, 3] ! A rank-1 length-4 array of default integer type, with A's elements integer i [1, (i, i=2, 5), 6] ! A rank-1 length-6 array of default integer type with an implied-do
Nei moduli sopra, tutti i valori dati devono essere dello stesso tipo e parametro di tipo. Non sono consentiti tipi di missaggio o parametri di tipo. I seguenti esempi non sono validi
[1, 2.] ! INVALID: Mixing integer and default real [1e0, 2d0] ! INVALID: Mixing default real and double precision [1., 2._dp] ! INVALID: Allowed only if kind `dp` corresponds to default real ["Hello", "Frederick"] ! INVALID: Different length parameters
Per costruire un array usando diversi tipi, deve essere fornita una specifica di tipo per l'array
[integer :: 1, 2., 3d0] ! A default integer array [real(dp) :: 1, 2, 3._sp] ! A real(dp) array [character(len=9) :: "Hello", "Frederick"] ! A length-2 array of length-9 characters
Quest'ultima forma per gli array di caratteri è particolarmente comoda per evitare spazi vuoti, come l'alternativa
["Hello ", "Frederick"] ! A length-2 array of length-9 characters
La dimensione di un array chiamato constant può essere implicita dal costruttore di array utilizzato per impostarne il valore
integer, parameter :: ids(*) = [1, 2, 3, 4]
e per i tipi con parametri di lunghezza può essere assunto il parametro della lunghezza
character(len=*), parameter :: names(*) = [character(3) :: "Me", "You", "Her"]
La specifica del tipo è richiesta anche nella costruzione di array a lunghezza zero. A partire dal
[ ] ! Not a valid array constructor
https://riptutorial.com/it/home 19
i parametri di tipo e tipo non possono essere determinati dal set di valori non esistenti. Per creare un array intero predefinito a lunghezza zero:
[integer :: ]
I costruttori di array costruiscono solo array di livello 1. A volte, ad esempio nell'impostazione del valore di una costante denominata, in un'espressione sono richiesti anche array di rango superiore. Array di rank più alti possono essere presi dal risultato di reshape con un array rank-1 costruito
integer, parameter :: multi_rank_ids(2,2) = RESHAPE([1,2,3,4], shape=[2,2])
In un costruttore di array, i valori dell'array nell'ordine degli elementi con qualsiasi array nella lista valori sono come se i singoli elemets fossero stati dati nell'ordine di elementi dell'array. Quindi, l'esempio precedente
integer, parameter :: A = [2, 4] [1, A, 3] ! A rank-1 length-4 array of default integer type, with A's elements
è equivalente a
[1, 2, 4, 3] ! With the array written out in array element order
Generalmente i valori nel costruttore possono essere espressioni arbitrarie, compresi i costruttori di array annidati. Affinché tale costruttore di array soddisfi determinate condizioni, ad esempio un'espressione costante o specifica, si applicano restrizioni ai valori dei componenti.
Sebbene non sia un costruttore di array, alcuni valori dell'array possono anche essere opportunamente creati usando la funzione intrinseca spread . Per esempio
[(0, i=1,10)] ! An array with 10 default integers each of value 0
è anche il risultato del riferimento alla funzione
SPREAD(0, 1, 10)
Specifica della natura della matrice: rango e forma
L'attributo dimension su un oggetto specifica che quell'oggetto è una matrice. Ci sono, in Fortran 2008, cinque tipi di array: 1
forma esplicita•forma assunta•dimensione assunta•forma differita•
https://riptutorial.com/it/home 20
forma implicita•
Prendi i tre array rank-1 2
integer a, b, c dimension(5) a ! Explicit shape (default lower bound 1), extent 5 dimension(:) b ! Assumed or deferred shape dimension(*) c ! Assumed size or implied shape array
Con questi si può vedere che è necessario un ulteriore contesto per determinare pienamente la natura di un array.
Forma esplicita
Un array di forme esplicito è sempre la forma della sua dichiarazione. A meno che la matrice non sia dichiarata locale a un sottoprogramma oa un costrutto di block , i limiti che definiscono la forma devono essere espressioni costanti. In altri casi, un array di forme esplicite può essere un oggetto automatico, utilizzando estensioni che possono variare a seconda di ogni chiamata di un sottoprogramma o di un block .
subroutine sub(n) integer, intent(in) :: n integer a(5) ! A local explicit shape array with constant bound integer b(n) ! A local explicit shape array, automatic object end subroutine
Forma assunta
Un array di forme presunte è un argomento fittizio senza l'attributo allocatable o pointer . Tale matrice prende la sua forma dall'argomento reale con cui è associato.
integer a(5), b(10) call sub(a) ! In this call the dummy argument is like x(5) call sub(b) ! In this call the dummy argument is like x(10) contains subroutine sub(x) integer x(:) ! Assumed shape dummy argument end subroutine sub end
Quando un argomento fittizio ha assunto la forma, l'ambito che fa riferimento alla procedura deve disporre di un'interfaccia esplicita disponibile per tale procedura.
Dimensione presunta
Un array di dimensioni presunte è un argomento fittizio che ha la sua dimensione assunta dal suo
https://riptutorial.com/it/home 21
argomento reale.
subroutine sub(x) integer x(*) ! Assumed size array end subroutine
Gli array di dimensioni presunte si comportano in modo molto diverso dagli array di forme presunte e queste differenze sono documentate altrove.
Forma differita
Una matrice di forme differite è una matrice che ha l'attributo allocatable o pointer . La forma di tale array è determinata dalla sua allocazione o dall'assegnazione del puntatore.
integer, allocatable :: a(:) integer, pointer :: b(:)
Forma implicita
Una matrice di forme implicite è una costante denominata che prende la sua forma dall'espressione utilizzata per stabilirne il valore
integer, parameter :: a(*) = [1,2,3,4]
Le implicazioni di queste dichiarazioni di array sugli argomenti fittizi devono essere documentate altrove.
1 A Specifiche tecniche che si estendono Fortran 2008 aggiunge una sesta natura di array: rango assunto. Questo non è coperto qui.
2 Questi possono essere equivalentemente scritti come
integer, dimension(5) :: a integer, dimension(:) :: b integer, dimension(*) :: c
o
integer a(5) integer b(:) integer c(*)
Intere matrici, elementi di array e sezioni di array
Considera la matrice dichiarata come
https://riptutorial.com/it/home 22
real x(10)
Quindi abbiamo tre aspetti di interesse:
L'intero array x ;1. Elementi di matrice, come x(1) ;2. Sezioni di array, come x(2:6) .3.
Interi array
Nella maggior parte dei casi l'intero array x riferisce a tutti gli elementi dell'array come entità singola. Può apparire in istruzioni eseguibili come print *, SUM(x) , print *, SIZE(x) o x=1 .
Un intero array può fare riferimento a matrici che non hanno una forma esplicita (come x sopra):
function f(y) real, intent(out) :: y(:) real, allocatable :: z(:) y = 1. ! Intrinsic assignment for the whole array z = [1., 2.,] ! Intrinsic assignment for the whole array, invoking allocation end function
Una matrice di dimensioni presunte può anche apparire come un intero array, ma solo in circostanze limitate (da documentare altrove).
Elementi di matrice
Si riferisce che un elemento dell'array fornisce indici interi, uno per ogni rango dell'array, che indica la posizione nell'intero array:
real x(5,2) x(1,1) = 0.2 x(2,4) = 0.3
Un elemento dell'array è uno scalare.
Sezioni di matrice
Una sezione array è un riferimento a un numero di elementi (forse solo uno) di un intero array, utilizzando una sintassi che coinvolge due punti:
real x(5,2) x(:,1) = 0. ! Referring to x(1,1), x(2,1), x(3,1), x(4,1) and x(5,1) x(2,:) = 0. ! Referring to x(2,1), x(2,2) x(2:4,1) = 0. ! Referring to x(2,1), x(3,1) and x(4,1) x(2:3,1:2) = 0. ! Referring to x(2,1), x(3,1), x(2,2) and x(3,2) x(1:1,1) = 0. ! Referring to x(1,1) x([1,3,5],2) = 0. ! Referring to x(1,2), x(3,2) and x(5,2)
https://riptutorial.com/it/home 23
Il modulo finale sopra utilizza un indice vettoriale . Questo è soggetto a una serie di restrizioni oltre le altre sezioni dell'array.
Ogni sezione dell'array è essa stessa una matrice, anche quando viene fatto riferimento a un solo elemento. Quello è x(1:1,1) è un array di rank 1 e x(1:1,1:1) è un array di rank 2.
Le sezioni delle matrici in generale non hanno un attributo dell'intero array. In particolare, dove
real, allocatable :: x(:) x = [1,2,3] ! x is allocated as part of the assignment x = [1,2,3,4] ! x is dealloacted then allocated to a new shape in the assignment
L'incarico
x(:) = [1,2,3,4,5] ! This is bad when x isn't the same shape as the right-hand side
non è consentito: x(:) , sebbene una sezione di matrice con tutti gli elementi di x , non sia una matrice allocabile.
x(:) = [5,6,7,8]
va bene quando x è della forma del lato destro.
Componenti dell'array di array
type t real y(5) end type t type(t) x(2)
Potremmo anche fare riferimento a interi array, elementi di array e sezioni di array in impostazioni più complicate.
Da quanto sopra, x è un intero array. Abbiamo anche
x(1)%y ! A whole array x(1)%y(1) ! An array element x%y(1) ! An array section x(1)%y(:) ! An array section x([1,2]%y(1) ! An array section x(1)%y(1:1) ! An array section
In tali casi non è consentito avere più di una parte del riferimento costituito da una matrice di rango 1. Ad esempio, non sono consentiti i seguenti aspetti
x%y ! Both the x and y parts are arrays x(1:1)%y(1:1) ! Recall that each part is still an array section
https://riptutorial.com/it/home 24
Operazioni di matrice
A causa dei suoi obiettivi computazionali, le operazioni matematiche sugli array sono semplici in Fortran.
Addizione e sottrazione
Le operazioni su array della stessa forma e dimensione sono molto simili all'algebra della matrice. Invece di scorrere tutti gli indici con i loop, si può scrivere addizione (e sottrazione):
real, dimension(2,3) :: A, B, C real, dimension(5,6,3) :: D A = 3. ! Assigning single value to the whole array B = 5. ! Equivalent writing for assignment C = A + B ! All elements of C now have value 8. D = A + B ! Compiler will raise an error. The shapes and dimensions are not the same
Anche gli array di slicing sono validi:
integer :: i, j real, dimension(3,2) :: Mat = 0. real, dimension(3) :: Vec1 = 0., Vec2 = 0., Vec3 = 0. i = 0 j = 0 do i = 1,3 do j = 1,2 Mat(i,j) = i+j enddo enddo Vec1 = Mat(:,1) Vec2 = Mat(:,2) Vec3 = Mat(1:2,1) + Mat(2:3,2)
Funzione
Allo stesso modo, la maggior parte delle funzioni intrinseche può essere utilizzata implicitamente assumendo l'operazione componente-saggio (sebbene ciò non sia sistematico):
real, dimension(2) :: A, B A(1) = 6 A(2) = 44 ! Random values B = sin(A) ! Identical to B(1) = sin(6), B(2) = sin(44).
Moltiplicazione e divisione
Bisogna fare attenzione al prodotto e alla divisione: le operazioni intrinseche che usano * e / simboli sono element-wise:
real, dimension(2) :: A, B, C A(1) = 2
https://riptutorial.com/it/home 25
A(2) = 4 B(1) = 1 B(2) = 3 C = A*B ! Returns C(1) = 2*1 and C(2) = 4*3
Questo non deve essere confuso con le operazioni con la matrice (vedi sotto).
Operazioni con matrici
Le operazioni della matrice sono procedure intrinseche. Ad esempio, il prodotto matrice degli array della sezione precedente è scritto come segue:
real, dimension(2,1) :: A, B real, dimension(1,1) :: C A(1) = 2 A(2) = 4 B(1) = 1 B(2) = 3 C = matmul(transpose(A),B) ! Returns the scalar product of vectors A and B
Le operazioni complesse consentono di incapsulare le funzioni creando array temporanei. Sebbene consentito da alcuni compilatori e opzioni di compilazione, questo non è raccomandato. Ad esempio, un prodotto che include una trasposizione di matrice può essere scritto:
real, dimension(3,3) :: A, B, C A(:) = 4 B(:) = 5 C = matmul(transpose(A),matmul(B,matmul(A,transpose(B)))) ! Equivalent to A^t.B.A.B^T
Sezioni di array avanzate: triplet di pedici e pedici vettoriali
Come menzionato in un altro esempio, un sottoinsieme degli elementi di un array, chiamato sezione dell'array, può essere referenziato. Da quell'esempio che potremmo avere
real x(10) x(:) = 0. x(2:6) = 1. x(3:4) = [3., 5.]
Le sezioni delle matrici possono essere più generali di questa, però. Possono assumere la forma di triplette sottoscritte o di pedici vettoriali.
Triplette degli abbonati
Una triplice pedice assume la forma [bound1]:[bound2][:stride] . Per esempio
real x(10) x(1:10) = ... ! Elements x(1), x(2), ..., x(10) x(1:) = ... ! The omitted second bound is equivalent to the upper, same as above x(:10) = ... ! The omitted first bound is equivalent to the lower, same as above
https://riptutorial.com/it/home 26
x(1:6:2) = ... ! Elements x(1), x(3), x(5) x(5:1) = ... ! No elements: the lower bound is greater than the upper x(5:1:-1) = ... ! Elements x(5), x(4), x(3), x(2), x(1) x(::3) = ... ! Elements x(1), x(4), x(7), x(10), assuming omitted bounds x(::-3) = ... ! No elements: the bounds are assumed with the first the lower, negative stride
Quando viene specificato un passo (che non deve essere zero), la sequenza di elementi inizia con il primo limite specificato. Se la falcata è positiva (o negativa), gli elementi selezionati seguono una sequenza incrementata (risp. Decrementata) dalla falcata fino a quando non viene preso l'ultimo elemento non più grande (o più piccolo) del secondo limite. Se il passo è omesso, viene trattato come se fosse uno.
Se il primo limite è maggiore del secondo limite e la falcata è positiva, non viene specificato alcun elemento. Se il primo limite è inferiore al secondo limite e la falcata è negativa, non viene specificato alcun elemento.
Va notato che x(10:1:-1) non è uguale a x(1:10:1) anche se ciascun elemento di x appare in entrambi i casi.
Sottoscrizioni del vettore
Un indice vettoriale è un array intero di grado 1. Questo designa una sequenza di elementi corrispondenti ai valori dell'array.
real x(10) integer i x([1,6,4]) = ... ! Elements x(1), x(6), x(4) x([(i,i=2,4)]) = ... ! Elements x(2), x(3) and x(4) print*, x([2,5,2]) ! Elements x(2), x(5) and x(2)
Una sezione di array con un indice vettoriale è limitata nel modo in cui può essere utilizzata:
potrebbe non essere un argomento associato ad un argomento fittizio definito nella procedura;
•
potrebbe non essere il bersaglio in un'istruzione di assegnazione puntatore;•potrebbe non essere un file interno in un'istruzione di trasferimento dati.•
Inoltre, una tale sezione di array potrebbe non apparire in un'istruzione che implica la sua definizione quando lo stesso elemento viene selezionato due volte. Da sopra:
print*, x([2,5,2]) ! Elements x(2), x(5) and x(2) are printed x([2,5,2]) = 1. ! Not permitted: x(2) appears twice in this definition
Sezioni dell'array di rank più alto
real x(5,2) print*, x(::2,2:1:-1) ! Elements x(1,2), x(3,2), x(5,2), x(1,1), x(3,1), x(5,1)
https://riptutorial.com/it/home 27
Leggi Array online: https://riptutorial.com/it/fortran/topic/996/array
https://riptutorial.com/it/home 28
Capitolo 4: Controllo dell'esecuzione
Examples
Se costrutto
Il costrutto if (chiamato istruzione IF blocco in FORTRAN 77) è comune in molti linguaggi di programmazione. Esegue condizionatamente un blocco di codice quando un'espressione logica viene valutata su true.
[name:] IF (expr) THEN block [ELSE IF (expr) THEN [name] block] [ELSE [name] block] END IF [name]
dove,
nome : il nome del costrutto if (facoltativo)•expr - un'espressione logica scalare racchiusa tra parentesi•block - una sequenza di zero o più istruzioni o costrutti•
Un nome di costrutto all'inizio di un'istruzione if then deve avere lo stesso valore del nome del costrutto alla end if dell'istruzione, e dovrebbe essere univoco per l'attuale unità di ambito.
Nelle istruzioni if , (in) le uguaglianze e le espressioni logiche che valutano un'istruzione possono essere utilizzate con i seguenti operatori:
.LT. which is < ! less than
.LE. <= ! less than or equal
.GT. > ! greater than
.GE. >= ! greater than or equal
.EQ. = ! equal
.NE. /= ! not equal
.AND. ! logical and
.OR. ! logical or
.NOT. ! negation
Esempi:
! simplest form of if construct if (a > b) then c = b / 2 end if !equivalent example with alternate syntax if(a.gt.b)then c=b/2 endif
https://riptutorial.com/it/home 29
! named if construct circle: if (r >= 0) then l = 2 * pi * r end if circle ! complex example with nested if construct block: if (a < e) then if (abs(c - e) <= d) then a = a * c else a = a * d end if else a = a * e end if block
Un uso storico del costrutto if è in quella che viene definita un'istruzione "aritmetica se". Poiché questo può essere sostituito da costrutti più moderni, tuttavia, non è coperto qui. Maggiori dettagli possono essere trovati qui .
SELEZIONA il costrutto CASE
Un costrutto di select case esegue condizionalmente un blocco di costrutti o istruzioni in base al valore di un'espressione scalare in un'istruzione select case . Questo costrutto di controllo può essere considerato come una sostituzione del goto calcolato.
[name:] SELECT CASE (expr) [CASE (case-value [, case-value] ...) [name] block]... [CASE DEFAULT [name] block] END SELECT [name]
dove,
nome : il nome del costrutto di select case (facoltativo)•expr - un'espressione scalare di tipo intero, logico o carattere (racchiusa tra parentesi)•case-value : una o più espressioni scalari di intero, logico o di inizializzazione del carattere racchiuse tra parentesi
•
block - una sequenza di zero o più istruzioni o costrutti•
Esempi:
! simplest form of select case construct select case(i) case(:-1) s = -1 case(0) s = 0 case(1:) s = 1 case default print "Something strange is happened"
https://riptutorial.com/it/home 30
end select
In questo esempio, (:-1) valore del caso è un intervallo di valori corrispondenti a tutti i valori inferiori a zero, (0) corrisponde agli zeri e (1:) corrisponde a tutti i valori sopra lo zero, la sezione default interessa se altre sezioni lo hanno fatto non eseguito.
Costruisci il blocco DO
Un costrutto do è un costrutto ciclico che ha un numero di iterazioni governate da un controllo di ciclo
integer i do i=1, 5 print *, i end do print *, i
Nella forma in alto, la variabile loop i passa attraverso il loop 5 volte, prendendo a turno i valori da 1 a 5. Dopo che il costrutto ha completato la variabile di ciclo ha il valore 6, cioè la variabile di ciclo viene incrementata ancora una volta dopo il completamento del ciclo .
Più in generale, il costrutto do loop può essere compreso come segue
integer i, first, last, step do i=first, last, step end do
Il ciclo inizia con i con il valore per first , incrementando ogni iterazione per step fino a quando i è maggiore last (o meno last se la dimensione del passo è negativa).
È importante notare che poiché Fortran 95, la variabile di ciclo e le espressioni di controllo del ciclo devono essere numeri interi.
Un'iterazione può essere interrotta prematuramente con l'istruzione del cycle
do i=1, 5 if (i==4) cycle end do
e l'intero costrutto potrebbe cessare l'esecuzione con l'istruzione exit
do i=1, 5 if (i==4) exit end do print *, i
do costrutti possono essere nominati:
do_name: do i=1, 5
https://riptutorial.com/it/home 31
end do do_name
che è particolarmente utile quando vi sono annidati do costrutti
do1: do i=1, 5 do j=1,6 if (j==3) cycle ! This cycles the j construct if (j==4) cycle ! This cycles the j construct if (i+j==7) cycle do1 ! This cycles the i construct if (i*j==15) exit do1 ! This exits the i construct end do end do1
do costrutti possono anche avere un controllo di ciclo indeterminato, "per sempre" o fino a quando una determinata condizione non viene soddisfatta
integer :: i=0 do i=i+1 if (i==5) exit end do
o
integer :: i=0 do while (i<6) i=i+1 end do
Ciò consente anche di un infinito do ciclo attraverso un .true. dichiarazione
print *,'forever' do while(.true.) print *,'and ever' end do
Un costrutto do può anche lasciare l'ordine delle iterazioni indeterminato
do concurrent (i=1:5) end do
notando che la forma del controllo del ciclo è la stessa di un controllo forall .
Esistono varie restrizioni sulle istruzioni che possono essere eseguite all'interno dell'intervallo di un costrutto do concurrent che sono progettate per garantire che non vi siano dipendenze tra le iterazioni del costrutto. Questa indicazione esplicita da parte del programmatore può consentire una maggiore ottimizzazione (inclusa la parallelizzazione) da parte del compilatore, che può essere difficile da determinare diversamente.
Le variabili "private" all'interno di un'interazione possono essere realizzate utilizzando un costrutto
https://riptutorial.com/it/home 32
di block all'interno del do concurrent :
do concurrent (i=1:5, j=2:7) block real tempval ! This is independent across iterations end block end do
Un'altra forma di blocco do costruire utilizza un marcato continue dichiarazione invece di un end do :
do 100, i=1, 5 100 continue
È persino possibile annidare tali costrutti con un'istruzione di terminazione condivisa
do 100, i=1,5 do 100, j=1,5 100 continue
Entrambe queste forme, e specialmente la seconda (che è obsolescente), devono essere generalmente evitate per motivi di chiarezza.
Infine, v'è anche un non-blocco do costruire. Ciò è ritenuto essere anche obsoleti e viene descritto altrove , insieme a metodi per ristrutturare come blocco do costruire.
DOVE costruisci
Il costrutto where , disponibile in Fortran90 in poi, rappresenta un costrutto do mascherato. L'istruzione masking segue le stesse regole dell'istruzione if , ma viene applicata a tutti gli elementi dell'array dato. L'utilizzo di where consente di eseguire operazioni su un array (o più array della stessa dimensione), i cui elementi soddisfano una determinata regola. Questo può essere usato per semplificare le operazioni simultanee su più variabili.
Sintassi:
[name]: where (mask) block [elsewhere (mask) block] [elsewhere block] end where [name]
Qui,
nome - è il nome dato al blocco (se nominato)•mask - è un'espressione logica applicata a tutti gli elementi•block - serie di comandi da eseguire•
https://riptutorial.com/it/home 33
Esempi:
! Example variables real:: A(5),B(5),C(5) A = 0.0 B = 1.0 C = [0.0, 4.0, 5.0, 10.0, 0.0] ! Simple where construct use where (C/=0) A=B/C elsewhere A=0.0 end ! Named where construct Block: where (C/=0) A=B/C elsewhere A=0.0 end where Block
Leggi Controllo dell'esecuzione online: https://riptutorial.com/it/fortran/topic/1657/controllo-dell-esecuzione
https://riptutorial.com/it/home 34
Capitolo 5: Estensioni di file di origine (.f, .f90, .f95, ...) e in che modo sono correlati al compilatore.
introduzione
I file Fortran hanno una varietà di estensioni e ognuno di essi ha un significato separato. Specificano la versione di rilascio di Fortran, lo stile di formattazione del codice e l'uso delle direttive del preprocessore simile al linguaggio di programmazione C.
Examples
Estensioni e significati
Di seguito sono riportate alcune delle estensioni comuni utilizzate nei file di origine Fortran e le funzionalità su cui possono essere eseguite.
F minuscola nell'estensione
Questi file non hanno le caratteristiche delle direttive del preprocessore simili al linguaggio di programmazione C. Possono essere compilati direttamente per creare file oggetto. ad es .: .f, .for, .f95
F maiuscola nell'estensione
Questi file hanno le caratteristiche delle direttive del preprocessore simili al linguaggio di programmazione C. I preprocessori sono definiti all'interno dei file o usando come file di intestazione C / C ++ o entrambi. Questi file devono essere pre-elaborati per ottenere i file di estensione in minuscolo che possono essere utilizzati per la compilazione. ad esempio: .F, .FOR, .F95
.f, .for, .f77, .ftn
Questi sono usati per i file di Fortran che usano il formato di stile fisso e quindi usano la versione di rilascio di Fortran 77 . Dal momento che sono estensioni in minuscolo, non possono avere direttive per il preprocessore.
.F, .FOR, .F77, .FTN
Questi sono usati per i file di Fortran che usano il formato di stile fisso e quindi usano la versione di rilascio di Fortran 77 . Poiché sono estensioni maiuscole, possono avere direttive di preprocessore e quindi devono essere preelaborate per ottenere i file di estensione minuscoli.
.f90, .f95, .f03, .f08 Questi sono usati per i file Fortran che usano il formato stile libero e quindi
https://riptutorial.com/it/home 35
usano versioni successive di Fortran. Le versioni di rilascio sono nel nome.
f90 - Fortran 90•f95 - Fortran 95•f03 - Fortran 2003•f08 - Fortran 2008•
Dal momento che sono estensioni in minuscolo, non possono avere direttive per il preprocessore.
.F90, .F95, .F03, .F08 Questi sono usati per i file Fortran che usano il formato Stile libero e quindi usano versioni successive di Fortran. Le versioni di rilascio sono nel nome.
F90 - Fortran 90•F95 - Fortran 95•F03 - Fortran 2003•F08 - Fortran 2008•
Poiché sono estensioni maiuscole, hanno direttive per il preprocessore e quindi devono essere preelaborate per ottenere i file di estensione in minuscolo.
Leggi Estensioni di file di origine (.f, .f90, .f95, ...) e in che modo sono correlati al compilatore. online: https://riptutorial.com/it/fortran/topic/10265/estensioni-di-file-di-origine---f---f90---f95-------e-in-che-modo-sono-correlati-al-compilatore-
https://riptutorial.com/it/home 36
Capitolo 6: I / O
Sintassi
WRITE(unit num, format num) restituisce i dati dopo le parentesi in una nuova riga.•READ(unit num, format num) ingressi alla variabile dopo le parentesi.•OPEN(unit num, FILE=file) apre un file. (Ci sono più opzioni per aprire i file, ma non sono importanti per I / O.
•
CLOSE(unit num) chiude un file.•
Examples
I / O semplice
Come esempio di input e output di scrittura, acquisiremo un valore reale e restituiremo il valore e il relativo quadrato finché l'utente non immetterà un numero negativo.
Come specificato di seguito, il comando read accetta due argomenti: il numero di unità e l'identificatore di formato. Nell'esempio seguente, usiamo * per il numero di unità (che indica stdin) e * per il formato (che indica l'impostazione predefinita per i valori reali, in questo caso). Specifichiamo anche il formato per la dichiarazione di print . In alternativa, puoi usare write(*,"The value....") o semplicemente ignorare la formattazione e averlo come
print *,"The entered value was ", x," and its square is ",x*x
che risulterà probabilmente in alcune stringhe e valori stranamente distanziati.
program SimpleIO implicit none integer, parameter :: wp = selected_real_kind(15,307) real(kind=wp) :: x ! we'll loop over until user enters a negative number print '("Enter a number >= 0 to see its square. Enter a number < 0 to exit.")' do ! this reads the input as a double-pricision value read(*,*) x if (x < 0d0) exit ! print the entered value and it's square print '("The entered value was ",f12.6,", its square is ",f12.6,".")',x,x*x end do print '("Thank you!")' end program SimpleIO
Leggi con alcuni errori di controllo
Un moderno esempio di Fortran che include il controllo degli errori e una funzione per ottenere un
https://riptutorial.com/it/home 37
nuovo numero di unità per il file.
module functions contains function get_new_fileunit() result (f) implicit none logical :: op integer :: f f = 1 do inquire(f,opened=op) if (op .eqv. .false.) exit f = f + 1 enddo end function end module program file_read use functions, only : get_new_fileunit implicit none integer :: unitno, ierr, readerr logical :: exists real(kind(0.d0)) :: somevalue character(len=128) :: filename filename = "somefile.txt" inquire(file=trim(filename), exist=exists) if (exists) then unitno = get_new_fileunit() open(unitno, file=trim(filename), action="read", iostat=ierr) if (ierr .eq. 0) then read(unitno, *, iostat=readerr) somevalue if (readerr .eq. 0) then print*, "Value in file ", trim(filename), " is ", somevalue else print*, "Error ", readerr, & " attempting to read file ", & trim(filename) endif else print*, "Error ", ierr ," attempting to open file ", trim(filename) stop endif else print*, "Error -- cannot find file: ", trim(filename) stop endif end program file_read
Passando gli argomenti della riga di comando
https://riptutorial.com/it/home 38
Dove gli argomenti della riga di comando sono supportati, possono essere letti tramite il get_command_argument intrinsico (introdotto nello standard Fortran 2003). Il command_argument_count intrinsic fornisce un modo per conoscere il numero di argomenti forniti nella riga di comando.
Tutti gli argomenti della riga di comando vengono letti come stringhe, pertanto è necessario eseguire una conversione del tipo interno per i dati numerici. Ad esempio, questo semplice codice somma i due numeri forniti sulla riga di comando:
PROGRAM cmdlnsum IMPLICIT NONE CHARACTER(100) :: num1char CHARACTER(100) :: num2char REAL :: num1 REAL :: num2 REAL :: numsum !First, make sure the right number of inputs have been provided IF(COMMAND_ARGUMENT_COUNT().NE.2)THEN WRITE(*,*)'ERROR, TWO COMMAND-LINE ARGUMENTS REQUIRED, STOPPING' STOP ENDIF CALL GET_COMMAND_ARGUMENT(1,num1char) !first, read in the two values CALL GET_COMMAND_ARGUMENT(2,num2char) READ(num1char,*)num1 !then, convert them to REALs READ(num2char,*)num2 numsum=num1+num2 !sum numbers WRITE(*,*)numsum !write out value END PROGRAM
L'argomento numero in get_command_argument varia utilmente tra 0 e il risultato di command_argument_count . Se il valore è 0 viene fornito il nome del comando (se supportato).
Molti compilatori offrono anche elementi intrinseci non standard (come getarg ) per accedere agli argomenti della riga di comando. Poiché questi non sono standard, dovrebbe essere consultata la corrispondente documentazione del compilatore.
L'uso di get_command_argument può essere esteso oltre l'esempio precedente con gli argomenti length e status . Ad esempio, con
character(5) arg integer stat call get_command_argument(number=1, value=arg, status=stat)
il valore di stat sarà -1 se il primo argomento esiste e ha lunghezza maggiore di 5. Se c'è qualche altra difficoltà nel recuperare l'argomento il valore di stat sarà un numero positivo (e arg sarà composto interamente da spazi vuoti). Altrimenti il suo valore sarà 0 .
L'argomento della length può essere combinato con una variabile di carattere di lunghezza differita, come nell'esempio seguente.
https://riptutorial.com/it/home 39
character(:), allocatable :: arg integer arglen, stat call get_command_argument(number=1, length=arglen) ! Assume for simplicity success allocate (character(arglen) :: arg) call get_command_argument(number=1, value=arg, status=stat)
Leggi I / O online: https://riptutorial.com/it/fortran/topic/6778/i---o
https://riptutorial.com/it/home 40
Capitolo 7: Interfacce esplicite e implicite
Examples
Sottoprogrammi interni / moduli e interfacce esplicite
Un sottoprogramma (che definisce una procedura ) può essere una subroutine o una function ; si dice che sia un sottoprogramma interno se viene chiamato o invocato dallo stesso program o sottoprogramma che lo contains , come segue
program my_program ! declarations ! executable statements, ! among which an invocation to ! internal procedure(s), call my_sub(arg1,arg2,...) fx = my_fun(xx1,xx2,...) contains subroutine my_sub(a1,a2,...) ! declarations ! executable statements end subroutine my_sub function my_fun(x1,x2,...) result(f) ! declarations ! executable statements end function my_fun end program my_program
In questo caso il compilatore saprà tutto su qualsiasi procedura interna, poiché tratta l'unità di programma come un tutto. In particolare, "vedrà" l' interface della procedura, cioè
se si tratta di una function o subroutine ,•quali sono i nomi e le proprietà degli argomenti a1 , a2 , x1 , x2 , ...,•quali sono le proprietà del risultato f (nel caso di una function ).•
Essendo l'interfaccia nota, il compilatore può verificare se gli argomenti effettivi ( arg1 , arg2 , xx1 , xx2 , fx , ...) passati alla procedura coincidono con gli argomenti dummy ( a1 , a2 , x1 , x2 , f , .. .).
In questo caso diciamo che l'interfaccia è esplicita .
Si dice che un sottoprogramma è un sottoprogramma del modulo quando viene invocato da un'istruzione nel modulo contenitore stesso,
module my_mod ! declarations
https://riptutorial.com/it/home 41
contains subroutine my_mod_sub(b1,b2,...) ! declarations ! executable statements r = my_mod_fun(b1,b2,...) end subroutine my_sub function my_mod_fun(y1,y2,...) result(g) ! declarations ! executable statements end function my_fun end module my_mod
o da una dichiarazione in un'altra unità di programma che use quel modulo,
program my_prog use my_mod call my_mod_sub(...) end program my_prog
Come nella situazione precedente, il compilatore saprà tutto sul sottoprogramma e, quindi, diciamo che l'interfaccia è esplicita .
Sottoprogrammi esterni e interfacce implicite
Si dice che un sottoprogramma è esterno quando non è contenuto nel programma principale, né in un modulo o sottoprogramma antoher. In particolare, può essere definito mediante un linguaggio di programmazione diverso da Fortran.
Quando viene richiamato un sottoprogramma esterno, il compilatore non può accedere al suo codice, quindi tutte le informazioni permesse al compilatore sono implicitamente contenute nell'istruzione chiamante del programma chiamante e nel tipo una proprietà degli argomenti acutali, non gli argomenti fittizi ( la cui dichiarazione è sconosciuta al compilatore). In questo caso diciamo che l'interfaccia è implicita .
È possibile utilizzare un'istruzione external per specificare che il nome di una procedura è relativo a una procedura esterna,
external external_name_list
ma anche così, l'interfaccia rimane implicita.
Un blocco di interface può essere usato per specificare l'interfaccia di una procedura esterna,
interface interface_body
https://riptutorial.com/it/home 42
end interface
dove l' interface_body è normalmente una copia esatta dell'intestazione della procedura seguita dalla dichiarazione di tutti i suoi argomenti e, se si tratta di una funzione, del risultato.
Ad esempio, per la funzione WindSpeed
real function WindSpeed(u, v) real, intent(in) :: u, v WindSpeed = sqrt(u*u + v*v) end function WindSpeed
Puoi scrivere la seguente interfaccia
interface real function WindSpeed(u, v) real, intent(in) :: u, v end function WindSpeed end interface
Leggi Interfacce esplicite e implicite online: https://riptutorial.com/it/fortran/topic/2882/interfacce-esplicite-e-implicite
https://riptutorial.com/it/home 43
Capitolo 8: Interoperabilità C
Examples
Chiamando C da Fortran
Fortran 2003 ha introdotto caratteristiche linguistiche che possono garantire l'interoperabilità tra C e Fortran (e in più lingue usando C come intermediario). Queste funzionalità sono per lo più accessibili tramite il modulo intrinseco iso_c_binding :
use, intrinsic :: iso_c_binding
La parola chiave intrinsic garantisce che venga utilizzato il modulo corretto e non un modulo creato dall'utente con lo stesso nome.
iso_c_binding fornisce l'accesso a parametri di tipo di tipo interoperabile :
integer(c_int) :: foo ! equivalent of 'int foo' in C real(c_float) :: bar ! equivalent of 'float bar' in C
L'uso di parametri di tipo C garantisce che i dati possano essere trasferiti tra i programmi C e Fortran.
L'interoperabilità dei caratteri C char e Fortran è probabilmente un argomento per sé e quindi non è discussa qui
Per chiamare effettivamente una funzione C da Fortran, prima l'interfaccia deve essere dichiarata. Questo è sostanzialmente equivalente al prototipo della funzione C, e consente al compilatore di conoscere il numero e il tipo degli argomenti, ecc. L'attributo bind viene usato per indicare al compilatore il nome della funzione in C, che potrebbe essere diverso dal Fortran nome.
geese.h
// Count how many geese are in a given flock int howManyGeese(int flock);
geese.f90
! Interface to C routine interface integer(c_int) function how_many_geese(flock_num) bind(C, 'howManyGeese') ! Interface blocks don't know about their context, ! so we need to use iso_c_binding to get c_int definition use, intrinsic :: iso_c_binding, only : c_int integer(c_int) :: flock_num end function how_many_geese end interface
https://riptutorial.com/it/home 44
Il programma Fortran deve essere collegato alla libreria C ( dipendente dal compilatore, includi qui? ) Che include l'implementazione di howManyGeese() , quindi how_many_geese() può essere chiamato da Fortran.
C structs in Fortran
L'attributo bind può anche essere applicato ai tipi derivati:
geese.h
struct Goose { int flock; float buoyancy; } struct Goose goose_c;
geese.f90
use, intrinsic :: iso_c_binding, only : c_int, c_float type, bind(C) :: goose_t integer(c_int) :: flock real(c_float) :: buoyancy end type goose_t type(goose_t) :: goose_f
Ora i dati possono essere trasferiti tra goose_c e goose_f . Le routine C che accettano argomenti di tipo Goose possono essere chiamate da Fortran con type(goose_t) .
Leggi Interoperabilità C online: https://riptutorial.com/it/fortran/topic/2184/interoperabilita-c
https://riptutorial.com/it/home 45
Capitolo 9: Procedure intrinseche
Osservazioni
Molte delle procedure intrinseche disponibili hanno in comune tipi di argomenti. Per esempio:
un argomento logico MASK che seleziona elementi di matrici di input da elaborare•un argomento scalare intero KIND che determina il tipo di risultato della funzione•un argomento intero DIM per una funzione di riduzione che controlla la dimensione su cui viene eseguita la riduzione
•
Examples
Usando PACK per selezionare elementi che soddisfano una condizione
La funzione del pack intrinseco racchiude una matrice in un vettore, selezionando gli elementi in base a una determinata maschera. La funzione ha due forme
PACK(array, mask) PACK(array, mask, vector)
(cioè, l'argomento vector è facoltativo).
In entrambi i casi la array è una matrice e una mask di tipo logico e conforme array (uno scalare o una matrice della stessa forma).
Nel primo caso il risultato è un array di tipo 1 di tipo e parametri di tipo di array con il numero di elementi che rappresenta il numero di elementi reali nella maschera.
integer, allocatable :: positive_values(:) integer :: values(5) = [2, -1, 3, -2, 5] positive_values = PACK(values, values>0)
risultati in positive_values come matrice [2, 3, 5] .
Con l'argomento vector rank-1 presente il risultato è ora la dimensione del vector (che deve avere almeno tanti elementi quanti sono i veri valori nella mask .
L'effetto con vector è restituire quella matrice con gli elementi iniziali di quella matrice sovrascritta dagli elementi mascherati array . Per esempio
integer, allocatable :: positive_values(:) integer :: values(5) = [2, -1, 3, -2, 5] positive_values = PACK(values, values>0, [10,20,30,40,50])
Risultati in positive_values essendo la matrice [2,3,5,40,50] .
https://riptutorial.com/it/home 46
Va notato che, indipendentemente dalla forma array degli argomenti, il risultato è sempre un array di rank-1.
Oltre a selezionare gli elementi di un array che soddisfano una condizione di mascheramento, è spesso utile determinare gli indici per i quali viene soddisfatta la condizione di mascheramento. Questo linguaggio comune può essere espresso come
integer, allocatable :: indices(:) integer i indices = PACK([(i, i=1,5)], [2, -1, 3, -2, 5]>0)
risultando negli indices l'array [1,3,5] .
Leggi Procedure intrinseche online: https://riptutorial.com/it/fortran/topic/2643/procedure-intrinseche
https://riptutorial.com/it/home 47
Capitolo 10: Procedure: funzioni e subroutine
Osservazioni
Funzioni e subroutine , insieme ai moduli , sono gli strumenti per suddividere un programma in unità. Ciò rende il programma più leggibile e gestibile. Ciascuna di queste unità può essere pensata come parte del codice che, idealmente, potrebbe essere compilato e testato separatamente. I programmi principali possono chiamare (o richiamare) tali sottoprogrammi (funzioni o subroutine) per eseguire un'attività.
Le funzioni e le subroutine sono diverse nel seguente senso:
Le funzioni restituiscono un singolo oggetto e - di solito - non alterano i valori dei suoi argomenti (cioè si comportano esattamente come una funzione matematica!);
•
Le subroutine di solito svolgono un compito più complicato e ordinariamente alterano i loro argomenti (se ne esiste qualcuno), così come altre variabili (ad es. Quelle dichiarate nel modulo che contiene la subroutine).
•
Le funzioni e le subroutine vanno sotto il nome di procedure . (Nel seguito useremo il verbo "call" come sinonimo di "invocare" anche se tecnicamente le procedure da call sono subroutine s, mentre le function s appaiono come lato destro del compito o nelle espressioni.)
Examples
Sintassi della funzione
Le funzioni possono essere scritte utilizzando diversi tipi di sintassi
function name() integer name name = 42 end function
integer function name() name = 42 end function
function name() result(res) integer res res = 42 end function
Le funzioni restituiscono valori attraverso un risultato di funzione . A meno che l'istruzione della funzione non abbia una clausola di result , il result della funzione ha lo stesso nome della funzione. Con result il result della funzione è quello dato dal result . In ciascuno dei primi due esempi sopra il risultato della funzione è dato dal name ; nel terzo da res .
https://riptutorial.com/it/home 48
Il risultato della funzione deve essere definito durante l'esecuzione della funzione.
Le funzioni consentono di utilizzare alcuni prefissi speciali.
Funzione pura significa che questa funzione non ha effetti collaterali:
pure real function square(x) real, intent(in) :: x square = x * x end function
La funzione elementale è definita come operatore scalare, ma può essere invocata con array come argomento effettivo, nel qual caso la funzione verrà applicata a livello di elemento. A meno che non sia specificato il prefisso impure (introdotto in Fortran 2008), una funzione elementare è anche una funzione pura .
elemental real function square(x) real, intent(in) :: x square = x * x end function
Dichiarazione di ritorno
L'istruzione return può essere utilizzata per uscire dalla funzione e dalla subroutine. A differenza di molti altri linguaggi di programmazione non è usato per impostare il valore di ritorno.
real function f(x) real, intent(in) :: x integer :: i f = x do i = 1, 10 f = sqrt(f) - 1.0 if (f < 0) then f = -1000. return end if end do end function
Questa funzione esegue un calcolo iterativo. Se il valore di f diventa negativo, la funzione restituisce il valore -1000.
Procedure ricorsive
In Fortran, le funzioni e le subroutine devono essere esplicitamente dichiarate come ricorsive , se devono chiamarsi di nuovo, direttamente o indirettamente. Pertanto, un'implementazione ricorsiva della serie di Fibonacci potrebbe essere simile a questa:
https://riptutorial.com/it/home 49
recursive function fibonacci(term) result(fibo) integer, intent(in) :: term integer :: fibo if (term <= 1) then fibo = 1 else fibo = fibonacci(term-1) + fibonacci(term-2) end if end function fibonacci
Un altro esempio può calcolare fattoriale:
recursive function factorial(n) result(f) integer :: f integer, intent(in) :: n if(n == 0) then f = 1 else f = n * f(n-1) end if end function factorial
Affinché una funzione faccia riferimento direttamente a se stessa, la sua definizione deve utilizzare il suffisso del result . Non è possibile che una funzione sia sia recursive che elemental .
L'intento di argomenti fittizi
L'attributo intent di un argomento fittizio in una subroutine o funzione dichiara l'uso previsto. La sintassi è uno dei due
intent(IN) intent(OUT) intent(INOUT)
Ad esempio, considera questa funzione:
real function f(x) real, intent(IN) :: x f = x*x end function
L' intent(IN) specifica che l'argomento dummy (non puntatore) x non può mai essere definito o diventare indefinito in tutta la funzione o nella sua inizializzazione. Se un argomento fittizio puntatore ha l' intent(IN) attributo intent(IN) , questo vale per la sua associazione.
intent(OUT) per un argomento fittizio senza puntatore indica che l'argomento dummy diventa indefinito in caso di invocazione del sottoprogramma (ad eccezione di qualsiasi componente di un tipo derivato con inizializzazione predefinita) e deve essere impostato durante l'esecuzione. L'argomento effettivo passato come argomento fittizio deve essere definibile: il passaggio di una
https://riptutorial.com/it/home 50
costante denominata o letterale o un'espressione non è consentito.
Analogamente a prima, se un argomento fittizio puntatore è intent(OUT) lo stato di associazione del puntatore diventa indefinito. L'argomento attuale qui deve essere una variabile puntatore.
intent(INOUT) specifica che l'argomento attuale è definibile ed è adatto sia per l'inoltro che per il ritorno dei dati dalla procedura.
Infine, un argomento fittizio può essere senza l'attributo intent . Tale argomento fittizio ha il suo uso limitato dall'argomento passato.
Ad esempio, considera
integer :: i = 0 call sub(i, .TRUE.) call sub(1, .FALSE.) end subroutine sub(i, update) integer i logical, intent(in) :: update if (update) i = i+1 end subroutine
L'argomento i può avere alcun intent attributo che permette sia delle chiamate subroutine del programma principale.
Fare riferimento a una procedura
Affinché una funzione o una subroutine siano utili, è necessario fare riferimento. A una subroutine viene fatto riferimento in una dichiarazione di call
call sub(...)
e una funzione all'interno di un'espressione. A differenza di molti altri linguaggi, un'espressione non costituisce un'istruzione completa, quindi un riferimento alla funzione è spesso visto in un'istruzione di assegnazione o utilizzato in altro modo:
x = func(...) y = 1 + 2*func(...)
Esistono tre modi per designare una procedura a cui si fa riferimento:
come il nome di un puntatore di procedura o procedura•un componente di procedura di un oggetto di tipo derivato•un nome vincolante alla procedura di tipo binding•
Il primo può essere visto come
https://riptutorial.com/it/home 51
procedure(), pointer :: sub_ptr=>sub call sub() ! With no argument list the parentheses are optional call sub_ptr() end subroutine sub() end subroutine
e gli ultimi due come
module mod type t procedure(sub), pointer, nopass :: sub_ptr=>sub contains procedure, nopass :: sub end type contains subroutine sub() end subroutine end module use mod type(t) x call x%sub_ptr() ! Procedure component call x%sub() ! Binding name end
Per una procedura con argomenti fittizi, il riferimento richiede argomenti effettivi corrispondenti, sebbene non sia possibile fornire argomenti fittizi facoltativi.
Considera la subroutine
subroutine sub(a, b, c) integer a, b integer, optional :: c end subroutine
Questo può essere fatto riferimento nei seguenti due modi
call sub(1, 2, 3) ! Passing to the optional dummy c call sub(1, 2) ! Not passing to the optional dummy c
Questo è il cosiddetto riferimento posizionale : gli argomenti reali sono associati in base alla posizione negli elenchi degli argomenti. Qui, il dummy a è associato con 1 , b con 2 c (se specificato) con 3 .
In alternativa, è possibile utilizzare la referenziazione delle parole chiave quando la procedura ha un'interfaccia esplicita disponibile
https://riptutorial.com/it/home 52
call sub(a=1, b=2, c=3) call sub(a=1, b=2)
che è lo stesso di sopra.
Tuttavia, con le parole chiave gli argomenti reali possono essere offerti in qualsiasi ordine
call sub(b=2, c=3, a=1) call sub(b=2, a=1)
Possono essere utilizzati entrambi i riferimenti di posizione e parola chiave
call sub(1, c=3, b=2)
purché venga fornita una parola chiave per ogni argomento che segue la prima apparizione di una parola chiave
call sub(b=2, 1, 3) ! Not valid: all keywords must be specified
Il valore del riferimento alla parola chiave è particolarmente pronunciato quando ci sono più argomenti fittizi facoltativi, come mostrato di seguito se nella definizione della subroutine sopra b erano anche facoltativi
call sub(1, c=3) ! Optional b is not passed
Gli elenchi degli argomenti per le procedure con collegamento del testo oi puntatori alle procedure del componente con un argomento passato vengono considerati separatamente.
Leggi Procedure: funzioni e subroutine online: https://riptutorial.com/it/fortran/topic/1106/procedure--funzioni-e-subroutine
https://riptutorial.com/it/home 53
Capitolo 11: Programmazione orientata agli oggetti
Examples
Definizione del tipo derivato
Fortran 2003 ha introdotto il supporto per la programmazione orientata agli oggetti. Questa funzione consente di sfruttare le moderne tecniche di programmazione. I tipi derivati sono definiti con il seguente formato:
TYPE [[, attr-list] :: ] name [(name-list)] [def-stmts] [PRIVATE statement or SEQUENCE statement]. . . [component-definition]. . . [procedure-part] END TYPE [name]
dove,
attr-list : una lista di specificatori di attributi•nome : il nome del tipo di dati derivato•nome-elenco : un elenco di nomi di parametri di tipo separati da virgole•def-stmts : una o più dichiarazioni INTEGER dei parametri di tipo nominati nell'elenco dei nomi
•
definizione del componente - una o più istruzioni di dichiarazione del tipo o istruzioni del puntatore di procedura che definiscono il componente del tipo derivato
•
procedura-parte : un'istruzione CONTAINS, eventualmente seguita da un'istruzione PRIVATE e una o più istruzioni di associazione della procedura
•
Esempio:
type shape integer :: color end type shape
Digitare le procedure
Per ottenere un comportamento simile alla classe, il tipo e le procedure correlate (subroutine e funzioni) devono essere inseriti in un modulo:
Esempio:
module MShape implicit none private
https://riptutorial.com/it/home 54
type, public :: Shape private integer :: radius contains procedure :: set => shape_set_radius procedure :: print => shape_print end type Shape contains subroutine shape_set_radius(this, value) class(Shape), intent(in out) :: self integer, intent(in) :: value self%radius = value end subroutine shape_set_radius subroutine shape_print(this) class(Shape), intent(in) :: self print *, 'Shape: r = ', self%radius end subroutine shape_print end module MShape
Più tardi, in un codice, possiamo usare questa classe Shape come segue:
! declare a variable of type Shape type(Shape) :: shape ! call the type-bound subroutine call shape%set(10) call shape%print
Tipi derivati astratti
Un tipo derivato estensibile può essere astratto
type, abstract :: base_type end type
Tale tipo derivato non può mai essere istanziato, ad esempio da
type(base_type) t1 allocate(type(base_type) :: t2)
ma un oggetto polimorfico può avere questo come tipo dichiarato
class(base_type), allocatable :: t1
o
function f(t1) class(base_type) t1 end function
https://riptutorial.com/it/home 55
I tipi astratti possono avere componenti e procedure legate al tipo
type, abstract :: base_type integer i contains procedure func procedure(func_iface), deferred :: def_func end type
La procedura def_func è una procedura legata al tipo posticipata con interfaccia func_iface . Tale procedura legata al tipo posticipata deve essere implementata da ciascun tipo di estensione.
Digita estensione
Un tipo derivato è estensibile se non ha né l'attributo bind né l'attributo sequence . Un tal tipo può essere esteso da un altro tipo.
module mod type base_type integer i end type base_type type, extends(base_type) :: higher_type integer j end type higher_type end module mod
Una variabile polimorfica con tipo dichiarato base_type è di tipo compatibile con tipo higher_type e può avere questo come tipo dinamico
class(base_type), allocatable :: obj allocate(obj, source=higher_type(1,2))
La compatibilità di tipo discende attraverso una catena di bambini, ma un tipo può estendere solo un altro tipo.
Un tipo derivato estendente eredita le procedure legate al tipo dal genitore, ma questo può essere ignorato
module mod type base_type contains procedure :: sub => sub_base end type base_type type, extends(base_type) :: higher_type contains procedure :: sub => sub_higher end type higher_type
https://riptutorial.com/it/home 56
contains subroutine sub_base(this) class(base_type) this end subroutine sub_base subroutine sub_higher(this) class(higher_type) this end subroutine sub_higher end module mod program prog use mod class(base_type), allocatable :: obj obj = base_type() call obj%sub obj = higher_type() call obj%sub end program
Tipo costruttore
I costruttori personalizzati possono essere creati per tipi derivati utilizzando un'interfaccia per sovraccaricare il nome del tipo. In questo modo, gli argomenti delle parole chiave che non corrispondono ai componenti possono essere utilizzati durante la costruzione di un oggetto di quel tipo.
module ball_mod implicit none ! only export the derived type, and not any of the ! constructors themselves private public :: ball type :: ball_t real :: mass end type ball_t ! Writing an interface overloading 'ball_t' allows us to ! overload the type constructor interface ball_t procedure :: new_ball end interface ball_t contains type(ball_t) function new_ball(heavy) logical, intent(in) :: heavy if (heavy) then new_ball%mass = 100 else
https://riptutorial.com/it/home 57
new_ball%mass = 1 end if end function new_ball end module ball_mod program test use ball_mod implicit none type(ball_t) :: football type(ball_t) :: boulder ! sets football%mass to 4.5 football = ball_t(4.5) ! calls 'ball_mod::new_ball' boulder = ball_t(heavy=.true.) end program test
Questo può essere usato per creare un'API più ordinata rispetto all'utilizzo di routine di inizializzazione separate:
subroutine make_heavy_ball(ball) type(ball_t), intent(inout) :: ball ball%mass = 100 end subroutine make_heavy_ball ... call make_heavy_ball(boulder)
Leggi Programmazione orientata agli oggetti online: https://riptutorial.com/it/fortran/topic/2374/programmazione-orientata-agli-oggetti
https://riptutorial.com/it/home 58
Capitolo 12: Tipi di dati
Examples
Tipi intrinseci
I seguenti sono tipi di dati intrinseci a Fortran:
integer real character complex logical
integer , real e complex sono tipi numerici.
character è un tipo usato per memorizzare stringhe di caratteri.
logical è usato per memorizzare valori .true. o .false. .
Tutti i tipi numerici e logici intrinseci sono parametrizzati utilizzando i tipi.
integer(kind=specific_kind)
o semplicemente
integer(specific_kind)
dove specific_kind è un numero intero chiamato constant.
Le variabili di caratteri, oltre ad avere un parametro gentile, hanno anche un parametro di lunghezza:
character char
dichiara che char è una variabile di lunghezza 1 di tipo predefinito, mentre
character(len=len) name
dichiara che il name è una variabile di carattere di tipo predefinito e lunghezza len . Il tipo può anche essere specificato
character(len=len, kind=specific_kind) name character(kind=specific_kind) char
dichiara che il name è un personaggio di tipo kind e lunghezza len . char è un carattere lunghezza-1 di tipo kind .
https://riptutorial.com/it/home 59
In alternativa, il modulo obsoleto per la dichiarazione dei caratteri
character*len name
può essere visto nel vecchio codice, dichiarando che il name è di lunghezza len e tipo di carattere predefinito.
La dichiarazione di una variabile di tipo intrinseco può essere nella forma in alto, ma può anche usare il type(...) :
integer i real x double precision y
è equivalente a (ma molto preferito sopra)
type(integer) i type(real) x type(double precision) y
Tipi di dati derivati
Definisci un nuovo tipo, mytype :
type :: mytype integer :: int real :: float end type mytype
Dichiarare una variabile di tipo mytype :
type(mytype) :: foo
È possibile accedere ai componenti di un tipo derivato con % operator 1 :
foo%int = 4 foo%float = 3.142
Una funzionalità di Fortran 2003 (non ancora implementata da tutti i compilatori) consente di definire tipi di dati parametrizzati:
type, public :: matrix(rows, cols, k) integer, len :: rows, cols integer, kind :: k = kind(0.0) real(kind = k), dimension(rows, cols) :: values end type matrix
Il tipo derivato matrix ha tre parametri tipo che sono elencati in parentesi dopo il nome tipo (sono
https://riptutorial.com/it/home 60
rows , cols e k ). Nella dichiarazione di ogni parametro di tipo deve essere indicato se sono di tipo gentile ( kind ) o lunghezza ( len ).
I parametri tipo tipo, come quelli dei tipi intrinseci, devono essere espressioni costanti, mentre i parametri del tipo di lunghezza, come la lunghezza di una variabile di carattere intrinseco, possono variare durante l'esecuzione.
Si noti che il parametro k ha un valore predefinito, quindi può essere fornito o omesso quando viene dichiarata una variabile di tipo matrix , come segue
type (matrix (55, 65, kind=double)) :: b, c ! default parameter provided type (matrix (rows=40, cols=50) :: m ! default parameter omitted
Il nome di un tipo derivato potrebbe non essere a doubleprecision o uguale a uno qualsiasi dei tipi intrinseci.
Molte persone si chiedono perché Fortran usi % come operatore di accesso ai componenti, anziché il più comune . . Questo perché . è già utilizzato dalla sintassi dell'operatore, ad esempio .not. , .and. , .my_own_operator. .
1.
Precisione dei numeri in virgola mobile
I numeri in virgola mobile di tipo real non possono avere alcun valore reale. Possono rappresentare numeri reali fino a una certa quantità di cifre decimali.
FORTRAN 77 ha garantito due tipi di virgola mobile e standard più recenti garantiscono almeno due tipi reali. Le variabili reali possono essere dichiarate come
real x double precision y
x qui è un vero tipo di default e y è un vero tipo con una precisione decimale maggiore di x . In Fortran 2008, la precisione decimale di y è almeno 10 e il suo intervallo di esponenti decimali almeno 37.
real, parameter :: single = 1.12345678901234567890 double precision, parameter :: double = 1.12345678901234567890d0 print *, single print *, double
stampe
1.12345684 1.1234567890123457
nei compilatori comuni che utilizzano la configurazione predefinita.
https://riptutorial.com/it/home 61
Notare il d0 nella costante a doppia precisione. Un vero letterale contenente d invece di e per denotare l'esponente viene usato per indicare la doppia precisione.
! Default single precision constant 1.23e45 ! Double precision constant 1.23d45
Fortran 90 ha introdotto tipi real parametrizzati usando i tipi. Il tipo di un tipo reale è un numero denominato costante costante o letterale:
real(kind=real_kind) :: x
o semplicemente
real(real_kind) :: x
Questa dichiarazione dichiara che x è di tipo real con una certa precisione a seconda del valore di real_kind .
I letterali in virgola mobile possono essere dichiarati con un tipo specifico usando un suffisso
1.23456e78_real_kind
Il valore esatto di real_kind non è standardizzato e differisce da compilatore a compilatore. Per verificare il tipo di qualsiasi variabile o costante reale, è possibile utilizzare il kind() funzione kind() :
print *, kind(1.0), kind(1.d0)
tipicamente stamperà
4 8
o
1 2
a seconda del compilatore.
I numeri di tipo possono essere impostati in diversi modi:
Singolo (predefinito) e doppia precisione:
integer, parameter :: single_kind = kind(1.) integer, parameter :: double_kind = kind(1.d0)
1.
Usando la funzione intrinseca selected_real_kind([p, r]) per specificare la precisione decimale richiesta. Il tipo restituito ha una precisione di almeno p cifre e consente l'esponente di almeno r .
2.
https://riptutorial.com/it/home 62
integer, parameter :: single_kind = selected_real_kind( p=6, r=37 ) integer, parameter :: double_kind = selected_real_kind( p=15, r=200 )
A partire da Fortran 2003, le costanti predefinite sono disponibili tramite il modulo intrinseco ISO_C_Binding per garantire che i tipi reali siano interoperabili con i tipi float , double o long_double del compilatore C associato:
use ISO_C_Binding integer, parameter :: single_kind = c_float integer, parameter :: double_kind = c_double integer, parameter :: long_kind = c_long_double
3.
A partire da Fortran 2008, le costanti predefinite sono disponibili tramite il modulo intrinseco ISO_Fortran_env . Queste costanti forniscono tipi reali con determinate dimensioni di memoria in bit
use ISO_Fortran_env integer, parameter :: single_kind = real32 integer, parameter :: double_kind = real64 integer, parameter :: quadruple_kind = real128
4.
Se un determinato tipo non è disponibile nel compilatore, il valore restituito da selected_real_kind() o il valore della costante intera è -1 .
Parametri di tipo lunghezza presunta e differita
Le variabili di tipo carattere o di tipo derivato con parametro lunghezza possono avere il parametro lunghezza assunto o differito . Il name variabile di carattere
character(len=len) name
è di lunghezza len durante l'esecuzione. Viceversa lo specificatore della lunghezza può essere o
character(len=*) ... ! Assumed length
o
character(len=:) ... ! Deferred length
Le variabili di lunghezza ipotizzate assumono la loro lunghezza da un'altra entità.
Nella funzione
function f(dummy_name) character(len=*) dummy_name end function f
https://riptutorial.com/it/home 63
l'argomento fittizio dummy_name ha lunghezza quella dell'argomento effettivo.
La costante const_name con nome in
character(len=*), parameter :: const_name = 'Name from which length is assumed'
ha lunghezza data dall'espressione costante sul lato destro.
I parametri di tipo lunghezza differita possono variare durante l'esecuzione. Una variabile con lunghezza posticipata deve avere l'attributo allocatable o pointer
character(len=:), allocatable :: alloc_name character(len=:), pointer :: ptr_name
La lunghezza di tale variabile può essere impostata in uno dei seguenti modi
allocate(character(len=5) :: alloc_name, ptr_name) alloc_name = 'Name' ! Using allocation on intrinsic assignment ptr_name => another_name ! For given target
Per i tipi derivati con parametrizzazione della lunghezza la sintassi è simile
type t(len) integer, len :: len integer i(len) end type t type(t(:)), allocatable :: t1 type(t(5)) t2 call sub(t2) allocate(type(t(5)) :: t1) contains subroutine sub(t2) type(t(*)), intent(out) :: t2 end subroutine sub end
Costanti letterali
Le unità di programma usano spesso costanti letterali. Questi coprono i casi ovvi come
print *, "Hello", 1, 1.0
Tranne che in un caso, ogni costante letterale è uno scalare che ha tipo, parametri di tipo e valore dati dalla sintassi.
https://riptutorial.com/it/home 64
Le costanti letterali intere sono della forma
1 -1 -1_1 ! For valid kind parameter 1 1_ik ! For the named constant ik being a valid kind paramter
Le vere costanti letterali sono della forma
1.0 ! Default real 1e0 ! Default real using exponent format 1._1 ! Real with kind parameter 1 (if valid) 1.0_sp ! Real with kind paramter named constant sp 1d0 ! Double precision real using exponent format 1e0_dp ! Real with kind named constant dp using exponent format
Le costanti letterali complesse sono della forma
(1, 1.) ! Complex with integer and real components, literal constants (real, imag) ! Complex with named constants as components
Se i componenti reali e immaginari sono entrambi interi, la costante letterale complessa è complessa di default e i componenti interi vengono convertiti in valori reali predefiniti. Se un componente è reale, il parametro gentile della costante letterale complessa è quello reale (e il componente intero viene convertito in quel tipo reale). Se entrambi i componenti sono reali, la costante letterale complessa è del tipo del reale con la massima precisione.
Le costanti letterali logiche sono
.TRUE. ! Default kind, with true value
.FALSE. ! Default kind, with false value
.TRUE._1 ! Of kind 1 (if valid), with true value
.TRUE._lk ! Of kind named constant lk (if valid), with true value
I valori letterali dei caratteri differiscono leggermente nel concetto, in quanto l'identificatore gentile precede il valore
"Hello" ! Character value of default kind 'Hello' ! Character value of default kind ck_"Hello" ! Character value of kind ck "'Bye" ! Default kind character with a ' '''Bye' ! Default kind character with a ' "" ! A zero-length character of default kind
Come suggerito sopra, le costanti letterali dei caratteri devono essere delimitate da apostrofi o virgolette e il marcatore di inizio e fine deve corrispondere. Gli apostrofi letterali possono essere inclusi tra i delimitatori delle virgolette o apparendo raddoppiati. Lo stesso per le virgolette.
Le costanti BOZ sono distinte da quelle precedenti, in quanto specificano solo un valore: non hanno alcun parametro di tipo o tipo. Una costante BOZ è un modello di bit e viene specificata come
https://riptutorial.com/it/home 65
B'00000' ! A binary bit pattern B"01010001" ! A binary bit pattern O'012517' ! An octal bit pattern O"1267671" ! An octal bit pattern Z'0A4F' ! A hexadecimal bit pattern Z"FFFFFF" ! A hexadecimal bit pattern
Le costanti letterali BOZ sono limitate dove possono apparire: come costanti nelle dichiarazioni di data e una selezione di procedure intrinseche.
Accesso alle sottostringhe dei caratteri
Per l'entità del personaggio
character(len=5), parameter :: greeting = "Hello"
una sottostringa può essere referenziata con la sintassi
greeting(2:4) ! "ell"
Per accedere a una singola lettera non è sufficiente scrivere
greeting(1) ! This isn't the letter "H"
ma
greeting(1:1) ! This is "H"
Per un array di caratteri
character(len=5), parameter :: greeting(2) = ["Hello", "Yo! "]
abbiamo l'accesso alla sottostringa come
greeting(1)(2:4) ! "ell"
ma non possiamo fare riferimento ai caratteri non contigui
greeting(:)(2:4) ! The parent string here is an array
Possiamo persino accedere a sottostringhe di costanti letterali
"Hello"(2:4)
Una parte di una variabile di carattere può anche essere definita utilizzando una sottostringa come variabile. Per esempio
https://riptutorial.com/it/home 66
integer :: i=1 character :: filename = 'file000.txt' filename(9:11) = 'dat' write(filename(5:7), '(I3.3)') i
Accesso a componenti complessi
L'entità complessa
complex, parameter :: x = (1., 4.)
ha la parte reale 1. e la parte complessa 4. .. Possiamo accedere a questi singoli componenti come
real(x) ! The real component aimag(x) ! The complex component x%re ! The real component y%im ! The complex component
Il formato x%.. è nuovo per Fortran 2008 e non ampiamente supportato nei compilatori. Questo modulo, tuttavia, può essere utilizzato per impostare direttamente i singoli componenti di una variabile complessa
complex y y%re = 0. y%im = 1.
Dichiarazione e attributi
Attraverso gli argomenti e gli esempi qui vedremo molte dichiarazioni di variabili, funzioni e così via.
Oltre al loro nome, gli oggetti dati possono avere attributi . Coperti in questo argomento sono dichiarazioni dichiarazioni come
integer, parameter :: single_kind = kind(1.)
che dà all'oggetto single_kind l'attributo del parameter (rendendolo una costante nominata).
Ci sono molti altri attributi, come
target•pointer•optional•save•
Gli attributi possono essere specificati con le cosiddette dichiarazioni di specifica degli attributi
integer i ! i is an integer (of default kind)...
https://riptutorial.com/it/home 67
pointer i ! ... with the POINTER attribute... optional i ! ... and the OPTIONAL attribute
Tuttavia, si ritiene generalmente che sia meglio evitare di utilizzare queste dichiarazioni di specifica degli attributi. Per chiarezza gli attributi possono essere specificati come parte di una singola dichiarazione
integer, pointer, optional :: i
Ciò riduce anche la tentazione di utilizzare la digitazione implicita.
Nella maggior parte dei casi in questa documentazione Fortran questa dichiarazione di dichiarazione singola è preferita.
Leggi Tipi di dati online: https://riptutorial.com/it/fortran/topic/939/tipi-di-dati
https://riptutorial.com/it/home 68
Capitolo 13: Unità di programma e layout di file
Examples
Programmi Fortran
Un programma Fortran completo è composto da un numero di unità di programma distinte. Le unità del programma sono:
programma principale•funzione o sottoprogramma subroutine•modulo o sottomodulo•bloccare l'unità di programma di dati•
Il programma principale e alcuni sottoprogrammi di routine (funzione o subroutine) possono essere forniti da una lingua diversa da Fortran. Ad esempio, un programma principale C può chiamare una funzione definita da un sottoprogramma della funzione Fortran, oppure un programma principale Fortran può chiamare una procedura definita da C.
Queste unità del programma Fortran possono essere fornite come file distinti o all'interno di un singolo file.
Ad esempio, potremmo vedere i due file:
prog.f90
program main use mod end program main
mod.f90
module mod end module mod
E il compilatore (invocato correttamente) sarà in grado di associare il programma principale al modulo.
Il singolo file può contenere molte unità di programma
everything.f90
module mod end module mod program prog
https://riptutorial.com/it/home 69
use mod end program prog function f() end function f()
In questo caso, tuttavia, si deve notare che la funzione f è ancora una funzione esterna per quanto riguarda il programma principale e il modulo. Il modulo sarà accessibile dal programma principale, tuttavia.
Le regole dell'ambito di digitazione si applicano a ogni singola unità di programma e non al file in cui sono contenute. Ad esempio, se vogliamo che ogni unità di scoping non abbia una digitazione implicita, il file sopra riportato deve essere scritto come
module mod implicit none end module mod program prog use mod implicit none end program prog function f() implicit none <type> f end function f
Moduli e sottomoduli
I moduli sono documentati altrove .
I compilatori spesso generano i cosiddetti file di modulo : di solito il file che contiene
module my_module end module
risulterà in un file chiamato qualcosa come my_module.mod dal compilatore. In tali casi, affinché un modulo sia accessibile da un'unità di programma, quel file di modulo deve essere visibile prima che quest'ultima unità di programma venga elaborata.
Procedure esterne
Una procedura esterna è quella che è definita al di fuori di un'altra unità di programma o con un mezzo diverso da Fortran.
La funzione contenuta in un file come
integer function f() implicit none end function f
https://riptutorial.com/it/home 70
è una funzione esterna.
Per le procedure esterne, la loro esistenza può essere dichiarata usando un blocco di interfaccia (a una interfaccia esplicita)
program prog implicit none interface integer function f() end interface end program prog
o da una dichiarazione dichiarazione per dare un'interfaccia implicita
program prog implicit none integer, external :: f end program prog
o anche
program prog implicit none integer f external f end program prog
L'attributo external non è necessario:
program prog implicit none integer i integer f i = f() ! f is now an external function end program prog
Blocca le unità del programma di dati
Le unità del programma di dati di blocco sono unità di programma che forniscono valori iniziali per oggetti in blocchi comuni. Questi sono deliberatamente lasciati senza documenti qui, e saranno presenti nella documentazione delle caratteristiche storiche di Fortran.
Sottoprogrammi interni
Un'unità di programma che non è un sottoprogramma interno può contenere altre unità di programma, chiamate sottoprogrammi interni .
program prog implicit none contains function f() end function f
https://riptutorial.com/it/home 71
subroutine g() end subroutine g end program
Tale sottoprogramma interno ha una serie di caratteristiche:
esiste un'associazione host tra entità nel sottoprogramma e il programma esterno•le regole di digitazione implicite sono ereditate ( implicit none è in vigore in f sopra)•i sottoprogrammi interni hanno un'interfaccia esplicita disponibile nell'host•
Sottoprogrammi di modulo e sottoprogrammi esterni possono avere sottoprogrammi interni come
module mod implicit none contains function f() contains subroutine s() end subroutine s end function f end module mod
File di codice sorgente
Un file di codice sorgente è un file di testo (generalmente) che deve essere elaborato dal compilatore. Un file di codice sorgente può contenere un massimo di un programma principale e un numero qualsiasi di moduli e sottoprogrammi esterni. Ad esempio, un file di codice sorgente può contenere quanto segue
module mod1 end module mod1 module mod2 end module mod2 function func1() ! An external function end function func1 subroutine sub1() ! An external subroutine end subroutine sub1 program prog ! The main program starts here... end program prog ! ... and ends here function func2() ! An external function end function func2
Qui dovremmo ricordare che, anche se i sottoprogrammi esterni sono dati nello stesso file dei moduli e del programma principale, i sottoprogrammi esterni non sono esplicitamente noti da nessun altro componente.
In alternativa, i singoli componenti possono essere distribuiti su più file e anche compilati in momenti diversi. La documentazione del compilatore dovrebbe essere letta su come combinare
https://riptutorial.com/it/home 72
più file in un singolo programma.
Un singolo file di codice sorgente può contenere codice sorgente in forma fissa o in formato libero: non possono essere mescolati, sebbene più file combinati in fase di compilazione possano avere stili diversi.
Per indicare al compilatore il modulo sorgente ci sono generalmente due opzioni:
scelta del suffisso del nome file•uso dei flag del compilatore•
Il flag di compilazione per indicare una fonte fissa o di forma libera può essere trovato nella documentazione del compilatore.
I suffissi significativi dei nomi dei file si trovano anche nella documentazione del compilatore, ma come regola generale un file denominato file.f90 viene utilizzato per contenere l'origine in forma libera mentre il file file.f viene utilizzato per contenere l'origine in forma fissa.
L'uso del suffisso .f90 per indicare l'origine in forma libera (che è stata introdotta nello standard Fortran 90) spesso induce il programmatore a utilizzare il suffisso per indicare lo standard di linguaggio a cui il codice sorgente è conforme. Ad esempio, potremmo vedere file con suffissi .f03 o .f08 . Ciò è generalmente da evitare: la maggior parte dei sorgenti di Fortran 2003 è anche compatibile con Fortran 77, Fortran 90/5 e Fortran 2008. Inoltre, molti concorrenti non considerano automaticamente tali suffissi.
I compilatori offrono spesso anche un preprocessore di codice incorporato (generalmente basato su cpp). Ancora una volta, può essere usato un flag in fase di compilazione per indicare che il preprocessore deve essere eseguito prima della compilazione, ma il suffisso del file del codice sorgente può anche indicare tale requisito di pre-elaborazione.
Per i filesystem con distinzione tra maiuscole e minuscole, il file file.F viene spesso considerato come un file sorgente di forma fissa da sottoporre a pre-elaborazione e file.F90 per essere un file di origine in formato libero da sottoporre a pre-elaborazione. Come prima, la documentazione del compilatore dovrebbe essere consultata per tali flag e suffissi di file.
Leggi Unità di programma e layout di file online: https://riptutorial.com/it/fortran/topic/2203/unita-di-programma-e-layout-di-file
https://riptutorial.com/it/home 73
Capitolo 14: Utilizzo dei moduli
Examples
Sintassi del modulo
Il modulo è una raccolta di dichiarazioni di tipo, dichiarazioni di dati e procedure. La sintassi di base è:
module module_name use other_module_being_used ! The use of implicit none here will set it for the scope of the module. ! Therefore, it is not required (although considered good practice) to repeat ! it in the contained subprograms. implicit none ! Parameters declaration real, parameter, public :: pi = 3.14159 ! The keyword private limits access to e parameter only for this module real, parameter, private :: e = 2.71828 ! Type declaration type my_type integer :: my_int_var end type ! Variable declaration integer :: my_integer_variable ! Subroutines and functions belong to the contains section contains subroutine my_subroutine !module variables are accessible print *, my_integer_variable end subroutine real function my_func(x) real, intent(in) :: x my_func = x * x end function my_func end module
Utilizzo di moduli da altre unità di programma
Per accedere a entità dichiarate in un modulo da un'altra unità di programma (modulo, procedura o programma), il modulo deve essere utilizzato con l'istruzione use .
module shared_data implicit none integer :: iarray(4) = [1, 2, 3, 4]
https://riptutorial.com/it/home 74
real :: rarray(4) = [1., 2., 3., 4.] end module program test !use statements most come before implicit none use shared_data implicit none print *, iarray print *, rarray end program
L'istruzione use supporta l'importazione solo dei nomi selezionati
program test !only iarray is accessible use shared_data, only: iarray implicit none print *, iarray end program
È possibile accedere alle entità anche con un nome diverso utilizzando una lista di ridenominazione :
program test !only iarray is locally renamed to local_name, rarray is still acessible use shared_data, local_name => iarray implicit none print *, local_name print *, rarray end program
Inoltre, la rinomina può essere combinata con l' only opzione
program test use shared_data, only : local_name => iarray end program
in modo che sia accessibile solo l' iarray del modulo, ma ha il nome locale local_name .
Se selezionato per l'importazione di nomi contrassegnati come privati, non è possibile importarli nel programma.
https://riptutorial.com/it/home 75
Moduli intrinseci
Fortran 2003 ha introdotto moduli intrinseci che forniscono accesso a costanti speciali denominate, tipi derivati e procedure modulo. Ora ci sono cinque moduli intrinseci standard:
ISO_C_Binding ; supportare l'interoperabilità C;•ISO_Fortran_env ; dettagliando l'ambiente Fortran;•IEEE_Exceptions , IEEE_Arithmetic e IEEE_Features ; supporto della cosiddetta funzione aritmetica IEEE.
•
Questi moduli intrinseci fanno parte della libreria Fortran e sono accessibili come altri moduli, tranne che l'istruzione use può avere la natura intrinseca esplicitamente dichiarata:
use, intrinsic :: ISO_C_Binding
Ciò garantisce che il modulo intrinseco venga utilizzato quando è disponibile un modulo fornito dall'utente con lo stesso nome. al contrario
use, non_intrinsic :: ISO_C_Binding
si accerta che lo stesso modulo fornito dall'utente (che deve essere accessibile) sia accessibile al posto del modulo intrinseco. Senza la natura del modulo specificata come in
use ISO_C_Binding
un modulo non intrinseco disponibile sarà preferito rispetto al modulo intrinseco.
I moduli IEEE intrinseci sono diversi dagli altri moduli in quanto la loro accessibilità in una unità di scoping può cambiare il comportamento del codice anche senza riferimento a nessuna delle entità definite in essi.
Controllo di accesso
L'accessibilità dei simboli dichiarati in un modulo può essere controllata utilizzando attributi e dichiarazioni private e public .
Sintassi del modulo di dichiarazione:
!all symbols declared in the module are private by default private !all symbols declared in the module are public by default public !symbols in the list will be private private :: name1, name2 !symbols in the list will be public public :: name3, name4
https://riptutorial.com/it/home 76
Sintassi del modulo di attributo:
integer, parameter, public :: maxn = 1000 real, parameter, private :: local_constant = 42.24
È possibile accedere ai simboli pubblici dalle unità di programma utilizzando il modulo, ma i simboli privati non possono.
Quando non viene utilizzata alcuna specifica, l'impostazione predefinita è public .
La specifica di accesso predefinita usando
private
o
public
può essere modificato specificando un accesso diverso con elenco dichiarazione-entità
public :: name1, name2
o usando attributi.
Questo controllo di accesso influisce anche sui simboli importati da un altro modulo:
module mod1 integer :: var1 end module module mod2 use mod1, only: var1 public end module program test use mod2, only: var1 end program
è possibile, ma
module mod1 integer :: var1 end module module mod2 use mod1, only: var1 public private :: var1 end module
https://riptutorial.com/it/home 77
program test use mod2, only: var1 end program
non è possibile perché var è privato in mod2 .
Entità modulo protetto
Oltre a consentire alle entità del modulo di avere il controllo dell'accesso (essendo public o private ) le entità dei moduli possono anche avere l'attributo protect . Un'entità pubblica protetta può essere associata all'utilizzo, ma l'entità utilizzata è soggetta a restrizioni sul suo utilizzo.
module mod integer, public, protected :: i=1 end module program test use mod, only : i print *, i ! We are allowed to get the value of i i = 2 ! But we can't change the value end program test
Un obiettivo pubblico protetto non può essere indicato all'esterno del suo modulo
module mod integer, public, target, protected :: i end module mod program test use mod, only : i integer, pointer :: j j => i ! Not allowed, even though we aren't changing the value of i end program test
Per un puntatore protetto pubblico in un modulo le restrizioni sono diverse. Ciò che è protetto è lo stato di associazione del puntatore
module mod integer, public, target :: j integer, public, protected, pointer :: i => j end module mod program test use mod, only : i i = 2 ! We may change the value of the target, just not the association status end program test
Come con i puntatori variabili, anche i puntatori di procedura possono essere protetti, impedendo nuovamente il cambio dell'associazione target.
Leggi Utilizzo dei moduli online: https://riptutorial.com/it/fortran/topic/1139/utilizzo-dei-moduli
https://riptutorial.com/it/home 78
Titoli di coda
S. No
Capitoli Contributors
1 Iniziare con FortranAlexander Vogt, Community, Enrico Maria De Angelis, Gilles, haraldkl, High Performance Mark, Ingve, innoSPG, milancurcic, packet0, RamenChef, Serenity, Vladimir F, Yossarian
2Alternative moderne a caratteristiche storiche
Brian Tompsett - , d_1999, Enrico Maria De Angelis, francescalus, Serenity, TTT, Vladimir F, Yossarian
3 ArrayEnrico Maria De Angelis, francescalus, G.Clavier, Gilles, Serenity, TTT, Vladimir F, Yossarian
4Controllo dell'esecuzione
Enrico Maria De Angelis, francescalus, haraldkl, ptev, Serenity, syscreat, TTT, Vladimir F
5
Estensioni di file di origine (.f, .f90, .f95, ...) e in che modo sono correlati al compilatore.
Arun
6 I / O AL-P, Ed Smith, francescalus, Kyle Kanos, TTT
7Interfacce esplicite e implicite
Enrico Maria De Angelis, Serenity, Vladimir F
8 Interoperabilità C Serenity, Yossarian
9Procedure intrinseche
francescalus
10Procedure: funzioni e subroutine
Alexander Vogt, Enrico Maria De Angelis, francescalus, haraldkl, Serenity, Vladimir F, Yossarian
11Programmazione orientata agli oggetti
Enrico Maria De Angelis, francescalus, syscreat, Yossarian
12 Tipi di datiAlexander Vogt, Enrico Maria De Angelis, francescalus, Vladimir F, Yossarian
13Unità di programma e layout di file
agentp, francescalus, haraldkl, trblnc
Alexander Vogt, Enrico Maria De Angelis, francescalus, 14 Utilizzo dei moduli
https://riptutorial.com/it/home 79
Serenity, Vladimir F
https://riptutorial.com/it/home 80