Recherche…


Notation de base

Tout type peut être déclaré en tant que tableau en utilisant soit l'attribut dimension, soit en indiquant directement la ou les dimension du tableau:

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

La dernière manière de déclarer un tableau multidimensionnel permet la déclaration de tableaux de même rang / dimensions de même type dans une seule ligne, comme suit

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

Le rang maximum (nombre de dimensions) autorisé est de 15 dans le standard Fortran 2008 et était de 7 auparavant.

Fortran stocke les tableaux dans l'ordre des colonnes . Autrement dit, les éléments de bar sont stockés dans la mémoire comme suit:

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

Dans Fortran, la numérotation des tableaux commence à 1 par défaut, contrairement à C qui commence à 0 . En fait, dans Fortran, vous pouvez spécifier explicitement les limites supérieure et inférieure de chaque dimension:

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

Cela déclare un tableau de forme (6, 3) , dont le premier élément est geese(7, -3) .

Les limites inférieures et supérieures le long des 2 dimensions (ou plus) sont accessibles par les fonctions intrinsèques ubound et lbound . En effet, lbound(geese,2) retournerait -3 , tandis que ubound(geese,1) retournerait 12 .

La taille d'un tableau est accessible par la size fonction intrinsèque. Par exemple, size(geese, dim = 1) renvoie la taille de la première dimension qui est 6.

Tableaux pouvant être alloués

Les tableaux peuvent avoir l'attribut allocatable :

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

Cela déclare la variable mais ne lui alloue aucun espace.

! 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

Une fois qu'une variable n'est plus nécessaire, elle peut être libérée :

deallocate(foo)

Si, pour une raison quelconque, une instruction d' allocate échoue, le programme s'arrêtera. Cela peut être évité si le statut est vérifié via le mot-clé 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

L'instruction deallocate a également le mot clé stat :

deallocate (geese, stat=status)

status est une variable entière dont la valeur est 0 si l'allocation ou la désallocation a réussi.

Constructeurs de tableaux

Une valeur de tableau rank-1 peut être créée en utilisant un constructeur de tableau , avec la syntaxe

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

La forme [...] été introduite dans Fortran 2003 et est généralement considérée comme plus lisible, en particulier dans les expressions complexes. Ce formulaire est utilisé exclusivement dans cet exemple.

Les valeurs figurant dans un constructeur de tableaux peuvent être des valeurs scalaires, des valeurs de tableau ou des boucles implicites.

Les paramètres type et type du tableau construit correspondent à ceux des valeurs du constructeur de tableau

[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

Dans les formulaires ci-dessus, toutes les valeurs données doivent être du même type et du même type. Les types de mélange ou les paramètres de type ne sont pas autorisés. Les exemples suivants ne sont pas valides

[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

Pour construire un tableau utilisant différents types, une spécification de type pour le tableau doit être donnée

[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

Cette dernière forme pour les tableaux de caractères est particulièrement pratique pour éviter le remplissage d'espace, comme l'alternative

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

La taille d'un tableau nommé constante peut être impliquée par le constructeur de tableaux utilisé pour définir sa valeur

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

et pour les types paramétrés en longueur, le paramètre de longueur peut être supposé

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

La spécification de type est également requise dans la construction de tableaux de longueur nulle. De

[ ] ! Not a valid array constructor

les paramètres de type et de type ne peuvent pas être déterminés à partir du jeu de valeurs non existant. Pour créer un tableau d'entiers par défaut de longueur nulle:

[integer :: ]

Les constructeurs de tableaux ne construisent que des tableaux de rang 1. Parfois, par exemple pour définir la valeur d'une constante nommée, des tableaux de rang supérieur sont également requis dans une expression. Les tableaux de rang supérieur peuvent être pris à partir du résultat de reshape avec un tableau de rang 1 construit

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

Dans un constructeur de tableaux, les valeurs du tableau dans l'ordre des éléments avec les tableaux de la liste de valeurs sont comme si les éléments individuels étaient eux-mêmes attribués dans l'ordre des éléments du tableau. Ainsi, l'exemple précédent

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

est équivalent à

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

En général, les valeurs du constructeur peuvent être des expressions arbitraires, y compris des constructeurs de tableaux imbriqués. Pour qu'un tel constructeur de tableau remplisse certaines conditions, comme être une expression de constante ou de spécification, des restrictions s'appliquent aux valeurs constitutives.


Bien que ce ne soit pas un constructeur de tableau, certaines valeurs de tableau peuvent également être créées de manière pratique en utilisant la fonction intrinsèque de spread . Par exemple

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

est aussi le résultat de la référence de la fonction

SPREAD(0, 1, 10)

Spécification de la nature du tableau: rang et forme

L'attribut de dimension sur un objet spécifie que cet objet est un tableau. Il y a, dans Fortran 2008, cinq natures de tableau: 1

  • forme explicite
  • forme supposée
  • taille supposée
  • forme différée
  • forme implicite

Prenez les trois rangées 1

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

Avec ceux-ci, on peut voir qu'un contexte supplémentaire est nécessaire pour déterminer entièrement la nature d'un tableau.

Forme explicite

Un tableau de forme explicite est toujours la forme de sa déclaration. À moins que le tableau ne soit déclaré comme local à un sous-programme ou à une construction de block , les limites définissant la forme doivent être des expressions constantes. Dans d'autres cas, un tableau de forme explicite peut être un objet automatique, en utilisant des extensions qui peuvent varier à chaque appel d'un sous-programme ou d'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

Forme supposée

Un tableau de forme supposé est un argument factice sans l' allocatable ou pointer . Un tel tableau prend sa forme à partir de l'argument réel auquel il est associé.

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

Lorsqu'un argument factice suppose que la portée faisant référence à la procédure doit avoir une interface explicite disponible pour cette procédure.

Taille supposée

Un tableau de taille supposé est un argument factice dont la taille est prise en compte dans son argument réel.

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

Les tableaux de taille supposés se comportent très différemment des tableaux de formes supposés et ces différences sont documentées ailleurs.

Forme différée

Un tableau de forme différé est un tableau qui possède l' allocatable ou le pointer . La forme d'un tel tableau est déterminée par son affectation ou son affectation de pointeur.

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

Forme implicite

Un tableau de forme implicite est une constante nommée qui prend sa forme à partir de l'expression utilisée pour établir sa valeur

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

Les implications de ces déclarations de tableaux sur les arguments factices doivent être documentées ailleurs.


1 Une spécification technique étendant Fortran 2008 ajoute une sixième nature de tableau: rang supposé. Ceci n'est pas couvert ici.

2 Celles-ci peuvent être écrites de manière équivalente

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

ou

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

Tableaux entiers, éléments de tableau et sections de tableau

Considérons le tableau déclaré comme

real x(10)

Ensuite, nous avons trois aspects d'intérêt:

  1. Le tableau entier x ;
  2. Éléments de tableau, comme x(1) ;
  3. Sections de tableau, comme x(2:6) .

Tableaux entiers

Dans la plupart des cas, le tableau entier x désigne tous les éléments du tableau en tant qu’entité unique. Il peut apparaître dans des instructions exécutables telles que print *, SUM(x) , print *, SIZE(x) ou x=1 .

Un tableau entier peut faire référence à des tableaux qui ne sont pas explicitement formés (comme x ci-dessus):

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

Un tableau de taille supposée peut également apparaître sous la forme d'un tableau complet, mais uniquement dans des circonstances limitées (à documenter ailleurs).

Éléments de tableau

On appelle un élément tableau des index entiers, un pour chaque rang du tableau, indiquant l’emplacement dans l’ensemble du tableau:

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

Un élément de tableau est un scalaire.

Sections de tableau

Une section de tableau est une référence à un certain nombre d'éléments (peut-être un seul) d'un tableau entier, en utilisant une syntaxe impliquant les deux points:

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)

La forme finale ci-dessus utilise un indice vectoriel . Ceci est soumis à un certain nombre de restrictions au-delà des autres sections de la baie.

Chaque section de tableau est elle-même un tableau, même lorsqu'un seul élément est référencé. C'est-à-dire que x(1:1,1) est un tableau de rang 1 et que x(1:1,1:1) est un tableau de rang 2.

Les sections de tableau n'ont généralement pas d'attribut de l'ensemble du tableau. En particulier, où

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

la tâche

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

n'est pas autorisé: x(:) , bien qu'une section de tableau avec tous les éléments de x , ne soit pas un tableau pouvant être alloué.

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

c'est bien quand x la forme du côté droit.


Composants de tableaux de tableaux

type t
   real y(5)
end type t

type(t) x(2)

Nous pouvons également faire référence à des tableaux entiers, à des éléments de tableau et à des sections de tableau dans des paramètres plus complexes.

De ce qui précède, x est un tableau entier. Nous avons aussi

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

Dans de tels cas, nous ne sommes pas autorisés à avoir plus d'une partie de la référence constituée d'un tableau de rang 1. Les éléments suivants, par exemple, ne sont pas autorisés

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

Opérations de tableau

En raison de ses objectifs de calcul, les opérations mathématiques sur les tableaux sont simples dans Fortran.

Addition et soustraction

Les opérations sur des tableaux de même forme et de même taille sont très similaires à l'algèbre matricielle. Au lieu de parcourir tous les indices avec des boucles, on peut écrire l'addition (et la soustraction):

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

Les tableaux de découpage sont également valides:

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)

Fonction

De la même manière, la plupart des fonctions intrinsèques peuvent être implicitement utilisées en supposant un fonctionnement par composants (bien que cela ne soit pas systématique):

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

Multiplication et division

Des précautions doivent être prises avec le produit et la division: les opérations intrinsèques utilisant des symboles * et / sont des éléments:

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

Cela ne doit pas être confondu avec les opérations matricielles (voir ci-dessous).

Opérations matricielles

Les opérations matricielles sont des procédures intrinsèques. Par exemple, le produit matriciel des tableaux de la section précédente est écrit comme suit:

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

Les opérations complexes permettent d'encapsuler les fonctions en créant des tableaux temporaires. Bien que autorisé par certains compilateurs et options de compilation, ceci n'est pas recommandé. Par exemple, un produit comprenant une transposition de matrice peut être écrit:

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

Sections de tableau avancées: triplets en indice et indices de vecteur

Comme mentionné dans un autre exemple, un sous-ensemble des éléments d'un tableau, appelé section de tableau, peut être référencé. De cet exemple, nous pouvons avoir

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

Les sections de tableau peuvent être plus générales que cela, cependant. Ils peuvent prendre la forme de triplets d'indice ou d'indices vectoriels.

Triplets d'indices

Un indice triple prend la forme [bound1]:[bound2][:stride] . Par exemple

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

Lorsqu'un stride (qui ne doit pas être zéro) est spécifié, la séquence d'éléments commence par la première limite spécifiée. Si la foulée est positive (resp. Négative), les éléments sélectionnés suivant une séquence incrémentée (resp. Décrémentée) par la foulée jusqu'à ce que le dernier élément non plus grand (resp. Plus petit) que la seconde soit pris. Si la foulée est omise, elle est considérée comme une seule.

Si la première limite est supérieure à la deuxième limite et que la foulée est positive, aucun élément n'est spécifié. Si la première limite est inférieure à la deuxième limite et que la foulée est négative, aucun élément n'est spécifié.

Il convient de noter que x(10:1:-1) est différent de x(1:10:1) même si chaque élément de x apparaît dans les deux cas.

Indices de vecteur

Un indice vectoriel est un tableau entier de rang 1. Cela désigne une séquence d'éléments correspondant aux valeurs du tableau.

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)

Une section de tableau avec un indice vectoriel est restreinte dans la façon dont elle peut être utilisée:

  • il peut ne pas s'agir d'un argument associé à un argument factice défini dans la procédure;
  • il peut ne pas être la cible dans une déclaration d'affectation de pointeur;
  • il ne s'agit peut-être pas d'un fichier interne dans une déclaration de transfert de données.

De plus, une telle section de tableau peut ne pas apparaître dans une instruction qui implique sa définition lorsque le même élément est sélectionné deux fois. D'en haut:

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

Sections de tableau de rang supérieur

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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow