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:
- De hele array
x
; - Matrixelementen, zoals
x(1)
; - 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)