• Aucun résultat trouvé

Tableaux et allocation dynamique

INTEGER :: i, nb_positifs

INTEGER, DIMENSION(5) :: v = (/ i, i = -2, 2 /) REAL, DIMENSION(5) :: u, u_log

...

nb_positifs = COUNT (v > 0) ! nombre d’éléments positifs (2 ici)

IF (ALL(u > 0)) u_log = log(u) ! calculé si tous les éléments de u sont > 0

f95/2003

7.4.6 Instruction et structure FORALL

Certaines affectations de tableaux, par exemple combinant deux indices, ne peuvent pas s’ex-primer de façon globale sur le tableau, malgré leur facilité à être traitées en parallèle. Par exemple, une affectation entre tableaux de rang différent :

DO i = 1, n

tab(i, i) = v(i) ! copie du vecteur v sur la diagonale de tab END DO

peut s’exprimer à l’aide de l’instructionFORALL: FORALL (i = 1:n) tab(i, i) = v(i)

Les expressions de droite sont alors calculées en parallèle pour toutes les valeurs de l’indice, comme si les résultats intermédiaires étaient stockés dans des variables temporaires jusqu’à la fin des calculs en attendant l’affectation finale du membre de gauche. En particulier, au contraire de ce qui se passe dans une boucle classique, l’ordre de parcours des indices est indifférent ; plus précisément il peut être choisi par le processeur pour optimiser (vectoriser) le calcul. Cette construction s’avère donc très adaptée aux calculs de filtrage numérique linéaire. Par exemple, l’instruction suivante calcule bien une différence finie pour estimer une dérivée, alors qu’une boucle dans le sens croissant des indices ne donnerait pas le même résultat.

FORALL (i = 1: size(v)-1 ) v(i+1) = v(i+1) - v(i)

La structureFORALL...END FORALLpermet d’exprimer une série d’affectations successives por-tant sur les mêmes indices15.

FORALL (i=1:n, j=1:p)

a(i, j) = i + j ! tous les a(i,j) sont calculés b(i, j) = a(i, j) ** i ! avant de calculer b(i,j) END FORALL

La structureFORALL admet de plus un masque (cf. 7.4.4, p ;78) avec une condition logique per-mettant de sélectionner les indices et le corps de la structure peut contenir aussi des constructions WHERE(cf.7.3.2, p.75).

7.5 Tableaux et allocation dynamique

7.5.1 Tableaux et procédures

Bien entendu, si on travaille avec des tableaux de profil fixe (fixe au moins à l’exécution, mais dont les dimensions peuvent être des expressions constantes, grâce à l’attributPARAMETER), on peut déclarer leur profil à la fois dans le programme principal et les procédures appelées : on dit que ces tableaux sontà profil explicite. Rappelons que, dans ce cas, seul compte le profil du tableau et non ses bornes.

15. Chaque instruction est alors exécutée sur tous les indices avant de passer à la suivante.

REAL, DIMENSION(-2:2) :: tab0 REAL, DIMENSION(5) :: tab1 CALL SUB(tab0)

CALL SUB(tab1) ...

CONTAINS

SUBROUTINE SUB(tab)

REAL, DIMENSION(5) :: tab

... ! tab(1) contient tab0(-2) au premier appel ... ! tab(1) contient tab1(1) au deuxième appel END SUBROUTINE SUB

...

Mais, il est plus fréquent que des procédures nécessitent l’usage de tableaux de rang connu, mais de profil variable d’un appel à l’autre. Si, dans le programme principal, les tableaux passés en argument doivent toujours être dimensionnés avec des expressions entières constantes, il est recommandé de leur attribuer, en tant qu’arguments muets de la procédure, unprofil implicite. Pour pouvoir appeler une procédure utilisant comme argument muet des tableaux de profil implicite, la procédure appelante doit connaître l’interface de la procédure appelée ; trois possibilités sont envisageables, dont la dernière est préférable :

– utiliser une procédure interne ;

– utiliser une procédure externe avec interface explicite ; – utiliser une procédure de module (cf.6.4, p.58).

De plus, des tableaux locaux à la procédure peuvent être dimensionnés à l’aide d’expressions entières non constantes : on les nomme tableaux automatiques.

PROGRAM principal

INTEGER, PARAMETER :: lignes = 3, colonnes = 4

REAL, DIMENSION(lignes,colonnes) :: tab REAL, DIMENSION(2*colonnes,2*lignes) :: tab2 ...

CALL sub(tab) CALL sub2(tab) CALL sub(tab2) CALL sub2(tab2) ...

CONTAINS

SUBROUTINE sub(tab)

REAL, DIMENSION(:,:) :: tab ! profil implicite ...

RETURN

END SUBROUTINE sub SUBROUTINE sub2(tab)

REAL, DIMENSION(:,:) :: tab ! profil implicite

REAL, DIMENSION(SIZE(tab,1),SIZE(tab,2)) :: aux ! tableau local automatique ...

RETURN

END SUBROUTINE sub2 ...

END PROGRAM principal

7.5. TABLEAUX ET ALLOCATION DYNAMIQUE 81

7.5.2 Tableaux dynamiques

Lorsque, par exemple, le profil d’un tableau n’est connu qu’à l’exécution, on peut lui allouer dynamiquement la mémoire nécessaire. Il faut alors déclarer ce tableau en précisant son rang16 et l’attributALLOCATABLE, qui en fait un tableau àprofil différé (deffered-shape-array). Une fois le profil connu, l’instruction ALLOCATE permettra d’allouer effectivement la mémoire requise, avant toute opération d’affectation sur ce tableau. Après avoir utilisé le tableau, il est recommandé de libérer la mémoire allouée par l’instructionDEALLOCATE, en particulier si on souhaite réutiliser le même identificateur de tableau avec une autre taille.

REAL, DIMENSION(:,:), ALLOCATABLE :: tab ! rang 2, profil différé

INTEGER :: lignes, colonnes, erreur

READ (*,*) lignes, colonnes ! saisie du profil du tableau ALLOCATE(tab(lignes, colonnes), stat=erreur) ! allocation de la mémoire IF( erreur /= 0 ) THEN

WRITE(*,*) ’erreur allocation de tab ’, &

lignes, ’ lignes x ’, colonnes, ’colonnes’

STOP END IF

READ (*,*) tab(:,:) ! affectation du tableau

...

DEALLOCATE(tab) ! libération de la mémoire

Dans un souci de fiabilité des programmes, on prendra soin, avant toute opération d’alloca-tion ou de libérad’alloca-tion de mémoire, de tester l’état des tableaux grâce à la foncd’alloca-tion d’interrogad’alloca-tion ALLOCATEDqui fournit un résultat booléen.

REAL, DIMENSION(:), ALLOCATABLE :: tab ! rang 1, profil différé

INTEGER :: n, erreur

...

IF(.NOT.ALLOCATED(tab)) THEN ! si tab n’est pas déjà alloué

READ(*,*) n ! saisie de la taille

ALLOCATE(tab(n), stat=erreur) ! on l’alloue IF( erreur /= 0 ) THEN

WRITE(*,*) ’erreur allocate: mémoire insuffisante’

STOP END IF

ELSE ! si tab est déjà alloué

n = SIZE(tab) END IF

...

tab (:) = ... ! travail sur tab

...

IF(ALLOCATED(tab)) THEN ! si tab est alloué DEALLOCATE(tab, stat=erreur) ! on libère la mémoire IF( erreur /= 0 ) THEN

WRITE(*,*) ’erreur deallocate’

STOP END IF END IF

Un tableau dynamiquelocal à une procédureet alloué dans cette procédure est automatiquement libéré à la sortie de la procédure (viaENDouRETURN), sauf s’il est rendu permanent par l’attribut SAVE.

16. Mais sans indiquer sa taille.

f95/2003 Tableau dynamique en paramètre Un tableau dynamique peut aussi être passé en argu-ment d’une procédure, mais, en fortran 95, il doit être déjà alloué avant l’appel de la procédure et n’est pas considéré comme allouable dans la procédure. Ces restrictions sont levées en fortran 2003, ainsi qu’avec les extensions spécifiques de certains compilateurs fortran 9517. Le tableau doit alors posséder l’attributALLOCATABLE dans la procédure, qui peut se charger de l’allocation. S’il s’agit d’un argument de sortie (INTENT(OUT)), il est désalloué si nécessaire lors de l’appel de la procédure.

1 MODULE m_alloc_sub

2 CONTAINS

3 SUBROUTINE init_tab(tab, m, n)

4 IMPLICIT NONE

5 INTEGER, INTENT(in) :: m, n

6 INTEGER, ALLOCATABLE, INTENT(out) :: tab(:,:)

7 INTEGER :: ok

8 INTEGER :: i, j

9 IF(.NOT.ALLOCATED(tab)) THEN

10 ALLOCATE(tab(m, n), stat = ok)

11 IF (ok /= 0) THEN

21 ! ne devrait pas se produire en fortran 2003 car tab est INTENT(OUT)

22 WRITE(*, *) ’tableau déjà alloué’

23 STOP

33 WRITE (*, *) ’entrer les dimensions du tableau: m et n’

34 READ (*, *) m, n

35 ! appel du sous programme qui alloue et initialise le tableau

36 CALL init_tab(t, m, n)

42 ! deuxième appel du sous programme avec tab déjà alloué, mais

43 ! nécessitant une réallocation car les diemsnions ont changé

44 CALL init_tab(t, m, n)

17. En particulierxlfd’ibm, le compilateurnagetg95avec l’option-std=f2003ou-std=f95assortie de-ftr15581 (cf.E.5.1, p.153) autorisent l’allocation de l’argument tableau dans la procédure.

7.5. TABLEAUX ET ALLOCATION DYNAMIQUE 83

f2003

7.5.3 Allocation au vol de tableaux dynamiques par affectation

En fortran 2003, un tableau allouable peut être (ré-)alloué automatiquement si on lui affecte une expression tableau :

– s’il n’était pas alloué auparavant, il est alloué avec le profil de l’expression qui lui est affectée ; – s’il était déjà alloué avec un profil différent, il est réalloué pour ajuster son profil à celui du

membre de droite de l’affectation.

La réallocation automatique peut être inhibée si on précise dans le membre de gauche le sym-bole «:» pour chaque dimension. Dans ce cas, les éléments de l’expression de droite en dehors du profil du tableau de gauche sont ignorés.

Par exemple, pour des tableaux de rang 1, le programme suivant :

1 ! allocation automatique par affectation

2 ! fortran 2003 seulement

3 ! ok avec NAG Fortran Compiler Release 5.2(643) le 12 fev 2009

4 PROGRAM t_alloc_affect

5 INTEGER, DIMENSION(:), ALLOCATABLE :: v1, v2, v3

6 v1 = [1, 2] ! allocation de v1 par affectation

7 WRITE(*,*) "taille de v1=", SIZE(v1), " v1=", v1

8 v2 = [-3, -2, -1 ] ! allocation de v2 par affectation

9 WRITE(*,*) "taille de v2=", SIZE(v2), " v2=", v2

10 v3 = v1 ! allocation implicite de v3 => 2 éléments

11 WRITE(*,*) "taille de v3=", SIZE(v3), " v3=", v3

12 v1 = v2 ! réallocation implicite de v1 => 3 éléments

13 WRITE(*,*) "taille de v1=", SIZE(v1), " v1=", v1

14 v3(:) = v2 ! pas de réallocation de v3 => v2(3) inutilisé

15 WRITE(*,*) "taille de v3=", SIZE(v3), " v3=", v3

16 DEALLOCATE(v1, v2, v3)

17 END PROGRAM t_alloc_affect affiche :

taille de v1= 2 v1= 1 2 taille de v2= 3 v2= -3 -2 -1 taille de v3= 2 v3= 1 2 taille de v1= 3 v1= -3 -2 -1 taille de v3= 2 v3= -3 -2

Chaînes de caractères

Ce court chapitre regroupe les outils, dont certains déjà introduits dans les chapitres précédents, permettant la manipulation des chaînes de caractères en fortran : le type chaîne (cf.chapitre2), les expressions de type chaîne (cf.chapitre3) , les sous-chaînes, les fonctions manipulant des chaînes, les entrées/sorties de chaînes (cf. chapitre 5), les tableaux de chaînes et le passage d’arguments chaînes dans les procédures.