Zoeken…


Basisnotatie

Elk type kan worden gedeclareerd als een array met behulp van het dimensie- kenmerk of door gewoon direct de dimension (s) van de array aan te geven:

! 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)

De laatste manier om multidimensionale array te declareren, maakt de declaratie van arrays van hetzelfde type verschillende rang / dimensies in één regel mogelijk, als volgt

real :: pencil(5), plate(3,-2:4), cuboid(0:3,-10:5,6)

De maximaal toegestane rang (aantal dimensies) is 15 in Fortran 2008-standaard en was eerder 7.

Fortran slaat arrays op in kolom-grote volgorde. Dat wil zeggen dat de elementen van de bar als volgt in het geheugen worden opgeslagen:

bar(1, 1), bar(2, 1), bar(3, 1), bar(4, 1), bar(1, 2), bar(2, 2), ...

In Fortran begint matrixnummering standaard bij 1 , in tegenstelling tot C die begint bij 0 . In Fortran kunt u zelfs de boven- en ondergrenzen voor elke dimensie expliciet opgeven:

integer, dimension(7:12, -3:-1) :: geese

Dit verklaart een reeks vormen (6, 3) , waarvan het eerste element geese(7, -3) .

Onder- en bovengrenzen langs de 2 (of meer) dimensies zijn toegankelijk via de intrinsieke functies ubound en lbound . lbound(geese,2) zou inderdaad -3 retourneren, terwijl ubound(geese,1) 12 zou retourneren.

Grootte van een array kan worden benaderd door intrinsieke functie size . size(geese, dim = 1) retourneert bijvoorbeeld de grootte van de eerste dimensie die 6 is.

Toewijsbare arrays

Arrays kunnen het toewijsbare kenmerk hebben:

! One dimensional allocatable array
integer, dimension(:), allocatable :: foo
! Two dimensional allocatable array
real, dimension(:,:), allocatable :: bar

Dit declareert de variabele maar wijst er geen ruimte voor toe.

! 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

Als een variabele niet langer nodig is, kan deze worden toegewezen :

deallocate(foo)

Als om welke reden dan ook een allocate mislukt, stopt het programma. Dit kan worden voorkomen als de status wordt gecontroleerd via het stat trefwoord:

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

De deallocate instructie heeft ook een stat trefwoord:

deallocate (geese, stat=status)

status is een variabele met een geheel getal waarvan de waarde 0 is als de toewijzing of de toewijzing is geslaagd.

Matrixconstructeurs

Een rang-1 matrixwaarde kan worden gemaakt met behulp van een matrixconstructor , met de syntaxis

(/ ... /)
[ ... ]

De vorm [...] werd geïntroduceerd in Fortran 2003 en wordt over het algemeen als duidelijk leesbaarder beschouwd, vooral in complexe uitdrukkingen. Dit formulier wordt uitsluitend in dit voorbeeld gebruikt.

De waarden die voorkomen in een array-constructor kunnen scalaire waarden, arraywaarden of impliciete do-loops zijn.

Het type en de typeparameters van de geconstrueerde array komen overeen met die van de waarden in de arrayconstructor

[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

In de bovenstaande formulieren moeten alle opgegeven waarden van hetzelfde type en dezelfde parameter zijn. Mixen van typen of typeparameters is niet toegestaan. De volgende voorbeelden zijn niet geldig

[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

Om een array met verschillende typen te construeren, moet een typespecificatie voor de array worden gegeven

[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

Deze laatste vorm voor tekenreeksen is vooral handig om opvulling in de ruimte, zoals het alternatief, te voorkomen

["Hello    ", "Frederick"]  ! A length-2 array of length-9 characters

De grootte van een array met de naam constant kan worden geïmpliceerd door de arrayconstructor die wordt gebruikt om de waarde in te stellen

integer, parameter :: ids(*) = [1, 2, 3, 4]

en voor lengte-geparametriseerde typen kan de lengte-parameter worden aangenomen

character(len=*), parameter :: names(*) = [character(3) :: "Me", "You", "Her"]

De typespecificatie is ook vereist bij de constructie van arrays met lengte nul. Van

[ ] ! Not a valid array constructor

het type en de typeparameters kunnen niet worden bepaald aan de hand van de niet-bestaande waardenset. Een standaard integer array met lengte nul maken:

[integer :: ]

Matrixconstructors construeren alleen rang-1-arrays. Soms, zoals bij het instellen van de waarde van een benoemde constante, zijn arrays met een hogere rang ook vereist in een expressie. Arrays met een hogere rang kunnen worden genomen uit het resultaat van een nieuwe reshape met een geconstrueerde rang-1 array

integer, parameter :: multi_rank_ids(2,2) = RESHAPE([1,2,3,4], shape=[2,2])

In een array-constructor zijn de waarden van de array in elementvolgorde, waarbij alle arrays in de waardelijst zijn alsof de afzonderlijke elementen zelf in de arrayelementvolgorde worden gegeven. Dus het eerdere voorbeeld

integer, parameter :: A = [2, 4]
[1, A, 3]      ! A rank-1 length-4 array of default integer type, with A's elements

is gelijk aan

[1, 2, 4, 3]   ! With the array written out in array element order

Over het algemeen kunnen de waarden in de constructor willekeurige expressies zijn, inclusief geneste array-constructors. Voor een dergelijke array-constructor om aan bepaalde voorwaarden te voldoen, zoals een constante of specificatie-expressie, zijn beperkingen van toepassing op samenstellende waarden.


Hoewel het geen array-constructor is, kunnen bepaalde arraywaarden ook handig worden gemaakt met de intrinsieke spread functie. Bijvoorbeeld

[(0, i=1,10)]  ! An array with 10 default integers each of value 0

is ook het resultaat van de functieverwijzing

SPREAD(0, 1, 10)

Array nature-specificatie: rang en vorm

Het dimension van een object geeft aan dat dat object een array is. Er zijn, in Fortran 2008, vijf matrixniveaus: 1

  • expliciete vorm
  • vorm aangenomen
  • veronderstelde grootte
  • uitgestelde vorm
  • impliciete vorm

Neem de drie rang-1 arrays 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

Hiermee is te zien dat verdere context nodig is om de aard van een array volledig te bepalen.

Expliciete vorm

Een expliciete vormmatrix is altijd de vorm van de verklaring. Tenzij de array wordt gedeclareerd als lokaal voor een subprogramma of block , moeten de grenzen die de vorm definiëren, constante expressies zijn. In andere gevallen kan een expliciete vormmatrix een automatisch object zijn, waarbij extensies worden gebruikt die kunnen variëren bij elke aanroep van een subprogramma of 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

Aangenomen vorm

Een veronderstelde allocatable is een allocatable zonder het allocatable of de pointer . Een dergelijke array neemt zijn vorm aan van het feitelijke argument waaraan hij is gekoppeld.

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

Wanneer een dummy-argument vorm heeft aangenomen, moet het bereik dat naar de procedure verwijst, een expliciete interface beschikbaar hebben voor die procedure.

Aangenomen maat

Een veronderstelde groottematrix is een dummyargument waarvan de grootte wordt aangenomen op basis van het feitelijke argument.

subroutine sub(x)
  integer x(*)   ! Assumed size array
end subroutine

Aangenomen dat groottematrices zich heel anders gedragen dan veronderstelde vormmatrices en deze verschillen zijn elders gedocumenteerd.

Uitgestelde vorm

Een array met uitgestelde vormen is een array met het allocatable of pointer . De vorm van een dergelijke array wordt bepaald door de toewijzing of pointer-toewijzing.

integer, allocatable :: a(:)
integer, pointer :: b(:)

Impliciete vorm

Een geïmpliceerde vormmatrix is een benoemde constante die zijn vorm ontleent aan de uitdrukking die wordt gebruikt om zijn waarde vast te stellen

integer, parameter :: a(*) = [1,2,3,4]

De implicaties van deze arrayverklaringen voor dummyargumenten moeten elders worden gedocumenteerd.


1 Een technische specificatie die Fortran 2008 uitbreidt, voegt een zesde array toe: veronderstelde rang. Dit wordt hier niet behandeld.

2 Deze kunnen evenzo worden geschreven als

integer, dimension(5) :: a
integer, dimension(:) :: b
integer, dimension(*) :: c

of

integer a(5)
integer b(:)
integer c(*)

Hele arrays, arrayelementen en arraysecties

Beschouw de array die is aangegeven als

real x(10)

Dan hebben we drie aspecten van belang:

  1. De hele array x ;
  2. Matrixelementen, zoals x(1) ;
  3. Matrixsecties, zoals x(2:6) .

Hele arrays

In de meeste gevallen verwijst de hele array x naar alle elementen van de array als een enkele entiteit. Het kan voorkomen in uitvoerbare instructies zoals print *, SUM(x) , print *, SIZE(x) of x=1 .

Een hele array kan verwijzen naar arrays die niet expliciet van vorm zijn (zoals x hierboven):

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

Een array met een veronderstelde grootte kan ook als een hele array worden weergegeven, maar alleen in beperkte omstandigheden (elders te documenteren).

Matrixelementen

Een array-element geeft gehele indexen aan, één voor elke rangorde van de array, die de locatie in de hele array aangeeft:

real x(5,2)
x(1,1) = 0.2
x(2,4) = 0.3

Een array-element is een scalair.

Array-secties

Een arraysectie is een verwijzing naar een aantal elementen (misschien slechts één) van een hele array, met behulp van een syntaxis met dubbele punten:

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)

Het laatste formulier hierboven gebruikt een vector subscript . Dit is onderhevig aan een aantal beperkingen naast andere arraysecties.

Elke arraysectie is zelf een array, zelfs wanneer slechts naar één element wordt verwezen. Dat wil zeggen x(1:1,1) is een array van rang 1 en x(1:1,1:1) is een array van rang 2.

Arraysecties hebben over het algemeen geen kenmerk van de hele array. In het bijzonder waar

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

de opdracht

x(:) = [1,2,3,4,5]   ! This is bad when x isn't the same shape as the right-hand side

is niet toegestaan: x(:) , hoewel een arraysectie met alle elementen van x geen toewijsbare array is.

x(:) = [5,6,7,8]

is prima als x de vorm van de rechterkant heeft.


Matrixcomponenten van arrays

type t
   real y(5)
end type t

type(t) x(2)

We kunnen ook verwijzen naar hele arrays, array-elementen en array-secties in meer gecompliceerde instellingen.

Uit het bovenstaande is x een hele array. We hebben ook

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 dergelijke gevallen mogen we niet meer dan één deel van de referentie hebben dat bestaat uit een array van rang 1. Het volgende is bijvoorbeeld niet toegestaan

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

Array-bewerkingen

Vanwege zijn computationele doelen zijn wiskundige bewerkingen op arrays ongecompliceerd in Fortran.

Optellen en aftrekken

Bewerkingen op arrays met dezelfde vorm en grootte lijken erg op matrixalgebra. In plaats van alle indices met lussen te doorlopen, kan men optellen (en aftrekken) schrijven:

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

Arrays van slicing zijn ook geldig:

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)

Functie

Op dezelfde manier kunnen de meeste intrinsieke functies impliciet worden gebruikt, uitgaande van componentgewijze bewerking (hoewel dit niet systematisch is):

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).

Vermenigvuldiging en deling

Voorzichtigheid is geboden bij product en verdeling: intrinsieke bewerkingen met * en / symbolen zijn elementair:

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

Dit moet niet worden verward met matrixbewerkingen (zie hieronder).

Matrixbewerkingen

Matrixbewerkingen zijn intrinsieke procedures. Het matrixproduct van de arrays uit de vorige sectie is bijvoorbeeld als volgt geschreven:

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

Complexe bewerkingen maken het mogelijk om functies in te kapselen door tijdelijke arrays te maken. Hoewel dit door sommige compilers en compilatieopties is toegestaan, wordt dit niet aanbevolen. Een product met een matrix-transponering kan bijvoorbeeld worden geschreven:

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

Geavanceerde array-secties: subscript-drieling en vector-subscripts

Zoals vermeld in een ander voorbeeld kan naar een subset van de elementen van een array worden verwezen, een arraysectie. Van dat voorbeeld kunnen we hebben

real x(10)
x(:)   = 0.
x(2:6) = 1.
x(3:4) = [3., 5.]

Matrixsecties kunnen echter algemener zijn dan dit. Ze kunnen de vorm aannemen van subscript-drietallen of vector-subscripts.

Abonnement-drieling

Een subscript triple heeft de vorm [bound1]:[bound2][:stride] . Bijvoorbeeld

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

Wanneer een stap (die niet nul mag zijn) wordt opgegeven, begint de reeks elementen met de eerste opgegeven limiet. Als de stap positief is (resp. Negatief), worden de geselecteerde elementen volgens een reeks verhoogd (resp. Verlaagd) door de pas tot het laatste element niet groter (resp. Kleiner) wordt genomen dan de tweede grens. Als de pas wordt weggelaten, wordt deze als één behandeld.

Als de eerste grens groter is dan de tweede grens en de stap positief is, worden geen elementen opgegeven. Als de eerste grens kleiner is dan de tweede grens en de stap negatief is, zijn er geen elementen opgegeven.

Opgemerkt moet worden dat x(10:1:-1) niet hetzelfde is als x(1:10:1) , hoewel elk element van x in beide gevallen voorkomt.

Vector subscripts

Een vector subscript is een rang-1 geheel getal array. Dit duidt een reeks elementen aan die overeenkomen met de waarden van de 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)

Een arraysectie met een vector subscript is beperkt in hoe het kan worden gebruikt:

  • het mag geen argument zijn dat is gekoppeld aan een dummy-argument dat in de procedure is gedefinieerd;
  • het is mogelijk niet het doel in een aanwijzingsopdracht;
  • het is mogelijk geen intern bestand in een gegevensoverdrachtverklaring.

Verder is het mogelijk dat een dergelijke arraysectie niet voorkomt in een instructie die de definitie ervan omvat wanneer hetzelfde element twee keer wordt geselecteerd. Van boven:

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

Array-secties met een hogere rang

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow