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:

  1. L'intero array x ;
  2. Elementi di matrice, come x(1) ;
  3. 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)


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow