Suche…
Grundnotation
Jeder Typ kann als Array deklariert werden, indem entweder das Dimensionsattribut verwendet wird oder die dimension
(en) des Arrays direkt angegeben werden:
! 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)
Die letztere Art der Deklaration eines mehrdimensionalen Arrays ermöglicht die Deklaration von Arrays mit unterschiedlichem Rang und unterschiedlichen Dimensionen in einer Zeile
real :: pencil(5), plate(3,-2:4), cuboid(0:3,-10:5,6)
Der maximale Rang (Anzahl der Dimensionen) ist in Fortran 2008 Standard 15 und war zuvor 7.
Fortran speichert Arrays in der Reihenfolge der Kolonnen . Das heißt, die Elemente des bar
werden wie folgt im Speicher gespeichert:
bar(1, 1), bar(2, 1), bar(3, 1), bar(4, 1), bar(1, 2), bar(2, 2), ...
In Fortran beginnt die Array-Nummerierung standardmäßig mit 1 , im Gegensatz zu C, das mit 0 beginnt. In Fortran können Sie die Ober- und Untergrenze für jede Dimension explizit angeben:
integer, dimension(7:12, -3:-1) :: geese
Dies deklariert ein Array von Shape (6, 3)
, dessen erstes Element geese(7, -3)
.
Auf die unteren und oberen Grenzen der 2 (oder mehr) Dimensionen kann durch die intrinsischen Funktionen ubound
und lbound
. In der Tat würden lbound(geese,2)
-3
, wohingegen ubound(geese,1)
12
zurückkehren würde.
Größe eines Arrays kann durch intrinsische Funktion zugegriffen werden size
. Zum Beispiel gibt size(geese, dim = 1)
die Größe der ersten Dimension zurück, die 6 ist.
Zuordenbare Arrays
Arrays können das zuweisbare Attribut haben:
! One dimensional allocatable array
integer, dimension(:), allocatable :: foo
! Two dimensional allocatable array
real, dimension(:,:), allocatable :: bar
Dies deklariert die Variable, reserviert jedoch keinen Platz für sie.
! 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
Sobald eine Variable nicht mehr benötigt wird, kann sie freigegeben werden :
deallocate(foo)
Wenn eine allocate
aus irgendeinem Grund fehlschlägt, wird das Programm angehalten. Dies kann verhindert werden, wenn der Status über das Schlüsselwort stat
überprüft wird:
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
Die deallocate
Anweisung hat auch ein stat
Schlüsselwort:
deallocate (geese, stat=status)
status
ist eine Ganzzahlvariable, deren Wert 0 ist, wenn die Zuweisung oder Freigabe erfolgreich war.
Array-Konstruktoren
Ein Array-Wert mit Rang 1 kann mithilfe eines Array-Konstruktors mit der Syntax erstellt werden
(/ ... /)
[ ... ]
Die Form wurde [...]
2003 in Fortran eingeführt und wird allgemein als lesbarer angesehen, insbesondere in komplexen Ausdrücken. Dieses Formular wird ausschließlich in diesem Beispiel verwendet.
Die in einem Array-Konstruktor enthaltenen Werte können skalare Werte, Array-Werte oder implied-do-Schleifen sein.
Die Parameter type und type des erstellten Arrays stimmen mit denen der Werte im Array-Konstruktor überein
[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 den obigen Formularen müssen alle angegebenen Werte denselben Typ und denselben Typparameter haben. Das Mischen von Typen oder Typparametern ist nicht zulässig. Die folgenden Beispiele sind nicht gültig
[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
Um ein Array mit verschiedenen Typen zu erstellen, wird eine Typspezifikation für das Array angegeben
[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
Diese letztere Form für Zeichenarrays ist besonders praktisch, um Leerzeichen wie die Alternative zu vermeiden
["Hello ", "Frederick"] ! A length-2 array of length-9 characters
Die Größe eines Arrays mit dem Namen konstant kann vom Array-Konstruktor impliziert werden, der zum Festlegen seines Werts verwendet wird
integer, parameter :: ids(*) = [1, 2, 3, 4]
und für längenparametrierte Typen kann der Längenparameter angenommen werden
character(len=*), parameter :: names(*) = [character(3) :: "Me", "You", "Her"]
Die Typspezifikation ist auch bei der Konstruktion von Arrays mit Nulllänge erforderlich. Von
[ ] ! Not a valid array constructor
Die Parameter type und type können nicht aus dem nicht vorhandenen Wertesatz ermittelt werden. So erstellen Sie ein Standard-Ganzzahl-Array mit Länge Null:
[integer :: ]
Array-Konstruktoren konstruieren nur Rang-1-Arrays. Manchmal, beispielsweise beim Festlegen des Wertes einer benannten Konstante, sind auch Arrays mit höherem Rang in einem Ausdruck erforderlich. Arrays mit höherem Rang können dem Ergebnis der reshape
mit einem konstruierten Rang-1-Array entnommen werden
integer, parameter :: multi_rank_ids(2,2) = RESHAPE([1,2,3,4], shape=[2,2])
In einem Arraykonstruktor sind die Werte des Arrays in der Elementreihenfolge, wobei alle Arrays in der Werteliste so aussehen, als würden die einzelnen Elemente in der Arrayelementreihenfolge angegeben. So das vorige Beispiel
integer, parameter :: A = [2, 4]
[1, A, 3] ! A rank-1 length-4 array of default integer type, with A's elements
ist äquivalent zu
[1, 2, 4, 3] ! With the array written out in array element order
Im Allgemeinen können die Werte im Konstruktor beliebige Ausdrücke sein, einschließlich geschachtelter Array-Konstruktoren. Damit ein solcher Array-Konstruktor bestimmte Bedingungen erfüllt, z. B. einen Konstanten- oder Spezifikationsausdruck, gelten Einschränkungen für konstituierende Werte.
Obwohl es sich nicht um einen Array-Konstruktor handelt, können bestimmte Array-Werte auch bequem mit der spread
Intrinsic-Funktion erstellt werden. Zum Beispiel
[(0, i=1,10)] ! An array with 10 default integers each of value 0
ist auch das Ergebnis der Funktionsreferenz
SPREAD(0, 1, 10)
Spezifikation der Feldnatur: Rang und Form
Das dimension
für ein Objekt gibt an, dass dieses Objekt ein Array ist. In Fortran 2008 gibt es fünf Arten von Feldern: 1
- explizite Form
- angenommene Form
- angenommene Größe
- zurückgestellte Form
- implizierte Form
Nehmen Sie die drei 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
Mit diesen ist ersichtlich, dass ein weiterer Kontext erforderlich ist, um die Art eines Arrays vollständig zu bestimmen.
Explizite Form
Ein explizites Formarray ist immer die Form seiner Deklaration. Wenn das Array nicht als lokal für ein Unterprogramm oder ein block
deklariert ist, müssen die die Form definierenden Grenzen konstante Ausdrücke sein. In anderen Fällen kann ein explizites Formarray ein automatisches Objekt sein, das Erweiterungen verwendet, die bei jedem Aufruf eines Unterprogramms oder block
variieren können.
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
Angenommene Form
Ein angenommenes Shape-Array ist ein Dummy-Argument ohne das Attribut allocatable
oder pointer
. Ein solches Array nimmt seine Form von dem tatsächlichen Argument an, mit dem es verbunden ist.
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
Wenn ein Dummy-Argument die Form angenommen hat, muss der Gültigkeitsbereich, auf den die Prozedur verweist, über eine explizite Schnittstelle für diese Prozedur verfügen.
Angenommene Größe
Ein angenommenes Größenarray ist ein Dummy-Argument, dessen Größe von seinem tatsächlichen Argument angenommen wird.
subroutine sub(x)
integer x(*) ! Assumed size array
end subroutine
Angenommene Größenfelder verhalten sich sehr unterschiedlich von angenommenen Formfeldern, und diese Unterschiede werden an anderer Stelle dokumentiert.
Verschobene Form
Ein Array mit verzögerter Form ist ein Array mit dem Attribut " allocatable
oder " pointer
. Die Form eines solchen Arrays wird durch seine Zuordnung oder Zeigerzuordnung bestimmt.
integer, allocatable :: a(:)
integer, pointer :: b(:)
Angedeutete Form
Ein impliziertes Form-Array ist eine benannte Konstante, die ihre Form von dem Ausdruck nimmt, mit dem der Wert festgelegt wird
integer, parameter :: a(*) = [1,2,3,4]
Die Auswirkungen dieser Array-Deklarationen auf Dummy-Argumente sind an anderer Stelle zu dokumentieren.
1 Eine technische Spezifikation, die Fortran 2008 erweitert, fügt einen sechsten Array-Charakter hinzu: angenommener Rang. Dies wird hier nicht behandelt.
2 Diese können äquivalent als geschrieben werden
integer, dimension(5) :: a
integer, dimension(:) :: b
integer, dimension(*) :: c
oder
integer a(5)
integer b(:)
integer c(*)
Ganze Arrays, Array-Elemente und Array-Abschnitte
Betrachten Sie das als deklarierte Array
real x(10)
Dann haben wir drei Aspekte von Interesse:
- Das gesamte Array
x
; - Array-Elemente wie
x(1)
; - Array-Abschnitte wie
x(2:6)
.
Ganze Arrays
In den meisten Fällen bezieht sich das gesamte Array x
auf alle Elemente des Arrays als eine einzige Entität. Es kann in ausführbaren Anweisungen wie print *, SUM(x)
, print *, SIZE(x)
oder x=1
.
Ein ganzes Array kann auf Arrays verweisen, die nicht explizit geformt sind (wie z. B. x
oben):
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
Ein Array mit angenommener Größe kann auch als gesamtes Array angezeigt werden, jedoch nur unter bestimmten Umständen (an anderer Stelle zu dokumentieren).
Array-Elemente
Ein Array-Element wird als Integer-Index bezeichnet, einer für jeden Rang des Arrays, der die Position im gesamten Array angibt:
real x(5,2)
x(1,1) = 0.2
x(2,4) = 0.3
Ein Array-Element ist ein Skalar.
Array-Abschnitte
Ein Array-Abschnitt ist eine Referenz auf eine Reihe von Elementen (vielleicht nur eines) eines ganzen Arrays, wobei eine Syntax verwendet wird, die Doppelpunkte enthält:
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)
Das letzte Formular oben verwendet einen Vektor-Index . Dies unterliegt einer Reihe von Einschränkungen, die über andere Array-Abschnitte hinausgehen.
Jeder Arrayabschnitt ist selbst ein Array, selbst wenn nur ein Element referenziert wird. Das heißt, x(1:1,1)
ist ein Array von Rang 1 und x(1:1,1:1)
ist ein Array von Rang 2.
Array-Abschnitte haben im Allgemeinen kein Attribut des gesamten Arrays. Insbesondere wo
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
die Zuordnung
x(:) = [1,2,3,4,5] ! This is bad when x isn't the same shape as the right-hand side
ist nicht erlaubt: x(:)
, obwohl ein Arrayabschnitt mit allen Elementen von x
kein zuweisbares Array ist.
x(:) = [5,6,7,8]
ist in Ordnung, wenn x
die Form der rechten Seite hat.
Array-Komponenten von Arrays
type t
real y(5)
end type t
type(t) x(2)
In komplizierteren Einstellungen können wir uns auch auf ganze Arrays, Array-Elemente und Array-Abschnitte beziehen.
Aus dem obigen ist x
ein ganzes Array. Wir haben auch
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 solchen Fällen dürfen wir nicht mehr als einen Teil der Referenz haben, der aus einem Array mit Rang 1 besteht. Die folgenden sind beispielsweise nicht zulässig
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-Operationen
Aufgrund ihrer Berechnungsziele sind mathematische Operationen in Arrays in Fortran unkompliziert.
Addition und Subtraktion
Operationen an Arrays derselben Form und Größe sind der Matrixalgebra sehr ähnlich. Anstatt alle Indizes mit Schleifen zu durchlaufen, können Sie die Addition (und die Subtraktion) schreiben:
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 von Slicing sind auch gültig:
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)
Funktion
Auf die gleiche Weise können die meisten intrinsischen Funktionen implizit verwendet werden, wenn eine komponentenweise Operation (jedoch nicht systematisch) vorausgesetzt wird:
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 und Division
Bei Produkt und Division ist Vorsicht geboten: intrinsische Operationen mit den Symbolen *
und /
sind elementweise:
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
Dies darf nicht mit Matrixoperationen verwechselt werden (siehe unten).
Matrixoperationen
Matrixoperationen sind intrinsische Prozeduren. Das Matrixprodukt der Arrays des vorherigen Abschnitts wird beispielsweise wie folgt geschrieben:
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
Komplexe Operationen ermöglichen das Einkapseln von Funktionen durch Erstellen temporärer Arrays. Dies wird zwar von einigen Compilern und Kompilierungsoptionen zugelassen, dies wird jedoch nicht empfohlen. Zum Beispiel kann ein Produkt mit einer Matrix-Transponierung geschrieben werden:
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
Erweiterte Array-Abschnitte: Index-Triplets und Vektor-Subskripte
Wie in einem anderen Beispiel erwähnt, kann auf eine Teilmenge der Elemente eines Arrays Bezug genommen werden, die als Arrayabschnitt bezeichnet wird. Von diesem Beispiel können wir haben
real x(10)
x(:) = 0.
x(2:6) = 1.
x(3:4) = [3., 5.]
Array-Abschnitte können jedoch allgemeiner sein. Sie können die Form von Index-Triplets oder Vektor-Subskripten annehmen.
Subskriptionen
Ein Index-Tripel hat die Form [bound1]:[bound2][:stride]
. Zum Beispiel
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
Wenn ein Schritt (der nicht Null sein darf) angegeben wird, beginnt die Folge der Elemente mit der ersten angegebenen Bindung. Wenn der Schritt positiv (bzw. negativ) ist, werden die ausgewählten Elemente in einer Folge um den Schritt erhöht (bzw. dekrementiert), bis das letzte Element nicht größer (bzw. kleiner) als die zweite Grenze ist. Wenn der Schritt weggelassen wird, wird er als eins behandelt.
Wenn die erste Grenze größer als die zweite Grenze ist und der Schritt positiv ist, werden keine Elemente angegeben. Wenn die erste Grenze kleiner als die zweite Grenze ist und der Schritt negativ ist, werden keine Elemente angegeben.
Es sollte beachtet werden, dass x(10:1:-1)
nicht dasselbe ist wie x(1:10:1)
, obwohl jedes Element von x
in beiden Fällen erscheint.
Vektor-Indizes
Ein Vektor-Index ist ein ganzzahliges Array mit Rang 1. Dies bezeichnet eine Folge von Elementen, die den Werten des Arrays entsprechen.
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)
Ein Array-Abschnitt mit einem Vektor-Index ist in seiner Verwendung eingeschränkt:
- es darf kein Argument sein, das mit einem Dummy-Argument verknüpft ist, das in der Prozedur definiert ist
- Es ist möglicherweise nicht das Ziel in einer Zeigerzuweisungsanweisung.
- Es kann sich nicht um eine interne Datei in einer Datenübertragungsanweisung handeln.
Außerdem erscheint ein solcher Array-Abschnitt möglicherweise nicht in einer Anweisung, die seine Definition beinhaltet, wenn dasselbe Element zweimal ausgewählt wird. Von oben:
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-Abschnitte mit höherem 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)