Débuter avec Fortran pdf


Télécharger Débuter avec Fortran pdf
3.53.5 étoiles sur 5 a partir de 1 votes.
Votez ce document:

Télécharger aussi :


Fortran 2003

Les apports de Fortran 2003

Patrick Corde et Hervé Delouis

13 février 2008

Fortran 2003

Avertissement : vous trouverez ici un certain nombre de notions introduites par la norme Fortran. Le choix des sujets est arbitraire et non exhaustif. C’est une exploration des principales nouveautés. Les exemples proposés n’ont pu être passés au crible d’un compilateur; il est donc fort possible que des erreurs ou des interprétations approximatives de la norme s’y soient glissées

Voici les principaux documents dont nous nous sommes inspirés :

–     Working Draft J3/04-007 - 10 mai 2004 (). Publié par le comité international J3 chargé du développement de la norme Fortran (585 pages)

–     Fortran 95/2003 explained - Michael METCALF, John REID, Malcolm COHEN - 2004 OXFORD University Press - ISBN 0-19-852693-8 (416 pages).

–     The Future of Fortran - John Reid - juillet/aouˆt 2003 - Scientific Programming ().

–     The New Features of Fortran 2000 - John Reid - Fortran Forum V.21 N.2 aouˆt 2002.

–     Object Orientation and Fortran 2002 : Part II - Malcolm Cohen : Fortran Forum SIGPLAN - V.18 N.1 avril 1999.

1    – Meilleure intégration à l’environnement système    . . . . . . . . . . . . . . .    11

2    – Interopérabilité avec C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    13

2.1    – Entités de type intrinsèques . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.2    – Tableaux C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .      16

2.3    – Variables globales C       . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.4    – Les pointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   19

2.5    – Fonctions C et procédures Fortran  . . . . . . . . . . . . . . . . . . . . .        22

2.5.1    – Exemple de fonction C appelée depuis Fortran . . . . . . . . . . . . .     24

2.5.2    – Exemple de procédure Fortran appelée depuis C . . . . . . . . . . . .     27

2.5.3    – Interopérabilité entre pointeurs : le type C PTR . . . . . . . . . . . . .  31

              2.6 – Structures de données C . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                                      45

    3 – Arithmétique IEEE et traitement des exceptions . . . . . . . . . . . . . . .                                                                        55

                         3.1 – Standard IEEE-754 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                                      56

3.1.1    – Valeurs spéciales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56


3.1.2    – Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     57

3.1.3    – Mode d’arrondi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    58

3.2    – Intégration standard IEEE : modules intrinsèques . . . . . . . . . . . . . 59

3.3    – Fonctions d’interrogation . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

3.4    – Procédures de gestion du mode d’arrondi . . . . . . . . . . . . . . . . . .        65

3.5    – Gestion des exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . .   66

3.6    – Procédures de gestion des interruptions      . . . . . . . . . . . . . . . . . .    70

3.7    – Procédures de gestion du contexte arithmétique . . . . . . . . . . . . . . 71

3.8    – Exemple complémentaire sur les exceptions       . . . . . . . . . . . . . . . . 73

3.9    – Modules intrinsèques . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  74

3.9.1    – Module IEEE EXCEPTIONS . . . . . . . . . . . . . . . . . . . . . . . .     75

3.9.2    – Module IEEE ARITHMETIC . . . . . . . . . . . . . . . . . . . . . . . .     77

3.9.3    – Module IEEE FEATURES . . . . . . . . . . . . . . . . . . . . . . . . . .       81

                          3.10 – Documentations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .                                                                                      83

4 – Nouveautés concernant les tableaux dynamiques . . . . . . . . . . . . . . .

85

4.1 – Passage en argument de procédure . . . . . . . . . . . . . . . . . . . . .

86

4.2 – Composante allouable d’un type dérivé . . . . . . . . . . . . . . . . . . .

88

4.3 – Allocation d’un scalaire ALLOCATABLE . . . . . . . . . . . . . . . . . . . .

89

4.4 – Allocation/réallocation via l’affectation . . . . . . . . . . . . . . . . . . .

90

4.5 – Sous-programme MOVE ALLOC de réallocation . . . . . . . . . . . . . . . .

92

5 – Nouveautés concernant les modules . . . . . . . . . . . . . . . . . . . . . . .

95

5.1 – L’attribut PROTECTED . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

95

5.2 – L’instruction IMPORT du bloc interface . . . . . . . . . . . . . . . . . . .

96

5.3 – USE et renommage d’opérateurs . . . . . . . . . . . . . . . . . . . . . . .

97

6 – Entrées-sorties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

99

6.1 – Nouveaux paramètres des instructions OPEN/READ/WRITE . . . . . . . . .

99

6.2      – Entrées-sorties asynchrones    . . . . . . . . . . . . . . . . . . . . . . . . . 101

6.3      – Entrées-sorties en mode stream . . . . . . . . . . . . . . . . . . . . . . . 103

6.4      – Traitement personnalisé des objets de type dérivé . . . . . . . . . . . . . 106 7 – Pointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

7.1    – Vocation (INTENT) des arguments muets pointeurs     . . . . . . . . . . . . 116

7.2    – Association et reprofilage   . . . . . . . . . . . . . . . . . . . . . . . . . . 117

7.3    – Pointeurs de procédures . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

7.3.1    – Pointeurs de procédure : interface implicite . . . . . . . . . . . . . . . 120

7.3.2    – Pointeurs de procédure : interface explicite . . . . . . . . . . . . . . . 122

8     – Nouveautés concernant les types dérivés . . . . . . . . . . . . . . . . . . . . 126

8.1    – Composante pointeur de procédure . . . . . . . . . . . . . . . . . . . . . 126

8.2    – Paramètres d’un type dérivé . . . . . . . . . . . . . . . . . . . . . . . . . 128

8.3    – Constructeurs de structures . . . . . . . . . . . . . . . . . . . . . . . . . 130

8.4    – Visibilité des composantes . . . . . . . . . . . . . . . . . . . . . . . . . . 135

8.5    – Extension d’un type dérivé     . . . . . . . . . . . . . . . . . . . . . . . . . 137

9     – Programmation orientée objet    . . . . . . . . . . . . . . . . . . . . . . . . . 140

9.1    – Variable polymorphique . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

9.1.1         – Argument muet polymorphique . . . . . . . . . . . . . . . . . . . . . 142

9.1.2         – Variable polymorphique : attribut POINTER, ALLOCATABLE . . . . . . 145

9.2    – Construction SELECT TYPE . . . . . . . . . . . . . . . . . . . . . . . . . . 146

9.3    – Pointeurs génériques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

9.4    – Type effectif d’une variable polymorphique . . . . . . . . . . . . . . . . . 149

9.5    – Procédures attachées à un type (type-bound procedures) . . . . . . . . . 151

9.5.1         – Procédure attachée par nom (name binding) . . . . . . . . . . . . . . 152

9.5.2         – Procédure attachée par nom générique (generic binding) . . . . . . . 153

9.5.3         – Procédure attachée par opérateur (operator binding) . . . . . . . . . 154

9.5.4         – Procédure attachée via le mot-clé FINAL (final binding) . . . . . . . . 157

9.6    – Héritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159

9.6.1         – Héritage d’une procédure type-bound  . . . . . . . . . . . . . . . . . . 159

9.6.2         – Surcharge d’une procédure type-bound . . . . . . . . . . . . . . . . . 161

9.6.3         – Procédure type-bound non surchargeable . . . . . . . . . . . . . . . . 163 9.7 – Type abstrait . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164

10    – En conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

Merci d’envoyer toutes remarques concernant ce document a` :

IDRIS – Bât. 506 – BP167 – 91403 ORSAY – FRANCE

Notes personnelles


1 – Environnement système

1 – Meilleure intégration à l’environnement système

Voici des procédures intrinsèques donnant accès aux arguments de la ligne de commande ou à des variables d’environnement.

? GET COMMAND(command, length, status) sous-progr. retournant dans command la commande ayant lancé le programme.

? COMMAND ARGUMENT COUNT() fonction retournant le nombre d’arguments de la commande.

? GET COMMAND ARGUMENT(number, value, length, status) sous-progr. retournant dans value le numbere argument de la commande (numérotés à partir de zéro).

? GET ENVIRONMENTVARIABLE(name, value, length, status, [trim name])

sous-progr. retournant dans value la valeur de la variable d’environnement spécifiée en entrée via name.

1 – Environnement système

Un nouveau module intrinsèque ISO FORTRANENV donne accès à des entités publiques concernant l’environnement :

? INPUT UNIT, OUTPUTUNIT et ERROR UNIT sont des constantes symboliques de type entier correspondant aux numéros des unités logiques relatifs à l’entrée standard, la sortie standard et à la sortie d’erreur. Ils remplacent avantageusement l’astérisque employé traditionnellement au niveau du paramètre UNIT des instructions READ/WRITE .

? IOSTAT END et IOSTAT EOR sont des constantes symboliques de type entier correspondant aux valeurs négatives prises par le paramètre IOSTAT des instructions d’entrée/sortie en cas de fin de fichier ou fin d’enregistrement. Cela permet d’enrichir la portabilité d’un code Fortran. Cependant, les cas d’erreurs génèrent une valeur positive restant dépendante du constructeur.

2 – Interopérabilité avec C

L’interopérabilité Fortran–C suppose évidemment que l’on ne manipule que des entités (variables, fonctions, concepts, ) communes aux deux langages, ce qui impose un certain nombre de restrictions et de contraintes.

Pour faciliter le travail du programmeur et améliorer la portabilité de son code, la norme Fortran 2003 fournit un certain nombre de nouveaux éléments syntaxiques nécessaires pour faciliter la définition d’entités interopérables qui seront ainsi connues et contrôlées comme telles à l’étape de compilation Fortran.

L’accès (USE) au module ISO C BINDING permet l’interopérabilité avec C pour un certain nombre d’entités que nous allons passer en revue

Note : l’interopérabilité Fortran–C est disponible avec le compilateur Fortran IBM depuis la version 9.1.0.


2.1 – Entités de type intrinsèques

Via des constantes symboliques définissant :

1.     la valeur entière du paramètre KIND des types/sous-types autorisés. Par exemple :

                        Type/sous-type en Fortran     Type correspondant en C

INTEGER(kind=C INT)

int

INTEGER(kind=C SHORT)

short int

INTEGER(kind=C LONG)

long int

REAL(kind=C FLOAT)

float

REAL(kind=C DOUBLE)

double

CHARACTER(kind=C CHAR)

char

etc.

Note : pour le type CHARACTER, C ne supportant que les variables de longueur 1 (gérées sous forme de tableaux), on pourra déclarer une chaˆ?ne sous la forme :

CHARACTER(kind=C_CHAR), dimension(*) :: chaine

2.     des caractères spéciaux :

                      Nom                                     Signification en C   Valeur ASCII   Equivalent C´

C NULL CHAR

null character

achar(0)

\0

C ALERT

alert

achar(7)

\a

C BACKSPACE

backspace

achar(8)

\b

C HORIZONTAL TAB

horizontal tab

achar(9)

\t

C NEW LINE

line feed/new line

achar(10)

\n

C VERTICAL TAB

vertical tab

achar(11)

\v

C FORM FEED

form feed

achar(12)

\f

C CARRIAGE RETURN

carriage return

achar(13)

r

\

2.2 – Tableaux C

Un tableau Fortran est interopérable s’il est d’un type interopérable et de profil explicite ou de taille implicite.

De plus pour les tableaux multidimensionnés, l’ordre des indices doit être inversé. Ainsi les tableaux Fortran :

integer(kind=C_INT), dimension(18,3:7,*) :: t1 integer(kind=C_INT), dimension(18,3:7,100) :: t2 sont interopérables avec les tableaux ainsi déclarés en C :

int t1[][5][18] int t2[100][5][18]

2.3 – Variables globales C

Une variable externe C peut interopérer avec un bloc COMMON ou avec une variable déclarée dans un module Fortran. Par exemple :

Ces variables Fortran sont interopérables avec celles définies en C au niveau externe par :

Remarques

? une variable globale Fortran doit avoir été déclarée avec l’attribut BIND(C) pour pouvoir être mise en correspondance avec une variable externe C,

? si cet attribut a été spécifié sans le paramètre NAME, une référence externe est générée entièrement en minuscules,

? si le paramètre NAME a été précisé, sa valeur correspond au nom de la référence externe générée, en respectant les minuscules et/ou majuscules employées.

2.4 – Les pointeurs

Les pointeurs C, quels qu’ils soient, sont interopérables avec des pointeurs Fortran particuliers du type dérivé semi-privé C PTR dont une composante privée contient l’adresse cachée d’une cible.

On retrouve là l’analogie avec le descripteur du pointeur Fortran qui est sous-jacent à l’attribut POINTER. Le pointeur en Fortran est un concept abstrait et puissant n’autorisant pas (fiabilité oblige) la manipulation arithmétique directe de l’adresse qui reste cachée.

La nécessité de définir les pointeurs de type C PTR, souvent appelés pointeurs C par opposition aux pointeurs Fortran, se justifie en partie par le fait que contrairement à ces derniers ils ne peuvent/doivent pas désigner une zone mémoire non contigu¨e. De plus, le type CPTR est utilisable dans un contexte d’interopérabilité avec tout type de pointeur C (typé ou non – void*).

Toutes les manipulations relatives aux pointeurs C se font via des opérateurs ou des procédures (méthodes), ainsi :

? C LOC(X) fonction retournant un scalaire de type C PTR contenant l’adresse de la cible X (au sens de l’opération unaire &X selon la norme C); par exemple :

A noter que la cible` X doit avoir l’attribut TARGET; elle peut désigner aussi bien un scalaire, un tableau statique, un tableau dynamique alloué, ou même un pointeur associé à un scalaire.

Nous verrons plus loin comment la fonction C LOC facilite l’interopérabilité avec des pointeurs C.

? C F POINTER(CPTR, FPTR [,SHAPE]) : convertit CPTR de type C PTR en un pointeur Fortran FPTR (SHAPE à spécifier si la cible est un tableau);

? C ASSOCIATED(C PTR 1[, C CPTR 2]) vérifie que deux pointeurs C (de type C PTR) sont identiques ou que le premier est à l’état nul.

Notes :

1.     si l’interopérabilité concerne un pointeur de fonction (C function pointer type), on utilisera alors les entités équivalentes :

–    type dérivé semi-privé C FUNPTR,

–    fonction C FUNLOC(X) retournant l’adresse C d’une procédure X dans un scalaire de type C FUNPTR,

–    sous-programme C F PROCPOINTER(CPTR, FPTR) : convertit CPTR, un pointeur de procédure de type C FUNPTR, en un pointeur Fortran FPTR .

2.     ces entités permettent l’interopérabilité des tableaux dynamiques : un tableau Fortran alloué peut être passé à C et un tableau alloué en C peut être associé à un pointeur Fortran (cf. exemple en fin de chapitre).

2.5 – Fonctions C et procédures Fortran

Nouveautés syntaxiques Fortran :

? attribut VALUE pour les arguments muets scalaires. L’argument d’appel correspondant n’est plus passé par référence (adresse), mais via une copie temporaire dans le stack. A noter que la copie en retour n’est pas faite, ce qui est` exclusif de intent(OUT/INOUT)!

? attribut BIND(C [,NAME= ]) obligatoire à la définition d’une procédure Fortran interopérable (ou du bloc interface associé à une fonction C dont le nom peut être spécifié avec le sous-paramètre NAME=).

L’interface de procédure Fortran est constituée des informations exploitables par

Fortran pour définir et contrôler l’interopérabilité avec un prototype de fonction C. Selon les cas, elle est constituée de :

C           Fortran

Fortran ? C l’appel procédural de la fonction C et le bloc interface associé; ? la partie déclarative de la procédure Fortran appelée.

Quelques règles à respecter :

? interface explicite et attribut BIND(C) obligatoire,

? arguments muets tous interopérables (non optionnels) et en cohérence avec ceux du prototype C,

? une fonction Fortran doit retourner un scalaire interopérable et un sous-programme doit correspondre à un prototype C retournant le type void,

? un argument du prototype C de type pointeur peut être associé à un argument muet Fortran classique sans l’attribut VALUE (cf. exemple suivant),

? un argument du prototype C qui n’est pas de type pointeur doit être associé à un argument muet avec l’attribut VALUE (cf. exemple suivant).

2.5.1 – Exemple de fonction C appelée depuis Fortran

Dans cet exemple, Fortran passe à C deux arguments : – un tableau passé classiquement par référence, – une variable entière passée par valeur.

Tout d’abord, voici la fonction C appelée et son prototype :

Ci-après, voici :

? le bloc interface associé à la fonction C (dans un module),

? le programme Fortran appelant,

? un schéma récapitulatif du passage des arguments.


Exemple : fonction C appelée depuis Fortran

Appel : y = C_FUNC(array=tab, N=n)

2.5.2 – Exemple de procédure Fortran appelée depuis C

Dans cet exemple, Fortran rec¸oit de C trois arguments :

–    une variable entière passée par valeur,

–    une variable réelle passée par référence,

–    un tableau à taille implicite passé par référence.

Voici le prototype C de la fonction correspondante et le programme C avec une séquence d’appel de f1 :

Voici le source du sous-programme Fortran F1 :

Exemple : procédure Fortran appelée depuis C

Appelant C

Sous?progr. Fortran

appelé BIND(C)

&beta

? Le prototype de la fonction C associée au sous-programme F1 indique qu’aucune valeur n’est retournée (void).

? Le 1er argument muet A de type INTEGER(C LONG) avec l’attribut VALUE correspond au paramètre formel a du prototype; il rec¸oit la valeur de alpha copiée dans le stack. Attention : l’attribut INTENT (vocation), n’ayant aucun sens dans ce cas, est interdit!

? Le 2e argument muet B de type REAL(C DOUBLE) correspond au paramètre formel b (pointeur typé double) du prototype; il rec¸oit l’adresse de beta (&beta).

? Le 3e argument muet D de type REAL(C DOUBLE) est un tableau de taille implicite correspondant au paramètre formel d du prototype; il rec¸oit l’adresse du 1er élément du tableau delta.


Passage par valeur (VALUE)

Passage par référence

Fortran

?

C

•      La fonction C récupère le contenu de la composante adresse encapsulée dans l’argument de type C PTR nécessairement déjà associé, • intent(OUT/INOUT) interdit,

•      Bloc interface obligatoire.

=? cf. exemple 1 ci-après

•     La fonction C récupère l’adresse de la composante adresse encapsulée dans l’argument de type C PTR non nécessairement associé,

•     Bloc interface obligatoire.

=? cf. exemple 2 ci-après

C

?

Fortran

•     C passe à Fortran un pointeur déjà valorisé,



•     intent(OUT/INOUT) interdit.

=? cf. exemple 4 ci-après

• C doit passer l’adresse (&p) d’un pointeur qui pourra donc être associé dans la procédure Fortran.

=? cf. exemples 3 et 4 ci-après

2.5.3 – Interopérabilité entre pointeurs : le type C PTR

Argument Fortran de type C PTR

Exemple 1 : Fortran =? C (argument C PTR passé par valeur)

Dans cet exemple, Fortran alloue et valorise un tableau à deux dimensions. Son adresse traduite en un pointeur C à l’aide de la fonction C LOC est transmise par valeur à une fonction C.

De plus la fonction C récupère les dimensions du tableau qui lui ont été passées par valeur.

Notes :

? le tableau Fortran déclaré avec l’attribut ALLOCATABLE n’est pas interopérable. Le type C PTR employé ici permet de contourner ce problème,

? on donne deux versions de la fonction C, l’une respectant la norme C89, l’autre la norme C99.

program EXEMPLE_1

use, intrinsic :: ISO_C_BINDING real(kind=C_FLOAT), dimension(:,:), allocatable, target :: mat

integer(kind=C_INT)     :: n, m interface !------------------------------------------!

subroutine c_func( n, m, v ) bind(C, name="fct")

import C_INT, C_PTR

integer(kind=C_INT), VALUE :: n, m type(C_PTR), VALUE        :: v end subroutine c_func

end interface !--------------------------------------!

read *, n, m ; allocate( mat(n,m) )

call random_number( mat ) call c_func( n, m, C_LOC(mat) ) print *, "SOMME = ", sum( array=mat, dim=1 ) deallocate( mat )

end program EXEMPLE_1

---------------------------------------------------------------------------------void fct( int n, int m, float *vec )      void fct( int n, int m, float mat[m][n] )

{                                                                                              ! {

float **mat; !        for( int i=0; i<m; i++ ) int     i, j; !        mat[i][n-1] *= 2.; mat = malloc( m*sizeof(float *) );        !

for( i=0, j=0; i<m; i++, j+=n )       !        return; mat[i] = vec+j, mat[i][n-1] *= 2.; ! } free( mat ); ! }      !


Exemple 1 : Fortran ==> C (argument C_PTR passé par valeur)

Appel : call c_func(n, m, C_LOC(mat))

Exemple 2 : Fortran =? C (argument C PTR passé par référence)

Dans cet exemple, Fortran souhaite sous-traiter à une fonction C l’allocation d’une matrice n*m qu’il référencera ensuite via un pointeur Fortran.

A l’appel de la fonction C, Fortran passe par valeur les deux d`    imensions n et m désirées et passe par référence un pointeur interopérable non encore associé.

La fonction C appelée alloue une zone mémoire de n*m réels. Son adresse est stockée dans l’objet Fortran pointeurC de type C PTR.

En retour de la fonction C, Fortran convertit l’objet pointeurC en un pointeur Fortran classique (via la procédure C F POINTER) qui devient ainsi associé à la matrice allouée en C.

Ensuite cet objet pointeurC est transmis par valeur à une autre fonction C afin de libérer la zone allouée.

program exemple2

use ISO_C_BINDING

integer(kind=C_INT)     :: n, m type(C_PTR)   :: pointeurC

real(kind=C_FLOAT), dimension(:,:), pointer :: p_mat interface

subroutine c_alloc( ptrC, n, m ) bind(C, name="C_alloc")

import C_PTR, C_INT

type(C_PTR), intent(out) :: ptrC integer(kind=C_INT), VALUE :: n, m

end subroutine c_alloc

subroutine c_free( ptrC ) bind(C, name="C_free")

import C_PTR

type(C_PTR), VALUE :: ptrC

end subroutine c_free

end interface

read *, n, m ; call c_alloc( pointeurC, n, m )

call C_F_POINTER( CPTR=pointeurC, FPTR=p_mat, shape=(/ n, m /) ) call random_number( p_mat )

print *, "SOMME = ", sum( array=p_mat, dim=1 )

call c_free( pointeurC )

end program exemple2

---------------------------------------------------------------------void C_alloc( float **p, int n, int m )

{ *p = malloc( n*m*sizeof(float) ); return ; }

---------------------------------------------------------------------void C_free( float *p ) { free( p ); return ; }

Exemple 2 : Fortran ==> C (argument C_PTR passé par référence)
Appel : call c_alloc(pointeurC, n, m)

Exemple 3 : C =? Fortran (argument C PTR passé par référence)

Dans cet exemple, C souhaite sous-traiter à des sous-programmes Fortran la gestion (allocation, valorisation, traitement, libération) d’un vecteur de 100 réels.

A l’appel du sous-programme`      for alloc, C passe en argument l’adresse &vec d’un pointeur de réels.

Dans le sous-programme for alloc, l’argument pointeurC muet correspondant est un pointeur de type C PTR de vocation INTENT(OUT) sans l’attribut VALUE.

Fortran alloue un tableau de la taille requise dont l’adresse est retournée à C via l’argument de sortie pointeurC valorisé à l’aide de la fonction C LOC.

En retour du sous-programme Fortran, C peut accèder à la zone dynamique par l’intermédiaire du pointeur vec.

Voici successivement :

–     le programme C appelant avec le prototype des sous-programmes Fortran, – les sous-programmes Fortran,

–     un schéma du passage des arguments du sous-programme for alloc.

Exemple 3 : C ==> Fortran (argument C_PTR passé par référence)

Appel : F_alloc(&vec, n)

Notes sur l’exemple 3 ci-dessus :

? Le tableau dynamique vecteur (allocatable) est déclaré comme entité globale dans le module creer liberer car il n’est pas possible de le libérer via un pointeur associé passé en argument du sous-programme for free.

? L’entité vecteur pourrait être déclarée avec l’attribut pointer (au lieu de allocatable); il ne serait alors plus nécessaire de le globaliser pour pouvoir désallouer la cible dynamique anonyme qui lui serait associée.

Par contre, sa conversion en pointeur C interopérable ne pourrait se faire que sous la forme C LOC(vecteur(1)) car, selon la norme, l’argument de C LOC ne peut être un pointeur Fortran associé à un tableau.


Exemple 4 : C =? Fortran (argument C PTR par référence et par valeur)

Dans cet exemple, C sollicite des méthodes Fortran pour manipuler des objets de type dérivé non interopérables adressés via un pointeur de type C PTR.

1.    C déclare deux pointeurs,

2.    C appelle la méthode INIT pour créer et valoriser deux objets de ce type (passage par référence),

3.    C appelle la méthode ADD pour effectuer un traitement sur ces deux objets (passage par valeur).

Notes :

–    dans la méthode INIT on utilise la fonction C LOC pour retourner à la fonction C l’adresse de l’objet alloué.

–    dans la méthode ADD on utilise la procédure C F POINTER afin de convertir l’objet de type C PTR en pointeur Fortran permettant de manipuler l’objet transmis.

module gestion_cellule use ISO_C_BINDING type pass integer n

real, allocatable, dimension(:) :: a

|-----------------------------------

/* Fonction C appelante */

end type pass

main()

type(pass), pointer :: p_cel

{

contains

void *p, *q ;

subroutine init( data, n ) BIND(C)

type(C_PTR), intent(out) :: data

init( &p, 100 ) ;

                           integer(C_INT), VALUE                 :: n

init( &q, 200 ) ;

allocate(p_cel)

p_cel%n = n

add( p, ) ;

allocate(p_cel%a(n))

add( q, ) ;

data = C_LOC(p_cel) end subroutine init

return 0 ;

subroutine add( data, ) BIND(C)

}

type(C_PTR), VALUE :: data

. . .

call C_F_POINTER( data, p_cel )

. . .

end subroutine add end module gestion_cellule

|-----------------------------------

2.6 – Structures de données C

Via l’attribut BIND(C).

Exemple : un objet de type C struct ainsi défini en C :

est interopérable avec une structure Fortran du type F struc :

Note : les entités ALLOCATABLE et les procédures sont exclues pour les composantes qui doivent bien suˆr toutes être interopérables; par contre, les types C PTR et C FUNPTR permettent d’y stocker l’adresse C de telles entités (cf. exemple ci-après).

Exemple Fortran =? C : Fortran passe par valeur à une fonction C une structure de données (type vecteur) contenant une composante pointeur interopérable associée à une cible dynamique déjà allouée et valorisée. Via un argument muet d’entrée défini comme une structure C équivalente, la fonction C peut accéder à la cible dynamique.

Voici tout d’abord un module contenant la définition du type dérivé Fortran vecteur et le bloc interface de la fonction C appelée :

Voici le programme Fortran appelant la fonction C; il lui passe le vecteur v encapsulant le tableau dynamique tab :

Voici la définition de la fonction C moyenne qui récupére en argument le vecteur passé par Fortran pour accéder au tableau alloué dans le but de calculer la moyenne de ses

éléments :


Exemple 1 : Fortran ==> C (structure de données en argument avec composante pointeur)

Exemple C =? Fortran : interopérabilité d’une structure de données passée par valeur et contenant une composante pointeur associée à une cible dynamique. Dans cet exemple la cible est allouée en C puis valorisée dans le sous-programme Fortran appelé.

Voici le sous-programme Fortran valorisation :

Programme C et prototype de la fonction Fortran F val appelée :

Exemple 2 : C ==> Fortran (structure de données en argument avec composante pointeur)

Reprenons ce même exemple en passant cette fois-ci le vecteur vec par référence.

Voici les modifications à apporter :

Notes personnelles


3 – Arithmétique IEEE

3 – Arithmétique IEEE et traitement des exceptions

3.1 – Standard IEEE-754

Le standard IEEE-754 concernant l’arithmétique réelle flottante ainsi que le traitement des exceptions définit un système de représentation des nombres flottants.

3.1.1 – Valeurs spéciales

Ce système permet la représentation des valeurs spe´ciales suivantes :

? NaN (Not a Number) : valeur d’une expression mathématique indéterminée comme

1,

? +INF (+?), -INF (??),

? 0+, 0?,

? dénormalisées : concernent les très petites valeurs.

Dans tout système de représentation, en l’occurrence celui défini par le standard IEEE, l’ensemble des réels représentables est un ensemble fini.

3.1.2 – Exceptions

Dans des cas extrêmes, une opération arithmétique peut produire comme résultat une des valeurs spéciales indiquées ci-dessus ou bien une valeur en dehors de l’ensemble des valeurs représentables. De tels cas génèrent des événements de type exception. Le standard IEEE définit 5 classes d’exception :

? overflow : valeur calculée trop grande,

? underflow : valeur calculée trop petite,

? division par zéro,

? opération invalide : valeur calculée égale à NaN,

? opération inexacte : valeur calculée non représentable exactement (implique un arrondi).

Dans le cas d’un underflow, la valeur calculée est soit une valeur dénormalisée (gradual underflow) soit 0 (abrupt underflow) selon le choix du programmeur.

Lorsqu’une exception se produit, un flag spécifique est positionné.

3.1.3 – Mode d’arrondi

Lorsque la valeur calculée n’est pas représentable, une exception de type opération inexacte est générée et le calcul se poursuit avec une valeur approchée (arrondie).

Le standard IEEE définit 4 modes d’arrondi :

? toward nearest (défaut sur IBM xlf),

? toward zéro,

? toward +INF (+?), ? toward -INF (??).

Note : aucune valeur par défaut n’est prévue par la norme!


3 – Arithmétique IEEE : modules intrinsèques

3.2 – Intégration standard IEEE : modules intrinsèques

Trois modules intrinsèques permettent l’accès aux fonctionnalités définies par le standard IEEE :

? IEEE ARITHMETIC,

? IEEE EXCEPTIONS,

? IEEE FEATURES.

Ces modules contiennent des définitions :

? de types,

? de constantes symboliques, ? de procédures.

3.3 – Fonctions d’interrogation

Ce sont des fonctions d’interrogation sur l’environnement utilisé afin de savoir s’il est conforme en tout ou partie au standard IEEE :

? IEEE SUPPORT STANDARD(x),

? IEEE SUPPORT DATATYPE(x),

? IEEE SUPPORT DENORMAL(x),

? IEEE SUPPORT INF(x),

? IEEE SUPPORT NAN(x),

Elles retournent une valeur logique indiquant si l’environnement utilisé respecte le standard ou un aspect du standard pour le type de l’argument réel x fourni.

Il existe des fonctions permettant de connaˆ?tre la classe ou le type de valeur d’un réel x (NaN, ?, négatif, positif, nul, ). L’appel à ces fonctions n’est possible que si la fonction IEEE SUPPORT DATATYPE appliquée à ce réel retourne la valeur vraie.

Les classes sont définies via des constantes symboliques d’un type prédéfini (IEEE CLASS TYPE) dont voici la liste :

? IEEE SIGNALING NAN (NaNS),

? IEEE QUIET NAN (NaNQ), ? IEEE NEGATIVE INF,

? IEEE POSITIVE INF,

? IEEE NEGATIVEDENORMAL,

? IEEE POSITIVEDENORMAL,

? IEEE NEGATIVENORMAL,

? IEEE NEGATIVE ZERO,

? IEEE POSITIVENORMAL,

? IEEE POSITIVE ZERO,

? IEEE OTHER VALUE

Ces fonctions sont les suivantes :

? IEEE CLASS(x),

? IEEE IS NAN(x),

? IEEE IS FINITE(x),

? IEEE IS NEGATIVE(x), ? IEEE IS NORMAL(x).

De plus la fonction IEEE_VALUE(x, class) génère un réel d’un type (celui de x) et d’une classe donnés.

L’exemple qui suit permet de récupérer la classe d’un réel x lu dans le fichier fort.1.

if ( IEEE_SUPPORT_DENORMAL( x ) ) then

if ( class_type == IEEE_NEGATIVE_DENORMAL ) & print *,"X is a IEEE_NEGATIVE_DENORMAL number"

if ( class_type == IEEE_POSITIVE_DENORMAL ) &

print *,"X is a IEEE_POSITIVE_DENORMAL number"

end if

if ( class_type == IEEE_NEGATIVE_NORMAL ) & print *,"X is a IEEE_NEGATIVE_NORMAL number"

if ( class_type == IEEE_POSITIVE_NORMAL ) & print *,"X is a IEEE_POSITIVE_NORMAL number"

if ( class_type == IEEE_NEGATIVE_ZERO ) & print *,"X is a IEEE_NEGATIVE_ZERO number"

if ( class_type == IEEE_POSITIVE_ZERO ) &

print *,"X is a IEEE_POSITIVE_ZERO number"

end if y = IEEE_VALUE( x, class_type ); print *,y end program class


3 – Arithmétique IEEE : gestion mode d’arrondi

3.4 – Procédures de gestion du mode d’arrondi

Le mode d’arrondi utilisé lors de calculs est géré par deux sous-programmes (les différents modes sont définis à l’aide des constantes symboliques IEEE NEAREST, IEEE UP, IEEE DOWN, IEEE TO ZERO du type prédéfini IEEE ROUND VALUE) :

? IEEE GET ROUNDING MODE(round value),

? IEEE SET ROUNDING MODE(round value),

3.5 – Gestion des exceptions

Le programmeur, après avoir détecté la survenance d’une exception, a la possibilité de lancer un traitement personnalisé.

A chacune des 5 classes d’exception correspondent 2 drapeau`                                                                                                x :

? l’un indiquant si l’événement relatif à l’exception s’est réalisé,

? l’autre signalant si ce type d’exception provoque une interruption du programme.

Ces différents drapeaux sont référencés à l’aide de constantes symboliques d’un type prédéfini (IEEE FLAG TYPE) :

? IEEE UNDERFLOW,

? IEEE OVERFLOW,

? IEEE DIVIDE BY ZERO,

? IEEE INVALID

? IEEE INEXACT

De plus, deux constantes symboliques de type tableau (IEEE USUAL, IEEE ALL) permettent de référencer tout ou partie de ces drapeaux :

IEEE_USUAL = (/ IEEE_OVERFLOW, IEEE_DIVIDE_BY_ZERO, IEEE_INVALID /)

IEEE_ALL                      = (/ IEEE_USUAL, IEEE_UNDERFLOW, IEEE_INEXACT /)

Ces constantes symboliques sont principalement utilisées comme argument de fonctions telles que :

? IEEE GET FLAG(flag, flag value)

? IEEE SET FLAG(flag, flag value)

Ces procédures retournent dans l’argument flag value un logique signalant l’état de l’exception indiquée en 1er argument sous forme d’une des constantes symboliques précédentes.

Exemple d’utilisation

Note : lors de l’appel et du retour d’une procédure, le contexte de gestion de l’arithmétique IEEE est sauvegardé puis restauré. Pour des raisons de performance, ce processus peut être inhibé sur certains environnements via une option du compilateur (cf. option -qnostrictieeemod de xlf sur IBM).

Lorsqu’une exception de type underflow se produit, le résultat du calcul est soit 0 (abrupt underflow) soit un nombre dénormalisé si le processeur supporte de tels nombres (gradual underflow).

Les deux sous-programmes suivants permettent de gérer le mode d’underflow désiré (gradual underflow ou abrupt underflow) :

? IEEE GET UNDERFLOW MODE(gradual)

? IEEE SET UNDERFLOW MODE(gradual)

use IEEE_ARITHMETIC implicit none

logical :: save_underflow_mode

! Sauvegarde du mode d’underflow courant. call IEEE_GET_UNDERFLOW_MODE( GRADUAL=save_underflow_mode )

! Positionnement du mode abrupt underflow

CALL IEEE_SET_UNDERFLOW_MODE( GRADUAL=.false. ) ! Calculs dans le mode abrupt underflow ; une valeur ! trop petite est alors remplaceé par ze´ro.

!                             . . .

! Restauration du mode d’underflow sauvegarde´.

CALL IEEE_SET_UNDERFLOW_MODE( GRADUAL=save_underflow_mode )


3 – Arithmétique IEEE : gestion des interruptions

3.6 – Procédures de gestion des interruptions

Lorsqu’une exception est générée, le programme peut s’arrêter ou bien continuer. Ce mode de fonctionnement est contrôlé par les sous-programmes suivants :

? IEEE GET HALTING MODE(flag, halting)

? IEEE SET HALTING MODE(flag, halting)

3 – Arithmétique IEEE : contexte arithmétique

3.7 – Procédures de gestion du contexte arithmétique

Deux autres sous-programmes gèrent l’état de l’environnement relatif à l’arithmétique flottante (drapeaux d’exceptions et d’interruptions, mode d’arrondi) :

? IEEE GET STATUS(status value)

? IEEE SET STATUS(status value)

L’argument status_value est du type IEEE STATUS TYPE; il contient en entrée (SET) ou en sortie (GET) l’état de tous les drapeaux relatifs à l’arithmétique flottante.

3 – Arithmétique IEEE : contexte arithmétique

Voici un exemple montrant comment sauvegarder puis restaurer l’ensemble de ces drapeaux :

3 – Arithmétique IEEE : exemple sur les exceptions


3.9 – Modules intrinsèques

La disponibilité des modules IEEE ARITHMETIC, IEEE EXCEPTIONS et IEEE FEATURES dépend de l’environnement utilisé, de même que les constantes symboliques définies dans le module IEEE FEATURES, dans le cas ou` celui-ci est fourni.

Le module IEEE ARITHMETIC se comporte comme s’il contenait une instruction use IEEE EXCEPTIONS.

Si, dans une unité de programme, le module IEEE ARITHMETIC ou IEEE EXCEPTIONS est accessible, les fonctionnalités IEEE OVERFLOW et IEEE DIVIDE BY ZERO sont supportées dans cette unité pour tout type de réels et de complexes. On utilisera la fonction IEEE SUPPORT FLAG afin de savoir si les autres fonctionnalités le sont.

Ces modules définissent 5 types dérivés dont les composantes sont privées et un ensemble de procédures.

3.9.1 – Module IEEE EXCEPTIONS

Il définit les types :

? IEEE FLAG TYPE permettant d’identifier un type d’exception particulier. Les valeurs possibles sont les constantes symboliques suivantes :

? IEEE INVALID,

? IEEE OVERFLOW,

? IEEE DIVIDE BY ZERO,

? IEEE UNDERFLOW,

? IEEE INEXACT

? IEEE STATUS TYPE pour la sauvegarde de l’environnement flottant.

Il définit les fonctions d’interrogations suivantes :

? IEEE SUPPORT FLAG,

? IEEE SUPPORT HALTING,

Il définit les sous-programmes élémentaires suivants :

? IEEE GET FLAG,

? IEEE GET HALTING MODE,

Il définit les sous-programmes non élémentaires suivants :

? IEEE GET STATUS,

? IEEE SET FLAG,

? IEEE SET HALTING MODE,

? IEEE SET STATUS

3.9.2 – Module IEEE ARITHMETIC

Il définit les types :

? IEEE CLASS TYPE permettant d’identifier la classe d’un réel. Les valeurs possibles sont les constantes symboliques suivantes :

? IEEE SIGNALING NAN,

? IEEE QUIET NAN,

? IEEE NEGATIVE INF,

? IEEE NEGATIVE NORMAL,

? IEEE NEGATIVEDENORMAL, ? IEEE NEGATIVE ZERO,

? IEEE POSITIVEZERO,

? IEEE POSITIVE DENORMAL,

? IEEE POSITIVE NORMAL,

? IEEE POSITIVE INF,

? IEEE OTHER VALUE

? IEEE ROUND TYPE permettant d’identifier le mode d’arrondi. Les valeurs possibles sont les constantes symboliques suivantes : ? IEEE NEAREST,

? IEEE TO ZERO,

? IEEE UP,

? IEEE DOWN,

? IEEE OTHER

De plus, il surdéfinit les opérateurs == et /= pour deux valeurs d’un de ces types.

Il définit les fonctions d’interrogation suivantes :

? IEEE SUPPORT DATATYPE,

? IEEE SUPPORT DENORMAL,

? IEEE SUPPORT DIVIDE,

? IEEE SUPPORT INF

Il définit les fonctions élémentaires suivants :

? IEEE CLASS,

? IEEE COPY SIGN,

? IEEE IS FINITE,

? IEEE IS NAN,

? IEEE IS NORMAL,

? IEEE IS NEGATIVE,

? IEEE LOGB,

? IEEE NEXT AFTER,

? IEEE REM,

? IEEE RINT,

? IEEE SCALEB,

? IEEE UNORDERED,

? IEEE VALUE

Il définit la fonction de transformation suivante :

? IEEE SELECTED REAL KIND

Il définit les sous-programmes non élémentaires suivants :

? IEEE GET ROUNDING MODE,

? IEEE GET UNDERFLOW MODE,

? IEEE SET ROUNDING MODE,

? IEEE SET UNDERFLOW MODE

3.9.3 – Module IEEE FEATURES

Il définit les constantes symboliques (du type IEEE FEATURES TYPE) associées à des fonctionnalités IEEE :

? IEEE DATATYPE,

? IEEE DENORMAL,

? IEEE DIVIDE,

? IEEE HALTING,

? IEEE INEXACT FLAG,

? IEEE INF,

? IEEE INVALID FLAG,

? IEEE NAN,

? IEEE ROUNDING,

? IEEE SQRT,

? IEEE UNDERFLOW FLAG

Pour un processeur donné, une partie de ces fonctionnalités peuvent être naturelles et seront donc mises en œuvre en l’absence du module IEEE FEATURES. Pour ce processeur, le fait de coder l’instruction use IEEE_FEATURES dans une unité de programme aura pour effet de solliciter d’autres fonctionnalités au prix d’un surcouˆt.

Le programmeur peut demander l’accès, à l’aide de la clause ONLY de l’intruction use précédente, à une fonctionnalité particulière laquelle peut être :

? naturelle,

? génératrice d’un surcouˆt,

? non disponible, un message d’erreur sera alors émis par le compilateur.

Exemple :


3 – Arithmétique IEEE : documentations

3.10 – Documentations

==> Exceptions and IEEE arithmetic



?uid=swg27003923&aid=1 ==> Chapter 16. Floating-point Control and Inquiry Procedures

Note : fonctionnalités faisant déjà partie des extensions du compilateur Fortran d’IBM depuis la version 9.1.0.

3 – Arithmétique IEEE : documentations

Notes personnelles

4 – Nouveautés concernant les tableaux dynamiques

En Fortran 95, du fait des insuffisances notoires des tableaux dynamiques (attribut ALLOCATABLE), on leur substituait souvent les pointeurs plus puissants, mais présentant des inconvénients en terme de performance.

En Fortran 2003, les tableaux allouables sont désormais gérés par un descripteur interne analogue à celui d’un pointeur. Ce descripteur peut être vu comme un type dérivé semi-privé contenant, entre autres, l’adresse d’une zone dynamique anonyme. Il est donc normal qu’un tableau dynamique ait maintenant les avantages du pointeur vis-à-vis du passage en paramètre de procédure et des composantes dynamiques de structures de données ainsi que de nouvelles possibilités abordées ci-après.

On réservera alors l’usage des pointeurs aux fonctionnalités qui leur sont propres :

notion d’alias dynamique d’entités éventuellement complexes, gestion de listes chaˆ?nées, pointeurs de procédures dans les types dérivés,


4.1 – Passage en argument de procédure

En Fortran 95, un tableau allouable ne pouvait être passé en argument d’appel que s’il était déjà alloué. Au sein de la procédure appelée, il était considéré comme un simple tableau à profil implicite (sans l’attribut ALLOCATABLE).

En Fortran 2003 et en contexte d’interface explicite, un argument muet pouvant avoir l’attribut ALLOCATABLE, l’argument d’appel correspondant devra aussi avoir cet attribut ainsi que le même rang et le même type/sous-type, sans être nécessairement déjà alloué. Voici un exemple :

Remarques :

? Si un argument muet a la vocation INTENT(OUT), l’argument d’appel correspondant est automatiquement désalloué à l’appel de la procédure (s’il était alloué).

? Comme c’était déjà le cas pour les pointeurs de tableaux en Fortran 95, les bornes inférieures/supérieures des dimensions d’un tableau allouable passé en argument sont récupérables dans l’unité appelée dans le cas ou` celui-ci a été préalablement alloué dans l’unité appelante.

? Quand un objet de type dérivé est désalloué, toute composante ayant l’attribut ALLOCATABLE est automatiquement désallouée. Si un destructeur (final subroutine – cf. §8.5) est attaché à l’objet, il est appliqué avant la désallocation de cette

composante.

4.2 – Composante allouable d’un type dérivé

L’attribut ALLOCATABLE est autorisé pour une composante. Voici un exemple :

C’est bien entendu le descripteur du tableau allouable qui sera stocké dans la composante A de MAT1.

4.3 – Allocation d’un scalaire ALLOCATABLE

L’attribut ALLOCATABLE peut dorénavant s’appliquer à un scalaire. Voici un exemple :

Dans cet exemple, la taille de la chaˆ?ne de caractères ch est définie à l’exécution et fournie ensuite au niveau de l’instruction ALLOCATE en explicitant le type.

4.4 – Allocation/réallocation via l’affectation

Une allocation/réallocation d’une entité var alloc (scalaire ou tableau ayant l’attribut ALLOCATABLE) peut se faire implicitement lors d’une opération d’affectation du type : var alloc = expression

1.     Si var alloc est déjà allouée, elle est automatiquement désallouée si des différences concernant le profil ou la valeur des length type parameters – (cf. §8.2) existent entre var alloc et expression.

2.     Si var alloc est ou devient désallouée, alors elle est réallouée selon le profil et les paramètres de type de expression. Voici un exemple permettant le traitement d’une chaˆ?ne de caractères de longueur variable :

character(:), ALLOCATABLE :: NAME !<-- Scalaire character(len=:) . . . .

NAME = ’chaine_de_car’//’acteres’; . . . .; NAME = ’FIN’

La variable scalaire NAME de type CHARACTER sera allouée lors de la première affectation avec une longueur LEN=20. Lors de la 2e affectation, elle sera désallouée puis réallouée avec une longueur LEN=3.

A noter que cette possibilité de réallocation dynamique f`        acilite la gestion des chaˆ?nes dynamiques ainsi que le respect de la contrainte de conformance lors d’une affectation de tableaux. Ainsi par exemple :

Le tableau x est automatiquement alloué/réalloué avec le bon profil sans se préoccuper du nombre d’éléments vrais de masque.

Note : ce processus d’allocation/réallocation automatique peut être inhibé en codant par exemple :

NAME(:) = ’chaine_de_car’//’acteres’ x(1:count(masque)) = pack(tableau, masque)

A gauche de l’affectation, la présence du`        :       signifie qu’on fait référence à un sous-ensemble d’une entité (NAME ou x) qui doit exister et donc être déjà allouée.

4.5 – Sous-programme MOVE ALLOC de réallocation

MOVE ALLOC(FROM, TO)

réalloue à TO l’objet alloué passé via FROM.

-   FROM entité allouable de n’importe quel type/rang. Sa vocation est INTENT(INOUT),

-   TO entité allouable compatible (type et rang) avec FROM. Sa vocation est INTENT(OUT).

En retour de ce sous-programme, le tableau allouable TO désigne le tableau allouable FROM; la zone mémoire préalablement désignée par TO est désallouée.

En fait, c’est une méthode permettant de nettoyer le descripteur de FROM après l’avoir recopié dans celui de TO.

–    Si FROM n’est pas alloué en entrée, TO devient non alloué en sortie.

–    Si TO a l’attribut TARGET, tout pointeur initialement associé à FROM devient associé à

TO.


5 – Nouveautés concernant les modules

5.1 – L’attribut PROTECTED

De même que la vocation INTENT(in) protège les arguments muets d’une procédure, l’attribut PROTECTED protège les entités déclarées avec cet attribut dans un module; elles sont exportables (use association) mais pas modifiables en dehors du module ou` est faite la déclaration.

? cet attribut n’est spécifiable que dans le module ou` est faite la déclaration, pas dans ceux qui l’importent (USE);

? les sous-objets éventuels d’un objet protégé rec¸oivent l’attribut PROTECTED; ? pour un pointeur, c’est l’association et non la cible qui est protégée.

5.2 – L’instruction IMPORT du bloc interface

En Fortran 95, un bloc interface ne pouvait accéder aux entités (définition de type dérivé par ex.) de l’unité hôte (module ou unité de programme). L’instruction IMPORT permet l’importation (host association) de ces entités dans un bloc interface :

IMPORT sans liste permet l’importation de toutes les entités vues par host association.

5.3 – USE et renommage d’opérateurs

Les opérateurs non intrinsèques d’un module peuvent être renommés au moment de leur importation via l’instruction USE. Voici un exemple :

Notes personnelles


6 – Entrées-sorties

6.1 – Nouveaux paramètres des instructions OPEN/READ/WRITE

IOMSG : ce paramètre des instructions READ/WRITE identifie une chaˆ?ne de caractères récupérant un message si une erreur, une fin de fichier ou une fin d’enregistrement intervient à l’issue de l’entrée-sortie.

ROUND : lors d’une entrée-sortie formatée le mode d’arrondi peut être contrôlé à l’aide du paramètre ROUND de instruction OPEN qui peut prendre comme valeurs : "up",

"down", "zero", "nearest", "compatible" ou "processor defined". Cette valeur peut être changée au niveau des instructions READ/WRITE à l’aide du même paramètre ou via les spécifications de format ru, rd, rz, rn, rc et rp. La valeur par défaut dépend du processeur utilisé.

SIGN : ce paramètre a été ajouté à l’instruction OPEN pour la gestion du signe + des données numériques en sortie. Il peut prendre les valeurs : "suppress", "plus" ou "processor defined". Cette valeur peut être changée au moment de l’instruction WRITE à l’aide du même paramètre, ou bien à l’aide des spécifications de format ss, sp et s. La valeur par défaut est "processor defined".

IOSTAT : deux nouvelles fonctions élémentaires is iostat end et is iostat eor permettent de tester la valeur de l’entier référencé au niveau du paramètre IOSTAT de l’instruction READ. Elles retournent la valeur vraie si une fin de fichier ou une fin d’enregistrement a été détectée.

Remarque : les paramètres comme IOSTAT peuvent dorénavant référencer tout type d’entier.

INTEGER(kind=2) :: unit, iostat

READ( UNIT=unit, , IOSTAT=iostat )

IF( is_iostat_end( iostat ) ) then

. . .

END IF

6.2 – Entrées-sorties asynchrones

Les entrées-sorties peuvent être faites en mode asynchrone, permettant ainsi au programme de continuer son exécution pendant que l’entrée-sortie est en cours. Ce mode de fonctionnement n’est possible que pour les fichiers externes ouverts avec le paramètre ASYNCHRONOUS=’yes’. Ce même paramètre sera fourni également au niveau de l’instruction READ/WRITE si l’on désire lancer une telle entrée-sortie, sinon, par défaut ou en précisant le paramètre ASYNCHRONOUS=’no’, elle sera synchrone quel que soit le mode d’ouverture effectué.

Une synchronisation peut être demandée explicitement à l’aide de l’instruction

WAIT(unit= , ). Celle-ci est implicite à la rencontre d’un INQUIRE ou d’un CLOSE sur le fichier.

Toute entité faisant l’objet d’entrées-sorties asynchrones récupère automatiquement un nouvel attribut ASYNCHRONOUS dans le but d’avertir le compilateur du risque encouru à optimiser des portions de code les manipulant.

En effet, le résultat de cette optimisation pourrait être un déplacement d’instructions référenc¸ant ces entités avant une instruction de synchronisation.

On peut préciser explicitement cet attribut lors de la déclaration :

6.3 – Entrées-sorties en mode stream

Le paramètre ACCESS de l’instruction OPEN admet une troisième valeur STREAM permettant d’effectuer des entrées-sorties en s’affranchissant de la notion

d’enregistrement : le fichier est considéré comme étant une suite d’unités (unité = octet ou mot suivant l’environnement). L’entrée-sortie est faite soit relativement à la position courante, soit à une position donnée.

Le fichier peut être formaté ou non.

La position courante est mesurée en unités en partant de 1. Le paramètre POS de

l’instruction INQUIRE permet de la connaˆ?tre.

Le paramètre POS (expression entière) des instructions READ/WRITE permet d’indiquer la position dans le fichier à partir de laquelle s’effectuera l’entrée-sortie.

Cette nouvelle méthode d’accès facilite notamment l’échange de fichiers binaires entre Fortran et C.

Note : sous UNIX/LINUX les fichiers ne contiennent pas de marque physique de fin de fichier. C’est une notion purement logique. De ce fait le dernier enregistrement d’un fichier accédé en mode stream est considéré comme incomplet. En conséquence, si on lit plus de données que cet enregistrement n’en contient une fin de fichier sera détecté comme le montre l’exemple suivant :

Contenu supposé du fichier data :

Ce programme produit la sortie suivante :

6.4 – Traitement personnalisé des objets de type dérivé

Au-delà du traitement standard, il devient possible de contrôler les opérations d’entrée-sortie portant sur un objet de type dérivé (public ou semi-privé) via une ou plusieurs procédures de type SUBROUTINE.

Il existe 4 catégories de procédures (lecture/écriture et avec/sans format) qui peuvent être attachées de fac¸on générique (generic bindings) au type dérivé de l’objet via des instructions du type :

GENERIC :: READ(FORMATTED)                       => lecture_format1,                                                                                  lecture_format2

GENERIC :: READ(UNFORMATTED) => lecture_nonformat1, lecture_nonformat2

GENERIC :: WRITE(FORMATTED)                      => ecriture_format1,                                                                                  ecriture_format2

GENERIC :: WRITE(UNFORMATTED) => ecriture_nonformat1, ecriture_nonformat2

insérées au sein de la définition du type comme nous le verrons dans les exemples plus loin.

A droite des flèches, on trouve le nom des procédures qui ser` ont discriminées à la compilation en fonction du type dérivé de l’objet traité et de la valeur effective des sous-types (paramètre KIND) de ses composantes (paramétrables à la déclaration).

Une alternative à l’attachement générique précédent est d’insérer un bloc interface au niveau de la définition du type :

Concernant les entrées-sorties avec format, un nouveau descripteur de format DT a été défini. Il s’applique à un objet de type dérivé de la liste d’entrée-sortie et a pour forme :

La chaˆ?ne de caractères et le tableau d’entiers facultativement indiqués avec ce descripteur sont automatiquement transmis en argument d’entrée de la procédure appelée. Ils sont à la libre disposition du programmeur pour paramétrer le traitement.

Note : toutes ces notions sont repérables dans la documentation anglaise sous les mots-clés dtio-generic-spec et dtv-type-spec.

Ce type de procédures doit respecter le prototype suivant :

SUBROUTINE lecture_format (dtv, unit, iotype, v_list, iostat, iomsg )

                           SUBROUTINE ecrit_nonformat (dtv, unit,                            iostat, iomsg )

dtv : objet de type dérivé qui est à l’origine de l’appel (discriminant en cas d’attachement générique de plusieurs procédures),

unit : numéro de l’unité logique sur laquelle a été connecté le fichier (0 pour un fichier interne),

iotype : chaˆ?ne de caractères indiquée au niveau du descripteur de format DT, v list : tableau d’entiers indiqué au niveau du descripteur de format DT, iostat : reflète en retour l’état de l’entrée-sortie, iomsg : contient en retour le texte d’un message d’erreur si iostat est non nul.

Voici un exemple avec des enregistrements formatés :

MODULE couleur_mod

TYPE couleur

CHARACTER(len=16) :: nom; REAL, DIMENSION(3) :: compos

CONTAINS

PROCEDURE :: ecr_format

GENERIC :: WRITE(FORMATTED) => ecr_format ! <=== Generic binding. END TYPE couleur

CONTAINS

SUBROUTINE ecr_format( dtv, unit, iotype, v_list, iostat, iomsg )

                         CLASS(couleur),                        INTENT(in)              :: dtv

                     INTEGER,                                      INTENT(in)               :: unit

                       CHARACTER(len=*),                   INTENT(in)               :: iotype

                              INTEGER, DIMENSION(:), INTENT(in)                    :: v_list

                     INTEGER,                                             INTENT(out) :: iostat

CHARACTER(len=*), INTENT(inout) :: iomsg CHARACTER(len=10), DIMENSION(2) :: fmt write( fmt(1), ’(a, i2, a)’ ) "(a,3f", v_list(1), ".2)" write( fmt(2), ’(a, i2, a)’ ) "(3f", v_list(1), ".2)"

SELECT CASE( iotype )

CASE (’NAMELIST’)   ; WRITE( UNIT=unit, FMT=* )      dtv%nom, dtv%compos CASE (’LISTDIRECTED’); WRITE( UNIT=unit, FMT=* )  dtv%nom, dtv%compos CASE (’DTCOMPLET’)     ; WRITE( UNIT=unit, FMT=fmt(1) ) dtv%nom, dtv%compos

CASE DEFAULT      ; WRITE( UNIT=unit, FMT=fmt(2) ) dtv%compos END SELECT

END SUBROUTINE ecr_format END MODULE couleur_mod

SUBROUTINE lec_binaire( dtv, unit, iostat, iomsg ) CLASS(couleur), INTENT(inout) :: dtv

                             INTEGER,                                      INTENT(in)               :: unit

                             INTEGER,                                             INTENT(out) :: iostat

                               CHARACTER(len=*),                      INTENT(inout) :: iomsg

READ( UNIT=unit, IOSTAT=iostat, IOMSG=iomsg ) dtv%nom, dtv%compos END SUBROUTINE lec_binaire

Remarque : cette nouveauté permet de bénéficier du concept d’abstraction des données.

Ce module pourra s’employer de la fac¸on suivante :

Note : dans ce dernier exemple, une fin d’enregistrement est générée uniquement lors de l’écriture effectuée au sein du programme principal. Par contre, concernant les écritures de plus bas niveau (à savoir celles effectuées dans la procédure pwf rattachée au type node) une fin d’enregistrement devra être traˆ?tée explicitement. Ce qui explique la présence du caractère «/» dans le format de l’instruction :

WRITE( UNIT=unit, FMT=’(/,dt)’, IOSTAT=iostat ) dtv%next_node

Notes personnelles


7 – Pointeurs

7.1 – Vocation (INTENT) des arguments muets pointeurs

Contrairement à Fortran 95, il est possible de définir la vocation (attribut INTENT) des arguments muets pointeurs au sein d’une procédure. C’est l’association qui est concernée et non la cible.

? INTENT(IN) : le pointeur ne pourra ni être associé, ni mis à l’état nul, ni alloué;

? INTENT(OUT) : le pointeur est forcé à l’état indéfini à l’entrée de la procédure;

? INTENT(INOUT) : le pointeur peut à la fois transmettre une association préétablie et retourner une nouvelle association.

Note : fonctionnalité faisant partie des extensions du compilateur Fortran d’IBM depuis la version 95.

7.2 – Association et reprofilage

Lors de l’association d’un pointeur à une cible il est dorénavant possible :

? d’indiquer un nouveau profil au niveau du pointeur tout en respectant le rang de la cible,

? de modifier de plus le profil uniquement dans le cas d’une cible de rang 1.

! Le sous-programme suivant re´cupe`re un tableau de rang 1 champ_vecteurs ! suppose´ contenir les coordonneés d’une se´rie de vecteurs dans un espace ! a` 3 dimensions.

subroutine sp( champ_vecteurs, n )

real, dimension(:), target :: champ_vecteurs integer        :: n, nb_vecteurs

real, dimension(:,:), pointer :: matrice

nb_vecteurs = size(champ_vecteurs)/3 matrice(1:3,1:nb_vecteurs) => champ_vecteurs

. . .

end subroutine sp

! Sous-programme dans lequel on de´sire avoir une vue matricielle ! du vecteur "vec" puis conside´rer la diagonale de cette matrice.

subroutine sp( nl, nc )

real, dimension(nl*nc), target :: vec real, dimension(:,:), pointer :: matrice real, dimension(:), pointer         :: diag

call random_number( vec )

! matrice( nl, nc ) => vec : INVALIDE matrice( 1:nl, 1:nc ) => vec diag => vec( 1::nl+1 ) end subroutine sp

7.3 – Pointeurs de procédures

Les pointeurs peuvent être associés à des cibles de type procédure. On parlera alors de pointeurs de procédures, assimilables aux pointeurs de fonctions en langage C.

Voici quelques aspects concernant ces pointeurs :

? l’interface peut être implicite ou explicite (cf. ci-après),

? une fonction peut retourner un pointeur de procédure,

? au moment de l’association p => proc d’un pointeur de procédure p à l’aide de l’opérateur classique =>, le compilateur vérifie (si l’interface est explicite) la compatibilité des interfaces procédurales comme pour l’appel classique d’une procédure. L’opérande de droite peut être au choix :

–    une procédure,

–    un pointeur de procédure,

–    une fonction retournant un pointeur de procédure.


7.3.1 – Pointeurs de procédure : interface implicite

Voici trois possibilités de les déclarer en mode d’interface implicite :

? Première possibilité (pour une fonction seulement) avec l’attribut POINTER :

? Deuxième possibilité avec les attributs PROCEDURE() et POINTER; dans l’exemple, p

est un pointeur en mode d’interface implicite, à l’état indéterminé, pouvant être associé à une fonction ou un sous-programme :

? Troisième possibilité (pour une fonction seulement) avec l’attribut PROCEDURE

référenc¸ant un type pour expliciter partiellement un pointeur de fonction en le déclarant par exemple sous la forme :

PROCEDURE(TYPE(obj_mat(k=8, dim=256, d=128))), POINTER :: p

p ne pourra alors être associé qu’à une fonction retournant un objet de type obj mat paramétré comme indiqué (cf. §8.2 - Paramètres d’un type dérivé).

Bien entendu, comme pour les appels de procédures, il est plutôt conseillé d’utiliser le mode d’interface explicite afin que le compilateur puisse contrôler la cohérence des associations de pointeurs de procédures La fiabilité est à ce prix!

Voyons quelles sont les possibilités de les déclarer en mode d’interface explicite.

7.3.2 – Pointeurs de procédure : interface explicite ? Attribut POINTER appliqué à une déclaration de procédure effectuée à l’aide d’un

? Attribut PROCEDURE faisant référence à une procédure modèle existante. Voici par exemple la déclaration de p initialement à l’état nul avec la même interface que celle du sous-programme proc (obligatoirement en mode d’interface explicite) :


? A défaut d’une procédure pouvant servir de modèle pour ex`        pliciter l’interface, il est aussi possible de définir un bloc interface virtuel (abstract interface) comme celui-ci :

Ce bloc interface virtuel peut être utilisé (via l’attribut PROCEDURE) au moment de la déclaration d’un pointeur de procédure comme p1 ou même d’une procédure externe comme proc dans l’exemple ci-dessous :

Notes personnelles

8 – Nouveautés concernant les types dérivés

8.1 – Composante pointeur de procédure

Un pointeur de procédure peut apparaˆ?tre en tant que composante d’un type dérivé.

L’association puis l’appel de la procédure cible s’effectue à partir d’un objet du type dérivé au moyen du symbole % comme pour l’accès aux composantes habituelles.

Par défaut, l’objet qui est à l’origine de l’appel est transmis implicitement comme premier argument à la procédure cible (passed-object dummy argument). L’attribut NOPASS, indiqué lors de la déclaration de la composante, empêche cette transmission implicite : dans ce cas, si on désire transmettre l’objet, on le fera explicitement.

L’attribut PASS peut être indiqué soit pour confirmer le mode par défaut soit pour transmettre implicitement l’objet vers un autre argument que le premier.


8.2 – Paramètres d’un type dérivé

En Fortran 95, les types intrinsèques étaient déjà paramétrables; en particulier le type CHARACTER(LEN= , KIND= ) avait deux paramètres à valeur entière pour spécifier le nombre de caractères et le sous-type.

Nuance importante, le premier n’est pas discriminant pour la généricité et pas doit être connu à la compilation, tandis que le deuxième l’est; Fortran 2003 généralise cette distinction aux paramètres des types dérivés qui pourront être déclarés avec l’attribut LEN ou KIND.

Les paramètres LEN/KIND peuvent être utilisés pour définir la longueur de chaˆ?nes ou les bornes de tableaux, mais seuls ceux ayant l’attribut KIND (dont la valeur doit être connue à la compilation) peuvent intervenir dans une expression d’initialisation ou la valorisation d’un sous-type (kind-selector).

Des valeurs par défaut peuvent être définies.

Voici un exemple de type dérivé paramétrable :

Les paramètres (ici k, dim et d) sont obligatoirement de type entier avec un attribut KIND/LEN.

Seuls ceux ayant l’attribut KIND sont discriminants au niveau de la généricité des fonctions.



Ceux avec l’attribut LEN font partie des length type parameters par opposition aux kind type parameters.

8.3 – Constructeurs de structures

Lors de la valorisation d’un type dérivé via un constructeur de structure, il est désormais possible d’affecter les composantes par mots clés :

Notez aussi la nouvelle notation du constructeur de vecteur encadré par des crochets (au lieu des caractères (/ et /)).

Une procédure générique peut avoir le même nom qu’un constructeur de structure. Les constituants de la famille générique ont priorité sur le constructeur en cas d’ambiguité. Cette technique peut être employée afin de surcharger un constructeur, comme le montre l’exemple suivant :

type(mycomplex) function two_reals_to_mycomplex(x, y) real, intent(in) :: x    !

                                       real, intent(in), optional :: y        !<=== Coordonneés carte´siennes

end function two_reals_to_mycomplex

end interface

. . .

type(mycomplex) :: a, b, c

complex                          :: w

. . .

a    = mycomplex( theta=5.6, rho=1.0 )        ! Appel constructeur intrinse`que

b   = mycomplex( w ) ! Appel a` complex_to_mycomplex

Si une composante d’un type dérivé à une valeur par défaut, l’argument correspondant au niveau du constructeur se comporte comme un argument optionnel.

NOTE : on remarque qu’il est possible d’adresser les composantes d’un type dérivé ayant l’attribut LEN ou KIND à l’aide du symbole %. Ce procédé s’applique également aux types intrinsèques :

Par analogie avec les tableaux à taille implicite (assumed-size-array), lors d’une déclaration, il est possible d’introduire le caractère ? pour les paramètres ayant l’attribut LEN (assumed-type-parameter). Cette forme peut être employée pour un argument muet d’une procédure par exemple :

De même, toujours pour ces paramètres, le caractère

(deffered-type-parameter), comme pour la longueur d’une chaˆ?ne de caractères ou les dimensions d’un tableau :

type(champ_vecteur(k=selected_real_kind(9,99), d=:, n=:)),        pointer :: p type(champ_vecteur(k=selected_real_kind(9,99), d=3, n=200)), target :: cible . . . p => cible

8.4 – Visibilité des composantes

En Fortran 95, un type dérivé pouvait seulement être public, privé ou semi-privé :

En Fortran 2003, la privatisation peut se gérer plus finement au niveau de chaque composante.

Remarque : les identificateurs i et k ne sont accessibles qu’au sein du module m.

8.5 – Extension d’un type dérivé

Un type existant peut être enrichi. Pour cela, on définit un nouveau type en référenc¸ant le type que l’on désire étendre au moyen de l’attribut EXTENDS.

La notation x%base_type%i = pourrait s’avérer utile pour lever une ambigu¨?té d’homonymie de nom de composantes après héritage

Extension d’un type paramétré

Lorsqu’un type paramétré est étendu, le nouveau type hérite des paramètres du type qu’il complète et peut en définir de nouveaux.

Notes personnelles


9 – Programmation orientée objet

9.1 – Variable polymorphique

C’est une variable dont le type peut varier au cours de l’exécution. Celle-ci doit avoir l’attribut POINTER ou ALLOCATABLE ou bien être un argument muet d’une procédure. Pour sa déclaration, on spécifie le mot-clé CLASS à la place de TYPE.

Dans cet exemple, le pointeur p pourra être associé à un objet de type point et à toutes les extensions éventuelles de ce type.

Le type indiqué au niveau du mot-clé CLASS doit forcément être un type dérivé extensible, ce qui exclut les types intrinsèques et les types dérivés pour lesquels on a précisé l’attribut sequence ou bind.

On appelle declared type le type indiqué à la déclaration au moyen du mot-clé CLASS et dynamic type le type réel de l’objet à l’exécution.

9.1.1 – Argument muet polymorphique

Son type dynamique est celui de l’argument réel fourni à l’appel. Cela permet d’appliquer à tous les types étendus une procédure définie pour le type de base. De fac¸on plus générale, voici les règles d’association arguments reéls <==> arguments muets suivant que ceux-ci sont polymorphiques ou non, illustrées à l’aide de l’exemple ci-dessous :


program p

use m

TYPE(point2d) :: A_p2d, B_p2d; CLASS(point2d) :: A_p2d_poly, B_p2d_poly

TYPE(point3d) :: A_p3d, B_p3d; CLASS(point3d) :: A_p3d_poly, B_p3d_poly real distance

! Argument muet polymorphique, argument reél d’un type fixe´ :

distance = distance2d_poly( A_p2d, B_p2d ) %{\overlay{1}\rnode{NodeA}}

distance = distance2d_poly( A_p3d, B_p3d )   ! valide distance = distance3d_poly( A_p2d, B_p2d )   ! invalide distance = distance3d_poly( A_p3d, B_p3d )      ! valide

! Argument muet d’un type fixe´, argument reél polymorphique :

distance = distance2d( A_p2d_poly, B_p2d_poly )   ! valide distance = distance2d( A_p3d_poly, B_p3d_poly )   ! invalide distance = distance2d( A_p3d_poly%point2d, B_p3d_poly%point2d ) ! valide

distance = distance3d( A_p2d_poly, B_p2d_poly )   ! invalide select type( A_p2d_poly ) class is ( point3d ) distance = distance3d( A_p2d_poly, B_p2d_poly ) ! class default

end select

                             distance = distance3d( A_p3d_poly, B_p3d_poly )                       ! valide

! Argument muet et argument reél polymorphiques :

distance = distance2d_poly( A_p2d_poly, B_p2d_poly )   ! valide distance = distance2d_poly( A_p3d_poly, B_p3d_poly )       ! valide distance = distance3d_poly( A_p2d_poly, B_p2d_poly )       ! invalide end program p

9.1.2 – Variable polymorphique : attribut POINTER, ALLOCATABLE

Pointeur polymorphique : variable polymorphique ayant l’attribut POINTER; son type dynamique est celui de sa cible qui peut être définie lors d’une association ou d’une allocation dynamique (ALLOCATE).

De même, le type dynamique d’une variable polymorphique ayant l’attribut ALLOCATABLE est celui fourni lors de son allocation.

TYPE(point2d), target :: p2d

TYPE(point3d), target :: p3d

CLASS(point2d), pointer                               :: ptr2d_1, ptr2d_2

CLASS(point3d), pointer                             :: ptr3d

CLASS(point2d), allocatable :: point

ptr2d_1 => p2d         ! Le type dynamique de ptr2d_1 est TYPE(point2d) ptr2d_2 => p3d  ! Le type dynamique de ptr2d_2 est TYPE(point3d) ptr3d       => p3d       ! Le type dynamique de ptr3d est TYPE(point3d)

ptr2d_2 => ptr2d_1 ! Le type dynamique de ptr2d_2 est celui de ptr2d_1 ptr3d      => ptr2d_1 ! Interdit

ALLOCATE( ptr2d_1 ) ! Alloue un objet de type dynamique TYPE(point2d) ! et associe ptr2d_1 avec.

ALLOCATE( TYPE(point3d)::ptr2d_2 ) ! Alloue un objet de type dynamique TYPE(point3d) ! et associe ptr2d_2 avec. ALLOCATE( TYPE(point3d_coul) :: point )

9.2 – Construction SELECT TYPE

Cette construction permet l’exécution de blocs d’instructions en fonction du type dynamique d’un objet polymorphique.

C’est le type dynamique de l’objet a qui est analysé. La sélection du bloc d’instructions à exécuter se fait d’après les règles suivantes :

? s’il existe une instruction TYPE IS correspondant au type, le bloc qui suit est exécuté,

? sinon, s’il existe une seule instruction CLASS IS répondant au type, le bloc qui suit est exécuté,

? sinon, s’il existe plusieurs instructions CLASS IS correspondant au type, c’est le bloc de l’instruction CLASS IS référenc¸ant le type le plus riche qui est exécuté,

? sinon, s’il existe une instruction CLASS DEFAULT, c’est son bloc qui est exécuté.

9.3 – Pointeurs génériques

Il est possible de définir un pointeur générique ou unlimited polymorphic pointer en précisant le caractère ? à la place du nom du type au niveau du mot-clé CLASS. Celui-ci peut ensuite être associé à tout type de cible.

9.4 – Type effectif d’une variable polymorphique

Deux nouvelles fonctions intrinsèques permettent de déterminer le type d’une variable polymorphique au moment de l’exécution :

Retourne vrai si a et b ont le même type dynamique.

EXTENDS_TYPE_OF( a, mold )

Retourne vrai si le type dynamique de a est une extension de celui de mold.


9.5 – Procédures attachées à un type (type-bound procedures)

Souvent, en programmation orientée objet, on désire appeler une procédure pour effectuer un traitement dont la nature dépend du type dynamique d’un objet polymorphique. Ceci est mis en œuvre au moyen de procédures attachées à un type dérivé (type-bound procedures) qui récupèrent en entrée l’objet à l’origine de l’appel défini comme argument muet polymorphique. Celles-ci peuvent faire l’objet d’une surcharge lors d’extensions du type.

Dans d’autres langages comme C++ on les appelle des méthodes ou services; leur invocation est vue comme l’envoi d’un message à un objet dont la nature peut être résolue à l’exécution (polymorphisme dynamique) ou à la compilation (polymorphisme statique).

Ce type de procédure peut évidemment s’employer pour un type dérivé simple non

étendu.

Elles doivent être définies en contexte d’interface explicite.

9.5.1 – Procédure attachée par nom (name binding)
9.5.3 – Procédure attachée par opérateur (operator binding)

function add8( a, b ) class(matrix(k=8, n=*, m=*), intent(in) :: a, b type(matrix(k=8, n=a%n, m=a%m)      :: add8 ! "type" et non "class". if( shape(a%A) /= shape(b%A) ) stop "Erreur : objets non conformants" add8%A(:,:) = a%A(:,:) + b%A(:,:)

end function add8

!--------------------------------subroutine affect4( a, b )

class(matrix(k=4, n=*, m=*), intent(inout) :: a class(matrix(k=4, n=*, m=*), intent(in) :: b if( shape(a%A) /= shape(b%A) ) stop "Erreur : objets non conformants" a%A(:,:) = b%A(:,:)

end function affect4

!--------------------------------subroutine affect8( a, b )

class(matrix(k=8, n=*, m=*), intent(inout) :: a class(matrix(k=8, n=*, m=*), intent(in) :: b if( shape(a%A) /= shape(b%A) ) stop "Erreur : objets non conformants" a%A(:,:) = b%A(:,:)

end function affect8 end module m

9.5.4 – Procédure attachée via le mot-clé FINAL (final binding)

C’est une procédure de type subroutine qui s’exécute lorsqu’un objet cesse d’exister. Pour cela, au sein du type dérivé correspondant à l’objet, on spécifie le mot-clé FINAL auquel on associe une liste de sous-programmes (final subroutines) appelés destructeurs.

Ceux-ci admettent un seul argument muet du type de celui défini.

Pour un objet alloué dynamiquement à l’aide de l’instruction ALLOCATE, le destructeur est appelé au moment de sa désallocation effectuée au moyen de l’instruction DEALLOCATE.

Pour un objet automatique, le destructeur est appelé lorsque l’unité de programme, au sein de laquelle l’objet est défini, est désactivée.

Ainsi, lors de la désallocation de l’objet obj déclaré ainsi : type(t(k=4)), dimension(:), allocatable :: obj c’est le destructeur finalize vect qui sera exécuté.

9.6 – Héritage

9.6.1 – Héritage d’une procédure type-bound

Un type étendu d’un type extensible hérite à la fois de ses composantes mais également de ses procédures type bound.

Voici un exemple d’héritage de procédure (ici affichage) :

9.6.2 – Surcharge d’une procédure type-bound

Lors de la définition d’un type étendu d’un type extensible il est possible d’étendre ou surcharger (override) les procédures type bound.

Dans les exemples précédents, les objets à partir desquels les procédures type bound sont appelées sont d’un type fixé : le compilateur sait alors quelle procédure appeler.

Si l’on désire bénéficier du polymorphisme dynamique, on déclare l’objet p de l’exemple précédent comme argument muet polymorphique. Cela permet d’appeler la procédure affichage correspondant au type dynamique de l’objet qui est à l’origine de

l’appel.

La fonction affiche s’appliquera alors à tout nouveau type étendu ultérieurement défini sans avoir à la recompiler.

9.6.3 – Procédure type-bound non surchargeable

L’attribut NON OVERRIDABLE à la déclaration d’une procédure type-bound permet d’interdire toute surcharge lors d’extensions éventuelles de ce type.


9.7 – Type abstrait

C’est un type qui sert de base à de futures extensions. Parmi les procédures qui lui sont attachées certaines peuvent être déclarées avec l’attribut DEFERRED indiquant qu’elles seront définies au sein de types étendus. La définition d’un type abstrait s’effectue en précisant le mot-clé ABSTRACT.

Il n’est pas possible de déclarer des objets de ce type. Par contre, celui-ci peut être utilisé pour la déclaration de variables polymorphiques.

L’extension d’un tel type peut se faire au moyen d’un type étendu normal ou d’un nouveau type abstrait.


10 – En conclusion

10 – En conclusion

? La phase d’élaboration technique de la norme Fortran 2003 est terminée ainsi que la phase ISO FCD (Final Committee Draft) dont le document

ISO-IEC/JTC1/SC22/WG5/N1578 (draft 04-007) est consultable en ligne à l’adresse :

à la rubrique Fortran 2003.

? La norme Fortran 2003 est désormais officielle depuis septembre 2004.

? En attendant l’arrivée des premiers compilateurs Fortran 2003, certains fournisseurs comme IBM, Nec, Nag, N.A. Software, intègrent progressivement certains aspects de cette norme.


Index

– Symboles –

type-bound procedure : : generic binding .153 type-bound procedure : : name binding ..152 type-bound procedure : : operator binding 154 type-bound procedure ..151

– A –

ABSTRACT INTERFACE .124, 127 ACCESS - STREAM .. 105 adresse cible : C LOC(X) ..20 affectation et allocation automatique . 90, 91

ALLOCATABLE . 85 allocatable . 45 ALLOCATABLE - argument de procédure 86 ALLOCATABLE - composante type dérivé .. 88 ALLOCATABLE - scalaire .89

ALLOCATABLE : argument INTENT(OUT) 87

ALLOCATABLE : argument SAVE . 87

allocation via affectation .. 90

argument de procédure : ALLOCATABLE 86 arguments - ligne de commande . 11 arrondi ..58 association : pointeur de procédure 119

asynchrones - E./S. 102

ASYNCHRONOUS .102

– B –

BIND(C) .. 18, 22, 23, 45, 46, 50 bloc interface : IMPORT .. 96 bound procedure - surcharge 161

– C –

C ALERT .. 15 C ASSOCIATED . 21 C BACKSPACE ..15 C CARRIAGE RETURN .. 15 C CHAR 14 C DOUBLE 14 C F POINTER 47 C F PROCPOINTER 21 C FLOAT .. 14 C FORM FEED ..15 C FUNLOC 21 C FUNPTR 21, 45 C HORIZONTAL TAB . 15 C INT 14 C LOC .20, 21, 47 C LONG 14 C NEW LINE . 15 C NULL CHAR .. 15 C PTR .. 19–21, 45, 46, 50 C SHORT ..14 C VERTICAL TAB ..15 calloc 48, 51 CHARACTER : interopérabilité . 14 CLASS .141

CLASS() ..161 CLOSE .102

COMMAND ARGUMENT COUNT .11 common : interopérabilité . 18 composante ALLOCATABLE : destructeur .. 87 constructeur de type dérivé . 130

– D –

dénormalisée .. 58 declared type .141

descripteur .85

descripteur de format DT 107

destructeur : composante ALLOCATABLE .. 87

destructeur type dérivé 157

division par zéro . 57 DT - descripteur format ..107 dtio-generic-pec .107 dynamic type .141

– E –

Entrées/sorties ..102 environnement .11 environnement - variables d’ ..12 ERROR UNIT .12 EXTENDS() . 161

EXTENDS TYPE OF . 149

– F –

FINAL .157

final subroutine .. 87 fonction C 47, 48, 51

– G –

GENERIC .153 GENERIC : : ASSIGNMENT 156 GENERIC : : OPERATOR .. 156 generic binding ..106 generic binding : type dérivé 153 GET COMMAND 11 GET COMMAND ARGUMENT . 11

GET ENVIRONMENT VARIABLE .11

– H –

héritage - procédure 160

– I –

IEEE ALL 67, 70–72 IEEE ARITHMETIC 59 IEEE CLASS ..62 IEEE CLASS TYPE .64

IEEE DIVIDE BY ZERO . 66, 70 IEEE EXCEPTIONS 59 IEEE FEATURES 59 IEEE GET FLAG .. 68, 70 IEEE GET HALTING MODE 70

IEEE GET ROUNDING MODE . 65

IEEE GET STATUS .72

IEEE GET UNDERFLOW MODE(gradual) ..69 IEEE INEXACT .66, 68 IEEE INVALID 66 IEEE IS FINITE . 62 IEEE IS NAN . 62 IEEE IS NEGATIVE 62 IEEE IS NORMAL .. 62 IEEE NEGATIVE DENORMAL 61, 64 IEEE NEGATIVE INF .61, 64 IEEE NEGATIVE NORMAL .61, 64 IEEE NEGATIVE ZERO . 61, 64

IEEE OTHER VALUE ..61 IEEE OVERFLOW ..66

IEEE POSITIVE DENORMAL . 61, 64

IEEE POSITIVE INF ..61, 64

IEEE POSITIVE NORMAL ..61, 64

IEEE POSITIVE ZERO .. 61, 64

IEEE QUIET NAN ..61 IEEE ROUND VALUE . 65 IEEE SET FLAG .68 IEEE SET HALTING MODE .70

IEEE SET ROUNDING MODE ..65

IEEE SET STATUS . 72

IEEE SET UNDERFLOW MODE(gradual) ..69 IEEE SIGNALING NAN 61

IEEE STATUS TYPE .. 72

IEEE SUPPORT DATATYPE 60, 64

IEEE SUPPORT DENORMAL .. 60 IEEE SUPPORT INF 60 IEEE SUPPORT NAN ..60 IEEE SUPPORT STANDARD 60 IEEE UNDERFLOW 66

IEEE UP 65 IEEE USUAL . 67 IEEE VALUE .62, 64 IMPORT : bloc interface .. 96

INPUT UNIT . 12

INQUIRE . 105

INTENT - pointeur 116

INTENT(OUT) : argument ALLOCATABLE 87

interface implicite ..120

Interface procédure Fortran .. 22 interopérabilité Fortran-C 13, 18 IOSTAT .12 IOSTATEND . 12 IOSTATEOR . 12 iso-IEC-1539 .2 ISO C BINDING 13, 20, 45 ISO FORTRAN ENV 12

– K –

KIND : paramètre type dérivé 128, 129 kind type parameters ..129

– L –

LEN : paramètre type dérivé . 128, 129 length type parameters 129

ligne de commande : arguments ..11

– M –

module : importation d’entités .. 96 module : protection d’entités . 95 module : renommage d’opérateurs .. 97 module : USE . 97

MOVE ALLOC 93

– N –

NAME= 22, 23 NaN .56, 57

NON OVERRIDABLE .163

– O –

opérateur : renommage via USE . 97 operator binding : type dérivé ..156 OPERATOR() .97 OUTPUT UNIT ..12 overflow .57 override - type bound procedure 161

– P –

paramètres d’un type dérivé .128

PASS, NOPASS . 126 POINTER ..85 pointer : interopérabilité .. 19 pointeur .85

pointeur - procédure .. 126

pointeur - reprofilage ..118 pointeur : vocation .116 pointeur C : valeur ..20 pointeur de procédure 21, 119–121, 124

pointeur de procédure : association 119

pointeur générique . 148

pointeur polymorphique ..145

pointeurs : interopérabilité 19

polymorphique - pointeur 145

polymorphisme ..162

POS - READ/WRITE .105 PRIVATE - type dérivé 135 procédure .. 23

procédure - pointeur .. 126

procédure : pointeur .21 procédure : pointeur de ..119–121, 124 PROCEDURE : attribut .120, 121, 124

PROCEDURE() - attribut pointeur .. 124

PROTECTED .95

PUBLIC - type dérivé .135

– R –

réallocation et affectation automatique .. 90, 91 réallocation via affectation 90 READ ..102 reprofilage et association .118

– S –

SAME TYPE AS .149, 150 SAVE : argument ALLOCATABLE . 87 scalaire : ALLOCATABLE .89 SELECT TYPE .. 146, 150 select type 146

standard IEEE 56, 57 STREAM - ACCESS .. 105 struct 45 structure : interopérabilité 46, 50

structure C .45

surcharge - type bound procedure . 161

– T –

tableau dynamique .. 85 tableaux : interopérabilité .18 tableaux dynamiques 90

toward +? .58

toward ?? 58

toward nearest 58

toward zero 58

traitement des interruptions ..70

traitement exception 68 type bound procedure .160 type dérivé .45 type dérivé : composante ALLOCATABLE ..87, 88 type dérivé : constructeur 130 type dérivé : destructeur . 157

type dérivé : E./S. .. 106, 107 type dérivé : GENERIC .. 106 type dérivé : generic binding 153 type dérivé : operator binding ..156 type dérivé : paramètre KIND 128, 129 type dérivé : paramètre LEN . 128, 129

type dérivé : paramètres ..128

type dérivé : PRIVATE 135

type dérivé : PUBLIC .135

type dérivé : visibilité .135

TYPE IS ..150

typedef ..45 typedef struct 48, 51

– U –

underflow ..57, 58 USE - module, renommage opérateur .. 97

– V –

valeurs spéciales .56, 57 VALUE .46, 50 VALUE : attribut 22, 23 variable d’environnement ..12 variable polymorphique 141 variable polymorphique : ALLOCATABLE ..145

variable polymorphique : argument muet 144

variable polymorphique : POINTER ..145

visibilité : type dérivé .135 void ..23

– W –

WAIT ..102 Working draft 2, 169 WRITE 102



165