Ricerca…
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, 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
(/ ... /)
[ ... ]
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
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
- 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 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
real x(10)
Quindi abbiamo tre aspetti di interesse:
- L'intero array
x
; - Elementi di matrice, come
x(1)
; - Sezioni di array, come
x(2:6)
.
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)
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
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
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
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)