Fortran
arrayer
Sök…
Grundläggande notation
Vilken typ som helst kan deklareras som en matris med antingen dimensionattributet eller genom att bara ange dimension
(er) för matrisen:
! 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)
Det senare sättet att deklarera multidimensionell matris, tillåter deklarering av olika typer av olika rang / dimensioner i en rad, enligt följande
real :: pencil(5), plate(3,-2:4), cuboid(0:3,-10:5,6)
Den högsta tillåtna rankningen (antalet dimensioner) är 15 i Fortran 2008-standarden och var 7 tidigare.
Fortran lagrar matriser i kolumn- huvudordning. Det vill säga elementen i bar
lagras i minnet enligt följande:
bar(1, 1), bar(2, 1), bar(3, 1), bar(4, 1), bar(1, 2), bar(2, 2), ...
I Fortran startar matrisnumreringen vid 1 som standard, i motsats till C som börjar vid 0 . I Fortran kan du faktiskt ange de övre och nedre gränserna för varje dimension uttryckligen:
integer, dimension(7:12, -3:-1) :: geese
Detta förklarar en matrisform (6, 3)
, vars första element är geese(7, -3)
.
Nedre och övre gränser längs de 2 (eller fler) dimensionerna kan nås av de inneboende funktionerna ubound
och lbound
. I lbound(geese,2)
verket skulle lbound(geese,2)
återvända -3
, medan ubound(geese,1)
skulle återvända 12
.
Storleken av en array kan nås genom inneboende funktion size
. Till exempel ger size(geese, dim = 1)
storleken på den första dimensionen som är 6.
Tilldelbara matriser
Matriser kan ha det allokerbara attributet:
! One dimensional allocatable array
integer, dimension(:), allocatable :: foo
! Two dimensional allocatable array
real, dimension(:,:), allocatable :: bar
Detta deklarerar variabeln men tilldelar inte utrymme för den.
! 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
När inte längre behövs en variabel, kan det avallokeras:
deallocate(foo)
Om du av någon anledning en allocate
uttalande misslyckas, kommer programmet att sluta. Detta kan förhindras om status kontrolleras via stat
nyckelordet:
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
deallocate
uttalandet har också nyckelord för stat
:
deallocate (geese, stat=status)
status
är en heltalvariabel vars värde är 0 om allokeringen eller omfördelningen var framgångsrik.
Arraykonstruktörer
Ett rank-1-arrayvärde kan skapas med hjälp av en array-konstruktör med syntaxen
(/ ... /)
[ ... ]
Formen [...]
introducerades i Fortran 2003 och betraktas generellt som tydligare att läsa, särskilt i komplexa uttryck. Denna form används exklusivt i detta exempel.
Värdena som finns i en matriskonstruktör kan vara skalvärden, matrisvärden eller implicit-loopar.
Typen och typparametrarna för den konstruerade arrayen matchar värdena i arraykonstruktören
[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
I formulärerna ovan måste alla angivna värden vara av samma typ och typparameter. Blandningstyper eller typparametrar är inte tillåtet. Följande exempel är inte giltiga
[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
För att konstruera en matris med olika typer ska en typspecifikation för matrisen ges
[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
Den senare formen för karaktärsuppsättningar är särskilt bekväm att undvika rymdstoppning, såsom alternativet
["Hello ", "Frederick"] ! A length-2 array of length-9 characters
Storleken på en matris med namnet konstant kan antydas av den arraykonstruktör som används för att ställa in dess värde
integer, parameter :: ids(*) = [1, 2, 3, 4]
och för längdparametrerade typer kan längdparametern antas
character(len=*), parameter :: names(*) = [character(3) :: "Me", "You", "Her"]
Typspecifikationen krävs också vid konstruktion av noll-längd arrayer. Från
[ ] ! Not a valid array constructor
parametrarna för typ och typ kan inte bestämmas utifrån den icke-existerande värdesättningen. Så här skapar du en heltalsfärg med noll längd:
[integer :: ]
Arraykonstruktörer konstruerar endast rang-1-matriser. Ibland, såsom att ställa in värdet på en namngiven konstant, krävs också högre rangordning i ett uttryck. Matriser med högre rang kan tas från resultatet av reshape
med en konstruerad rang-1-array
integer, parameter :: multi_rank_ids(2,2) = RESHAPE([1,2,3,4], shape=[2,2])
I en arraykonstruktör är värdena på matrisen i elementordning med alla arrayer i värdelistan som om de enskilda elemeterna gavs sig i matriselementordning. Således, det tidigare exemplet
integer, parameter :: A = [2, 4]
[1, A, 3] ! A rank-1 length-4 array of default integer type, with A's elements
är ekvivalent med
[1, 2, 4, 3] ! With the array written out in array element order
Generellt kan värdena i konstruktören vara godtyckliga uttryck, inklusive kapslade arraykonstruktörer. För att en sådan matriskonstruktör uppfyller vissa villkor, såsom att vara ett konstant eller specifikationsuttryck, gäller begränsningar för beståndsdelar.
Även om det inte är en arraykonstruktör, kan vissa matrisvärden också bekvämt skapas med användning av den inre funktionen spread
. Till exempel
[(0, i=1,10)] ! An array with 10 default integers each of value 0
är också resultatet av funktionsreferensen
SPREAD(0, 1, 10)
Specifikationer för array: rang och form
dimension
på ett objekt anger att det objektet är en matris. I Fortran 2008 finns det fem matriser: 1
- uttrycklig form
- antagen form
- antagen storlek
- uppskjuten form
- underförstådd form
Ta de tre rank-1 matriserna 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
Med dessa kan man se att ytterligare sammanhang krävs för att fullständigt bestämma arrayens art.
Explicit form
En tydlig formuppsättning är alltid formen på dess deklaration. Om inte matrisen förklaras som lokal för ett underprogram eller block
, måste gränserna som definierar formen vara konstant uttryck. I andra fall kan en uttrycklig formuppsättning vara ett automatiskt objekt med hjälp av utsträckningar som kan variera vid varje anrop av ett delprogram eller 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
Antagen form
En antagen formuppsättning är ett dummy-argument utan allocatable
eller pointer
. En sådan matris tar sin form från det faktiska argumentet som det är förknippat med.
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
När ett dummy-argument har antagit formen, ska proceduren som refererar till ha ett tydligt gränssnitt tillgängligt för den proceduren.
Antagad storlek
En antagen storleksgrupp är ett dummy-argument som har sin storlek antas från dess faktiska argument.
subroutine sub(x)
integer x(*) ! Assumed size array
end subroutine
Antagna storleksuppsättningar uppför sig mycket annorlunda än antagna formuppsättningar och dessa skillnader är dokumenterade någon annanstans.
Uppskjuten form
En uppskjuten form array är en matris som har den allocatable
eller pointer
attribut. Formen på en sådan matris bestäms av dess allokering eller pekartilldelning.
integer, allocatable :: a(:)
integer, pointer :: b(:)
Implicerad form
En implicit formuppsättning är en benämnd konstant som tar sin form från uttrycket som används för att fastställa dess värde
integer, parameter :: a(*) = [1,2,3,4]
Konsekvenserna av dessa arrayförklaringar på dummy-argumenter ska dokumenteras någon annanstans.
1 En teknisk specifikation som utvidgar Fortran 2008 lägger till en sjätte array-karaktär: antagen rang. Detta omfattas inte här.
2 Dessa kan på samma sätt skrivas som
integer, dimension(5) :: a
integer, dimension(:) :: b
integer, dimension(*) :: c
eller
integer a(5)
integer b(:)
integer c(*)
Hela matriser, arrayelement och arrayavsnitt
Betrakta den matris som förklaras som
real x(10)
Sedan har vi tre aspekter av intresse:
- Hela matrisen
x
; - Arrayelement, som
x(1)
; - Arrayavsnitt, som
x(2:6)
.
Hela matriser
I de flesta fall avser hela matrisen x
alla elementen i matrisen som en enda enhet. Det kan visas i körbara uttalanden som print *, SUM(x)
, print *, SIZE(x)
eller x=1
.
En hel matris kan hänvisa till arrayer som inte är uttryckligen formade (till exempel x
ovan):
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
En antagen storleksanordning kan också visas som en hel matris, men endast i begränsade omständigheter (för att dokumenteras någon annanstans).
Arrayelement
Ett arrayelement hänvisas till att ge heltalindex, ett för varje rangordning i arrayen, som anger platsen i hela arrayen:
real x(5,2)
x(1,1) = 0.2
x(2,4) = 0.3
Ett arrayelement är en skalär.
Arrayavsnitt
En matrisavsnitt är en hänvisning till ett antal element (kanske bara ett) i en hel matris med en syntax som involverar kolon:
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)
Den sista formen ovan använder ett vektornivå . Detta är föremål för ett antal begränsningar utöver andra matrisavsnitt.
Varje matrisavsnitt är i sig själv en matris, även när det bara refereras till ett element. Det vill x(1:1,1)
är en matris av rang 1 och x(1:1,1:1)
är en matris med rang 2.
Arrayavsnitt har i allmänhet inte ett attribut för hela matrisen. I synnerhet var
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
uppgiften
x(:) = [1,2,3,4,5] ! This is bad when x isn't the same shape as the right-hand side
är inte tillåtet: x(:)
, även om en matrisdel med alla element i x
, inte är en allokerbar matris.
x(:) = [5,6,7,8]
är bra när x
har formen på höger sida.
Arraykomponenter i matriser
type t
real y(5)
end type t
type(t) x(2)
Vi kan också hänvisa till hela matriser, arrayelement och arrayavsnitt i mer komplicerade inställningar.
Från ovanstående är x
en hel matris. Vi har också
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
I sådana fall får vi inte ha mer än en del av referensen som består av en grupp av rang 1. Följande till exempel är inte tillåtna
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-operationer
På grund av dess beräkningsmål är matematiska operationer på matriser rakt fram i Fortran.
Addition och subtraktion
Funktioner på matriser av samma form och storlek liknar mycket matrisalgebra. I stället för att gå igenom alla index med slingor kan man skriva tillägg (och subtraktion):
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
Matriser från skivning är också giltiga:
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)
Fungera
På samma sätt kan de flesta inneboende funktioner användas implicit under antagande av komponentvis funktion (även om detta inte är systematiskt):
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).
Multiplikation och uppdelning
Man måste vara försiktig med produkt och division: inneboende funktioner med *
och /
symboler är elementmässigt:
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
Detta får inte misstas med matrisoperationer (se nedan).
Matrisoperationer
Matrisoperationer är inneboende procedurer. Till exempel är matrisprodukten för matriserna i föregående avsnitt skrivet enligt följande:
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
Komplexa funktioner tillåter inkapslade funktioner genom att skapa tillfälliga matriser. Medan vissa kompilatorer och kompileringsalternativ tillåts rekommenderas detta inte. En produkt som inkluderar en matristranspon kan till exempel skrivas:
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
Avancerade matrisavsnitt: prenumerationstripletter och vektorabonnemang
Som nämnts i ett annat exempel kan det hänvisas till en delmängd av elementen i en matris, kallad en matrisdel. Från det exemplet vi kan ha
real x(10)
x(:) = 0.
x(2:6) = 1.
x(3:4) = [3., 5.]
Arrayavsnitt kan dock vara mer generella än detta. De kan ha formen av prenumerationstripletter eller vektorabonnemang.
Prenumerations tripletter
En prenumerationstrippel har formen [bound1]:[bound2][:stride]
. Till exempel
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
När en steg (som inte får vara noll) anges börjar sekvensen med element med den första angivna gränsen. Om steget är positivt (resp. Negativt) tas de valda elementen efter en sekvens ökad (resp. Dekrementerad) av steget tills det sista elementet som inte är större (resp. Mindre) än den andra gränsen tas. Om steget utelämnas behandlas det som ett.
Om den första gränsen är större än den andra gränsen, och steget är positivt, anges inga element. Om den första gränsen är mindre än den andra gränsen, och steget är negativt, anges inga element.
Det bör noteras att x(10:1:-1)
inte är samma som x(1:10:1)
även om varje element i x
visas i båda fallen.
Vectorabonnemang
Ett vektornivå är en rangordning med ett heltal. Detta anger en sekvens av element som motsvarar värdena i matrisen.
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)
Ett matrisavsnitt med ett vektornivå är begränsat i hur det kan användas:
- det kan inte vara ett argument som är associerat med ett dummy-argument som definieras i proceduren;
- det kanske inte är målet i ett uttalande om tilldelning av pekare;
- det kanske inte är en intern fil i ett dataöverföringsuttalande.
Vidare kan en sådan matrisdel inte visas i ett uttalande som innebär dess definition när samma element väljs två gånger. Från ovan:
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
Sektioner med högre rangordning
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)