Fortran90 PDF PDF
Fortran90 PDF PDF
Fortran90 PDF PDF
Notes de Cours
Novembre 2021
Ces notes constituent le document du cours intitulé “Fortran 90 et programmation numérique”
dispensé aux étudiants de 3A GMM (première année du cycle ingénieur de la filière Génie
Mathématique et Modélisation) de Polytech Clermont-Ferrand.
Ce cours ne prétend pas présenter aux étudiants l’ensemble des possibilités offertes par le fortran
90, mais se concentre sur les aspects les plus intéressants pour la programmation numérique.
Les séances de Travaux Pratiques qui accompagnent ce cours permettent aux étudiants d’implé-
menter des algorithmes élémentaires d’analyse numérique, tels que les résolutions de systèmes
linéaires par des méthodes directes et itératives, la méthode de Newton-Raphson pour la résolution
de problèmes non linéaires, les méthodes de recherche de valeurs propres, d’orthogonalisation, ...
Bien que le fortran 90 soit quasiment “machine-indépendant”, certains résultats (messages d’er-
reurs à la compilation, erreurs suite aux “débordements de tableaux”, ...) dépendent de la
machine sur laquelle on travaille. Il est donc possible d’observer des comportements différents
de ceux présentés dans ces notes.
Ces notes peuvent être téléchargées à l’adresse :
http://math.univ-bpclermont.fr/∼bouchon/HTML POLYTECH/Doc/fortran90 pdf.pdf
où elles sont régulièrement mises à jour.
Chapitre 1: Introduction.
Chapitre 3: Tableaux.
3.1 Déclaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.1.1 Tableaux monodimensionnels (“vecteurs”) . . . . . . . . . . . . . . . . . . . . . . . . . . . .21
3.1.2 Tableaux multi-dimensionnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2 Utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.2.1 Opérations sur chaque élément . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.2.2 Opérations globales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.2.3 Opérations sur des “sous-tableaux”. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.3 Allocation dynamique de la mémoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.4 Fonctions intrinsèques travaillant sur les tableaux. . . . . . . . . . . . . . . . . . . . . .29
ii Plan
6.1 Pointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
6.1.1 Principe. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
6.1.2 Pointeurs et cibles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
6.1.3 Pointeurs et tableaux, allocation dynamique. . . . . . . . . . . . . . . . . . . . . . . . . . 53
6.2 Types dérivés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.2.1 Principe, exemple. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.2.2 Types dérivés et allocation dynamique. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Bibliographie.
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 1
Chapitre 1: Introduction.
Un ordinateur (ou “une machine” ) est un dispositif permettant le traitement rapide et précis
d’informations symboliques stockées sous forme d’instructions appelées un programme.
rechercher les informations nécessaires pour ce traitement, les envoyer à l’unité arithmétique
qui exécute les différents calculs,
récupérer les résultats de chaque calcul à partir de l’unité arithmétique et les stocker dans
la mémoire,
...
La mémoire permet le stockage des programmes et des informations. Elle se compose d’un
ensemble d’unités de stockage appelées les mots (en anglais “word”, d’où les unités MW :
Méga-Word, ...), chaque word est caractérisé par son adresse mémoire.
Chaque word contient une série d’éléments de stockage, qui peuvent contenir deux états (conven-
tionnellement désignés par 0 et 1). Toute information élémentaire est donc stockée sous forme
binaire.
Lorsqu’un programme est exécuté, les instructions sont recherchées et traitées dans l’ordre où
elles sont stockées en mémoire. Il est possible d’effectuer des branchements, c’est-à-dire de
demander à l’unité de contrôle d’aller chercher l’instruction suivante à une adresse déterminée.
Il est également possible d’effectuer des boucles, c’est-à-dire de demander à l’unité de contrôle
d’exécuter plusieurs fois une série d’instructions,...
Pour être exécutable , un programme doit être écrit dans le code machine binaire compris par
le processeur (en “langage machine”). Le programme en langage machine est indéchiffrable pour
l’utilisateur : l’édition d’un exécutable en mode texte donne une série de caractères spéciaux
incompréhensibles.
En outre, chaque type de processeur reconnaı̂t un certain type de langage.
Un programme écrit pour un type de processeur n’est pas exécutable par un autre.
Aujourd’hui, la plupart des programmes sont écrits en langages de niveau élevé .
Ces langages ressemblent à de l’anglais et sont donc plus faciles à manipuler que le langage
machine.
2 Chapitre 1: Introduction
Fortran (de l’anglais FORmula TRANslation), est né au milieu des années 1950. C’était le
premier langage de niveau élevé.
En fortran 90, les instructions sont écrites dans un fichier dont l’extension est “f90”, (par
exemple : toto.f90), la commande de compilation sur un système Unix est généralement
> f90 toto.f90
Cette commande demande à la machine d’effectuer les opérations suivantes :
• tester la cohérence du code : le compilateur renvoie à l’écran des messages d’erreurs lorsque
les règles du fortran 90 ne sont pas respectées. (Ces messages d’erreurs ne sont pas toujours
très explicites, mais ils contiennent systématiquement les numéros des lignes du fichier où
apparaissent les erreurs),
Une fois la compilation achevée (avec succès), on peut exécuter le code par la commande
> ./a.out
La machine exécute alors les instructions du fichier a.out, ces instructions sont directement
comprises par les processeur et correspondent aux instructions du code source toto.f90.
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 3
• Le programme commence par l’instruction : PROGRAM EXEMPLE1 et s’achève par END PROGRAM
EXEMPLE1. Ceci est indispensable. Naturellement, on peut modifier le nom du programme
(ici EXEMPLE1), mais la dernière instruction doit reprendre le même nom que la première.
• Juste après l’instruction PROGRAM EXEMPLE1, on “déclare” les différentes variables qui vont
être utilisées dans le code.
INTEGER :: indique que l’on va utiliser trois variables, nommées A,B et C, qui seront
A,B,C
toutes les trois de type “INTEGER”, c’est à dire de type entier.
• Les instructions suivantes sont quasiment écrites en anglais.
PRINT*, demande l’affichage à l’écran de données (ici une chaı̂ne de caractères et l’entier C
un peu plus loin dans le code),
READ*,demande la lecture au clavier d’une donnée. La variable qui suit cette instruction
prendra la valeur qui sera saisie au clavier lors de l’exécution.
• Suivent trois instructions correspondant à des calculs et affectations, ainsi que trois af-
fichages à l’écran.
L’instruction C=A+B demande à la machine d’évaluer la somme des variables entières A et B,
et de stocker le résultat dans la variable C.
Ensuite, l’instruction C=A-B permettra d’évaluer la différence A-B et modifiera la valeur de
la variable C lui affecter la valeur du résultat de ce calcul.
De même pour l’instruction C=A*B...
Exemple d’exécution :
TAPER AU CLAVIER LA VALEUR DE A
8
TAPER AU CLAVIER LA VALEUR DE B
3
LA VALEUR DE C=A+B EST 11
LA VALEUR DE C=A-B EST 5
LA VALEUR DE C=A*B EST 24
4 Chapitre 1: Introduction
Inversement, il est possible de mettre sur une même ligne plusieurs instructions, séparées par des
“;” :
Ainsi,
A=0
B=0
est équivalent à :
A=0 ; B=0
Indentation :
Contrairement au fortran 77, le format est libre en fortran 90. Chaque ligne peut être écrite
indifféremment à partir de la première colonne, deuxième colonne, ou plus loin encore.
Cela dit, pour faciliter la lecture du code, on respecte généralement des règles d’indentation. Il
s’agit de décaler une ou plusieurs instructions vers la droite, dans certains cas.
Les exemples de codes donnés dans ce polycopié respectent ces règles, notamment pour les boucles
et tests qui seront vus au chapitre 2.
La déclaration d’une variable se fait de la manière suivante (pour l’instant... on verra d’autres
manières de déclarer des données par la suite) :
<TYPE> :: <Nom variable>
où <TYPE> doit être l’un des types énumérés dans cette section, et où <Nom variable> doit être
le nom de la variable.
La présence des :: est souvent facultative; cela dit, comme elle est obligatoire dans certains
types de déclaration, il est de coutume de les mettre systématiquement.
Le nom de la variable doit obéir aux règles suivantes :
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 5
• Le nom ne doit pas commencer par un chiffre, et ne doit pas contenir de caractère spécial,
sauf (“underscore”) qui est autorisé.
Il est de bon goût de choisir comme nom de variable dans un code un nom suffisamment explicite
pour faciliter la lecture du code.
exemples :
• Il serait malheureux de donner x comme nom à une variable correspondant à un temps, ...
Il est prudent de faire précéder toutes les déclarations par l’instruction IMPLICIT NONE. Ceci indique
au compilateur que l’on s’interdit de faire référence à des variables non déclarées. La compilation
serait alors interrompue avec affichage d’un message d’erreur dans le cas où l’on aurait tenté
d’utiliser une variable non déclarée.
Si l’on ne fait pas précéder les déclaration par IMPLICIT NONE, le compilateur attribue de lui-
même un certain type aux variables qui ne seraient pas déclarées, ce qui pourrait conduire à des
erreurs...
Une variable de type caractère - appelé parfois aussi chaı̂ne de caractère - (en anglais : “CHAR-
ACTER” et “STRING”) est une succession de symboles qui peuvent être : des lettres majuscules
ou minuscules, des chiffres, des “caractères spéciaux” (espace, -*+,;.&# ...)
Les éléments de ce type sont des nombres entiers, dont la valeur absolue est limitée par une
valeur qui dépend du nombre d’octets utilisés pour les stocker.
Si l’entier est “simple précision” (c’est à dire : déclaré par INTEGER ou INTEGER*4), alors il est
stocké sur 4 octets, c’est à dire sur 32 bits.
L’un des bits correspond à son signe + ou −, les 31 autres permettent de définir la valeur absolue
de l’entier.
L’entier est donc compris entre ±(231 − 1), c’est à dire entre −2147483647 et +2147483647.
Si l’entier est “double précision” (c’est à dire : déclaré par INTEGER*8), alors il est stocké sur 8
octets, c’est à dire sur 64 bits.
L’un des bits correspond à son signe + ou −, les 63 autres permettent de définir la valeur absolue
de l’entier.
6 Chapitre 1: Introduction
L’entier est donc compris entre ±(263 − 1), c’est à dire entre
−9223372036854775807 et 9223372036854775807.
Les éléments de ce type sont des nombres qui peuvent avoir une “partie décimale”.
Tout nombre x ∈ R non nul peut s’écrire de manière unique sous la forme : x = εm × 10e , où :
• ε = ±1 correspond au signe,
• 1 ≤ m < 10,
• e ∈ Z.
Le mode de stockage d’un réel sur machine s’inspire de cette idée, mais en base 2 :
Tout nombre x ∈ R peut s’écrire (pas de manière unique) sous la forme : x = εm × 2e , où :
• ε = ±1 est le signe,
• e ∈ Z est l’exposant.
Si le réel est “simple précision” (c’est à dire : déclaré par REAL ou REAL*4), alors il est stocké sur
4 octets, c’est à dire sur 32 bits.
La précision relative en simple précision est la différence relative entre deux valeurs voisines
de la mantisse.
Elle est donc de 2−22 , c’est à dire de l’ordre de 2.3841857 × 10−7 .
Si le réel est “double précision” (c’est à dire : déclaré par REAL*8), alors il est stocké sur 8 octets,
c’est à dire sur 64 bits.
Les 11 bits suivants correspondent à l’exposant. Cet exposant peut donc prendre 211 = 2048
valeurs différentes, qui sont les entiers allant de −1024 à +1023 inclus.
Les 52 bits restants servent à stocker la mantisse, comprise entre 0 et 1.
Le plus grand réel stockable ainsi est donc rmax = 1 × mmax × 21023∼< 21023 ≈ 8.98846567431158 ×
10307 .
Le plus petit est son opposé (−8.98846567431158 × 10307 ).
La précision relative est donc ici de 2−52 , c’est à dire de l’ordre de 2.220446 × 10−16 .
Un élément de type COMPLEX est un couple de réels. Il nécessite donc deux fois plus d’espace
mémoire qu’un réel.
Ainsi, un élément déclaré par COMPLEX ou COMPLEX*8 est stocké sur huit octets, soit deux réels
simple précision, et un élément déclaré par COMPLEX*16 est stocké sur seize octets, soit deux réels
double précision.
Un élément booléen (ou logique) peut prendre deux valeurs appelées conventionnellement VRAI
et FAUX (ou + et -, ou 0 et 1, ...) .
Il est bien sûr codé sur 1 bit.
g. Paramètres.
Les déclarations que nous avons vues jusqu’à présent permettent de déclarer des variables pro-
prement dites, ce qui signifie que l’on peut non seulement utiliser leurs valeurs “en lecture” mais
aussi les modifier.
Il est possible de déclarer des paramètres, dont la valeur ne pourra pas être modifiée par
l’exécution du code.
La déclaration se fait de la manière suivante :
INTEGER, PARAMETER :: N=10
(la présence des :: est indispensabledans ce cas), N est alors un élément ENTIER, dont la valeur
reste obligatoirement égale à 10 dans toute l’exécution du code.
Si l’on tente de modifier cette valeurs par une affectation de la forme N=..., on aura une erreur
à la compilation.
Nous verrons par la suite (au chapitre 3) quel peut être l’intérêt de déclarer des paramètres plutôt
que des variables.
Lorsqu’on déclare une variable, fortran 90 lui attribue une valeur “par défaut”. Par exemple,
pour un élément de type numérique, fortran 90 attribue par défaut la valeur 0.
8 Chapitre 1: Introduction
Il est possible de donner une valeur différente au moment de la déclaration, ceci se fait de la
manière suivante :
REAL :: A=3.5
(la présence des :: est indispensable dans ce cas), A est alors un élément de type réel, qui vaut
3.5 au début du code.
Contrairement aux paramètres, une variable déclarée ainsi peut être modifiée dans la suite du
code.
a. Opérateurs
Les opérateurs correspondent aux différentes opérations arithmétiques que sait faire fortran 90.
Il y a des opérateurs destinés aux types numériques (INTEGER, REAL et COMPLEX), ces opérateurs
sont + , - , * , / et ** (qui correspond à la “puissance”).
D’autres sont destinées au type booléen (les opérateurs .AND. , .OR.).
Un opérateur numérique travaille sur la variable qui le précède et celle qui le suit, et transforme
l’expression en une variable du même type.
Si les types des arguments sont différents, le résultats sera du type “le moins inclusif”. COMPLEX
est moins inclusif que REAL qui est moins inclusif que INTEGER.
exemples :
3.0 + 0.26 correspondra au réel 3.26
7 / 2 correspondra à l’entier 3
3 * 0.25 correspondra au réel 0.75
Dans les expressions ci dessus, un élément affiché sans partie décimale désigne un élément de
type ENTIER. 3 n’est donc pas le même objet que 3.0.
L’ordre de priorité d’exécution des différentes opérations est dicté soit par le parenthésage, soit
par les règles usuelles de l’arithmétique.
Ainsi :
3 * ( 7 + ( 1.0 + 2 / ( 1 + 5 ) ) + 3 / ( 2 + 4.0 ) ) = 3 * ( 7 + ( 1.0 + 2 / 6 ) + 3 / 6.0 )
= 3 * ( 7 + ( 1.0 + 0 ) + 0.5 ) = 3 * ( 7 + 1.0 + 0.5 ) = 3 * 8.5 = 25.5
Il est naturellement possible d’effectuer ce type d’opération avec des variables déclarées en entête,
le résultat dépendra de la valeur que contient la variable au moment précis où est effectuée
l’opération.
Il existe aussi des opérateurs dont le résultat n’est pas de même type que les données, c’est
notamment le cas des opérateurs de tests, dont les résultats sont booléens.
Ces opérateurs sont .EQ. (teste l’égalité), .NE. (inégalité), .GT. (strictement supérieur), .GE.
(supérieur ou égal), .LT. (strictement inférieur), .LE. (inférieur ou égal).
Exemples :
7.GT.2 donne le booléen .TRUE. ,
3 * ( 7 + ( 1.0 + 2 / ( 1 + 5 ) ) + 3 / ( 2 + 4.0 ) ) .LT. 20.0 = ... = 25.5 .LT. 20.0 = .FALSE.
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 9
b. Affectations
Une affectation consiste à attribuer (éventuellement modifier) la valeur contenue dans une vari-
able.
La syntaxe est : (variable) = (expression)
Dans le programme donné en exemple (section 1.2.1), les affectations C=A+B, C=A-B, C=A*B modifient
successivement la valeur numérique de la variable entière C.
Les valeurs numériques des variables A et B ne sont pas modifiées car ces variables n’apparaissent
qu’à droite du signe égal: on dit que ces deux variables sont utilisées ici en lecture.
Nous verrons dans la suite de ce cours qu’il existe d’autres moyens de modifier les valeurs des
différentes variables.
Dans le cas où les types à gauche et à droite du signe égal ne sont pas les mêmes, l’affectation
se fait après une conversion.
Exemples
Supposons différentes variables aient été déclarées de la manière suivante :
INTEGER :: I
REAL :: A,B
L’instruction
I=3.6
est correcte, 3.6 est converti à l’entier inférieur le plus proche, I prendra donc la valeur 3.
L’instruction
A=I+2
est correcte, elle évalue l’expression entière 3+2, obtient donc l’entier 5. Cet entier est ensuite
converti en réel, A prend donc la valeur 5.0 .
Attention !!!
L’instruction
B=3/4
est correcte, elle évalue l’expression entière 3/4, obtient donc l’entier 0. Cet entier est ensuite
converti en réel, B prend donc la valeur 0.0 et non pas 0.75 !!!
Beaucoup d’erreurs proviennent de l’oubli de cette règle.
Ce paragraphe a pour objet de présenter les différentes syntaxes possibles pour coder les tests
en fortran 90.
PROGRAM EXEMPLE2 1
REAL :: A,B
PRINT*, ’ENTRER LA VALEUR DU REEL A’
READ*, A
Exemple : PRINT*, ’ENTRER LA VALEUR DU REEL B’
READ*, B
IF (A.GT.B) PRINT*, ’A EST STRICTEMENT PLUS GRAND QUE B’
END PROGRAM EXEMPLE2 1
Il est possible d’utiliser une structure “bloc d’instructions” pour ce type de test. Ceci est
nécessaire dans le cas où l’on a plusieurs instructions conditionnées par le résultat du test :
PROGRAM EXEMPLE2 2
REAL :: A,B
PRINT*, ’ENTRER LA VALEUR DU REEL A’
READ*, A
PRINT*, ’ENTRER LA VALEUR DU REEL B’
READ*, B
Exemple : IF (A.GT.B) THEN
PRINT*, ’A EST STRICTEMENT PLUS GRAND QUE B’
PRINT*, ’A=’,A
PRINT*, ’B=’,B
END IF
END PROGRAM EXEMPLE2 2
Les instructions comprises entre les instructions IF et END IF ne sont exécutées que si le booléen
suivant IF a la valeur .TRUE. .
On observera que l’on a respecté les règles d’indentation : le bloc d’instructions compris entre
les instructions IF et END IF a été décalé de quelques caractères (deux ou trois en général) vers
la droite.
La structure bloc IF - THEN - (ELSE IF) - ELSE - END IF permet de traiter certaines instructions
ou d’autres en fonction de la valeur d’une ou plusieurs variables booléennes.
PROGRAM EXEMPLE2 3
REAL :: A,B
PRINT*, ’ENTRER LA VALEUR DU REEL A’
READ*, A
PRINT*, ’ENTRER LA VALEUR DU REEL B’
READ*, B
IF (A.GT.B) THEN
PRINT*, ’A EST STRICTEMENT PLUS GRAND QUE B’
Exemple : PRINT*, ’A=’,A
PRINT*, ’B=’,B
ELSE IF (A.EQ.B) THEN
PRINT*, ’A ET B SONT EGAUX !!!’
ELSE
PRINT*, ’B EST STRICTEMENT PLUS GRAND QUE A’
END IF
END PROGRAM EXEMPLE2 3
donne à l’exécution :
ENTRER LA VALEUR DU REEL A
3 ENTRER LA VALEUR DU REEL A ENTRER LA VALEUR DU REEL A
ENTRER LA VALEUR DU REEL B 2 -2
1 ENTRER LA VALEUR DU REEL B ENTRER LA VALEUR DU REEL B
A EST STRICTEMENT PLUS GRAND QUE B 2 3
A= 3.0 A ET B SONT EGAUX !!! B EST STRICTEMENT PLUS GRAND QUE A
B= 1.0
On peut insérer autant de ELSE IF que l’on veut.
Dès que l’un des booléens a la valeur .TRUE., la série d’instructions qui suit le test correspondant
est exécutée, puis on passe directement au END IF sans tester les autres booléens !
Les boucles sont des séries d’instructions amenées à être exécutées plusieurs fois consécutivement.
Il existe deux principaux types de boucles : les boucles indexées et les boucles dites “DO WHILE”.
Une boucle indexée est une série d’instructions qui vont être exécutées un certain nombre de
fois, mais pour lesquelles une certaine variables (l’index de la boucle) prendra successivement des
valeurs différentes, ces valeurs étant déterminées par les éléments suivant l’instruction DO.
PROGRAM EXEMPLE2 4
I A LA VALEUR 1
INTEGER :: I
I A LA VALEUR 2
DO I = 1,5
Exemple : PRINT*, ’I A LA VALEUR’,I donne à l’exécution : I A LA VALEUR 3
I A LA VALEUR 4
END DO
I A LA VALEUR 5
END PROGRAM EXEMPLE2 4
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 13
ici encore on respecte les règles d’indentation : le bloc d’instructions compris entre les instructions
DO et END DO est décalé de quelques caractères vers la droite.
Pour cet exemple, I prend successivement toutes les valeurs entières de 1 à 5 inclus.
Il est possible d’imposer un incrément, c’est-à-dire de “sauter” certaines valeurs pour l’index I :
PROGRAM EXEMPLE2 5
INTEGER :: I
I A LA VALEUR 1
DO I = 1,5,2
Exemple : PRINT*, ’I A LA VALEUR’,I donne à l’exécution : I A LA VALEUR 3
I A LA VALEUR 5
END DO
END PROGRAM EXEMPLE2 5
PROGRAM EXEMPLE2 6
INTEGER :: I
DO I = 1,5,3 I A LA VALEUR 1
Exemple : PRINT*, ’I A LA VALEUR’,I donne à l’exécution : I A LA VALEUR 4
END DO
END PROGRAM EXEMPLE2 6
PROGRAM EXEMPLE2 7
INTEGER :: I
I A LA VALEUR 5
DO I = 5,1,-2
Exemple : PRINT*, ’I A LA VALEUR’,I donne à l’exécution : I A LA VALEUR 3
I A LA VALEUR 1
END DO
END PROGRAM EXEMPLE2 7
Ainsi, une boucle codée DO I=A,B,C ... END DO exécutera les instructions délimitées entre le DO
et le END DO avec comme valeurs de I, les valeurs allant de A à B avec le pas (en Anglais “step”) C.
Attention : Si A>B mais que le pas C est strictement positif, on ne passe pas une seule fois
dans la boucle.
Par exemple, on ne passe pas une seule fois dans une boucle DO I = 1 , 0 (car le pas “par défaut”
est 1 qui est positif.).
De même, si A<B mais que le pas C est strictement négatif, on ne passe pas non plus dans la
boucle.
Remarque : Les arguments entiers de la boucle ne sont pas forcément des constantes explicites,
on peut également donner des variables :
14 Chapitre 2: Boucles et Tests
PROGRAM EXEMPLE2 8
INTEGER :: I,A,B,C
PRINT*, ’ENTRER A B ET C’
PRINT*, ’SEPARES PAR UNE VIRGULE’
Exemple : READ*, A,B,C
DO I = A,B,C
PRINT*, ’I A LA VALEUR’,I
END DO
END PROGRAM EXEMPLE2 8
donne à l’exécution :
ENTRER A B ET C
SEPARES PAR UNE VIRGULE
1,4,0
I A LA VALEUR 1
ENTRER A B ET C
I A LA VALEUR 1
SEPARES PAR UNE VIRGULE ENTRER A B ET C
I A LA VALEUR 1
1,4,2 SEPARES PAR UNE VIRGULE
I A LA VALEUR 1
I A LA VALEUR 1 1,4,-2
I A LA VALEUR 1
I A LA VALEUR 3
.
.
.
Le fonctionnement d’une boucle non indexée est différent de celui d’une boucle indexée, la sortie
ou non de la boucle est fonction d’un booléen (c’est à dire du résultat d’un test).
La syntaxe est la suivante :
Exemple :
PROGRAM EXEMPLE2 9
INTEGER :: A,I
PRINT*, ’ENTRER A, J’’AFFICHERAI TOUS LES’
PRINT*, ’ENTIERS DONT LE CARRE EST PLUS’
PRINT*, ’PETIT QUE A’
READ*, A
I=0
DO WHILE (I*I.LE.A)
I=I+1
IF (I*I.LE.A) PRINT*, I,I*I
END DO
END PROGRAM EXEMPLE2 9
Donne à l’exécution :
ENTRER A, J’AFFICHERAI TOUS LES
ENTIERS DONT LE CARRE EST PLUS
PETIT QUE A
20
1 1
2 4
3 9
4 16
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 15
Ce type de boucle est souvent utilisé pour tester la validité d’une saisie au clavier.
Exemple :
PROGRAM EXEMPLE2 10
REAL :: A
PRINT*, ’ENTRER UN REEL A COMPRIS ENTRE 0 ET 1’
READ*, A
DO WHILE ((A.LT.0).OR.(A.GT.1))
PRINT*, ’SAISIE INCORRECTE :’
PRINT*, ’A DOIT ETRE COMPRIS ENTRE 0 ET 1’
READ*, A
END DO
END PROGRAM EXEMPLE2 10
Donne à l’exécution :
ENTRER UN REEL A COMPRIS ENTRE 0 ET 1
2
SAISIE INCORRECTE :
A DOIT ETRE COMPRIS ENTRE 0 ET 1
-0.6
SAISIE INCORRECTE :
A DOIT ETRE COMPRIS ENTRE 0 ET 1
0.6
Exemple :
PROGRAM EXEMPLE2 11
INTEGER :: I,J
DO I = 1 , 3
DO J = 1 , 5
IF (I*I*I.GE.J*J) THEN
PRINT*, ’LE CUBE DE ’,I,’ EST SUPERIEUR OU EGAL AU CARRE DE ’,J
ELSE
PRINT*, ’LE CUBE DE ’,I,’ EST STRICTEMENT INFERIEUR AU CARRE DE ’,J
END IF
END DO
END DO
END PROGRAM EXEMPLE2 11
Il est particulièrement important dans ce cas de respecter les règles d’indentation pour la lisibilité
du code.
D’autre part, dans ce type de structure, le premier END DO correspond forcément au dernier DO (sur
J),et le dernier END DO correspond forcément au premier DO (sur I). Il est impossible “entremêler”
de telles boucles.
Ces règles sont aussi valable pour les tests imbriqués entre eux, ou pour les boucles imbriqués
dans les tests.
Par exemple, le code suivant ne serait pas compilé :
PROGRAM EXEMPLE2 11bugge
INTEGER :: I,J
DO I = 1 , 3
DO J = 1 , 5
IF (I*I*I.GE.J*J) THEN
PRINT*, ’LE CUBE DE ’,I,’ EST SUPERIEUR OU EGAL AU CARRE DE ’,J
ELSE
PRINT*, ’LE CUBE DE ’,I,’ EST STRICTEMENT INFERIEUR AU CARRE DE ’,J
END DO
END IF
END DO
END PROGRAM EXEMPLE2 11bugge
On obtient, à la compilation, le message d’erreur suivant qui signifie que fortran 90 n’a pas trouvé
le END IF correspondant au test entamé par IF.
IF (I*I*I.GE.J*J) THEN
^
"exemple2.7.bugge.f90", Line = 5, Column = 9: ERROR: An END statement is missing for this IF statement.
f90: COMPILE TIME 0.050000 SECONDS
f90: MAXIMUM FIELD LENGTH 4758540 DECIMAL WORDS
f90: 12 SOURCE LINES
f90: 1 ERRORS, 0 WARNINGS, 0 OTHER MESSAGES, 0 ANSI
La raison est qu’il a rencontré avant un END DO, qui ne correspond pas à une boucle imbriquée
dans le test.
PROGRAM EXEMPLE2 12
INTEGER :: I,A,B,C
PRINT*, ’ENTRER A B ET C’
PRINT*, ’SEPARES PAR UNE VIRGULE’
READ*, A,B,C
DO I = A,B
PRINT*
PRINT*, ’I A LA VALEUR’,I Remarque : vues les règles ex-
IF (I/C*C.EQ.I) THEN
PRINT*, ’I EST MULTIPLE DE C’
pliquées au chapitre 1 concernant
PRINT*, ’ON SORT DE LA BOUCLE’ les règles de calcul sur les INTEGER,
EXIT
END IF il est clair que I/C*C est égal à C si
IF (I/2*2.EQ.I) THEN et seulement si I est multiple de C.
PRINT*, ’I EST PAIR’
PRINT*, ’ON PASSE A L’’ITERATION SUIVANTE’
CYCLE
END IF
PRINT*, ’I N’’EST NI PAIR, NI MULTIPLE DE C’
END DO
END PROGRAM EXEMPLE2 12
ENTRER A B ET C
SEPARES PAR UNE VIRGULE
28,45,16
I A LA VALEUR 28
I EST PAIR
ON PASSE A L’ITERATION SUIVANTE
I A LA VALEUR 29
I N’EST NI PAIR, NI MULTIPLE DE C
Donne à l’exécution : I A LA VALEUR 30
I EST PAIR
ON PASSE A L’ITERATION SUIVANTE
I A LA VALEUR 31
I N’EST NI PAIR, NI MULTIPLE DE C
I A LA VALEUR 32
I EST MULTIPLE DE C
ON SORT DE LA BOUCLE
Lorsqu’on utilise ce type de contrôle dans des boucles “imbriquées”, il faut étiqueter (en franglais
“labeler”, c’est à dire “nommer”) les boucles, de manière à ce que le compilateur sache de quelle
boucle il faut sortir.
Ceci se fait de la manière suivante :
Exemple :
PROGRAM EXEMPLE2 13
INTEGER :: I,J
B1: DO I = 1,4
PRINT*
PRINT*, ’I A LA VALEUR’,I
B2: DO J=1,4
PRINT*, ’J A LA VALEUR ’,J
IF (J/2*2.EQ.J) CYCLE B2
PRINT*, ’J EST IMPAIR’
IF ((I+J)/5*5.EQ.I+J) EXIT B1
PRINT*, ’I+J N’’EST PAS MULTIPLE DE 5’
END DO B2
END DO B1
END PROGRAM EXEMPLE2 13
18 Chapitre 2: Boucles et Tests
I A LA VALEUR 1
J A LA VALEUR 1
J EST IMPAIR
I+J N’EST PAS MULTIPLE DE 5
J A LA VALEUR 2
J A LA VALEUR 3
J EST IMPAIR
I+J N’EST PAS MULTIPLE DE 5
Donne à l’exécution : J A LA VALEUR 4
I A LA VALEUR 2
J A LA VALEUR 1
J EST IMPAIR
I+J N’EST PAS MULTIPLE DE 5
J A LA VALEUR 2
J A LA VALEUR 3
J EST IMPAIR
Les règles concernant les noms à donner aux boucles sont les mêmes que celles pour les noms de
variables.
Notez que les END DO correspondant aux DO “étiquetés” rappellent le nom de la boucle. Il faut
donc faire apparaı̂tre les noms pour les END DO dans l’ordre inverse d’apparition pour les DO.
2.4 Branchements
Nous avons vu jusqu’à présent que fortran 90 interprétait les différentes instructions dans l’ordre
où elles étaient codées.
L’instruction GOTO permet justement de demander à fortran 90 d’aller traiter une instruction
autre que celle qui suit immédiatement.
Pour cela, il faut “numéroter” une ligne. Ceci se fait de la plus simple des manière : on ajoute
une valeur entière devant la ligne que l’on souhaite numéroter.
Ensuite, l’instruction GOTO suivi de ce numéro demandera au code d’aller exécuter l’instruction
numérotée, puis celles qui suivent.
PROGRAM EXEMPLE2 14
INTEGER :: A,B,C
5 PRINT*, ’SAISIR LES VALEURS DE A,B,C’
PRINT*, ’SEPAREES PAR UNE ,’
READ*, A,B,C
DO I = A,B,C
PRINT*, ’I=’,I
IF (I.GT.6) GOTO 20
IF (I.GT.5) GOTO 10
END DO
PRINT*, ’ON EST SORTI DE LA BOUCLE’
10 PRINT*, ’I EST PLUS GRAND QUE 5, JE RECOMMENCE’
GOTO 5
20 PRINT*, ’I EST PLUS GRAND QUE 6, ON ARRETE’
END PROGRAM EXEMPLE2 14
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 19
Remarque : contrairement à d’autres langages, il est possible en fortran 90 de sortir d’un bloc
avec un GOTO (on entend par “bloc” un groupe d’instructions comprises entre un DO et un END DO,
ou encore entre un IF et un END IF, ...).
Cela signifie qu’il est possible, dans un bloc, de coder un GOTO vers une instruction extérieure à
ce bloc.
En revanche, il est impossible de “rentrer” dans un bloc avec un goto, ce qui signifie que si l’on
souhaite aller vers une instruction comprise dans un bloc, il est nécessaire que le GOTO fasse partie
de ce même bloc.
ENTRER I
donne à l’exécution : 6 ou
COMPRIS ENTRE -2 ET25, MAIS DIFFERENT DE 2,3,5,7,8,9,10 ...
ENTRER I
28 .
I EST PLUS GRAND OU EGAL A 26
L’instruction SELECT CASE (I) précise que l’on va traiter l’un où l’autre des blocs d’instructions
en fonction de la valeur de la variable INTEGER I .
20 Chapitre 2: Boucles et Tests
Ensuite, chacun des CASE permettra de définir lequel des différents blocs sera traité.
Comme nous le voyons dans cet exemple, il est possible de faire suivre SELECT CASE par une
variable.
En revanche, chacun des CASE suivants ne devra faire apparaı̂tre que des constantes explicites ou
des paramètres.
D’autre part, il ne faut pas que les possibilités données par les CASE donnent lieu à des ambiguı̈té :
seul l’un des CASE ne doit pouvoir être satisfait.
Cette structure est donc relativement rigide, elle est du coup assez peu utilisée.
En pratique, elle ne sert en fait qu’à gérer des “menus”...
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 21
Chapitre 3: Tableaux.
3.1 Déclaration
Un tableau permet de regrouper au sein de la même variable une famille de données de mêmes
types.
Ces deux déclarations sont rigoureusement équivalentes. A sera alors un tableau à 5 éléments,
indexés de 1 à 5, ce qui signifie que ces 5 éléments seront A(1), A(2), A(3), A(4) et A(5).
Il est possible d’utiliser des paramètres (cf §1.2.2.f ) pour définir la dimension du tableau
exemple :
INTEGER, PARAMETER :: N=4
REAL :: A(0:N)
→ A est un alors un tableau à 5 éléments : A(0), A(1), A(2), A(3) et A(4).
Attention, il n’est pas possible de faire ceci avec une variable non paramètre, même si cette
variable est déclarée avec une affectation de valeur.
Ainsi,
INTEGER :: N=4
REAL :: A(0:N)
donnera une erreur à la compilation.
exemples :
REAL :: A(5,3)
REAL, DIMENSION (5,3) :: B
REAL, DIMENSION (-2:1,3,0:3) :: C
INTEGER, PARAMETER :: N=4
REAL :: D(0:N,N,N+2)
La tableau A est un tableau contenant 15 éléments, qui seront :
A(1,1), A(2,1), A(3,1), A(4,1), A(5,1),
A(1,2), A(2,2), A(3,2), A(4,2), A(5,2),
A(1,3), A(2,3), A(3,3), A(4,3), et A(5,3).
La déclaration pour le tableau B est rigoureusement équivalente.
La tableau C est un tableau contenant 48 éléments, qui seront :
C(-2,1,0), C(-1,1,0), C(0,1,0), C(1,1,0),
C(-2,2,0), C(-1,2,0), C(0,2,0), C(1,2,0),
C(-2,3,0), C(-1,3,0), C(0,3,0), C(1,3,0),
C(-2,1,1), C(-1,1,1), C(0,1,1), C(1,1,1),
C(-2,2,1), C(-1,2,1), C(0,2,1), C(1,2,1),
C(-2,3,1), C(-1,3,1), C(0,3,1), C(1,3,1),
C(-2,1,2), C(-1,1,2), C(0,1,2), C(1,1,2),
C(-2,2,2), C(-1,2,2), C(0,2,2), C(1,2,2),
C(-2,3,2), C(-1,3,2), C(0,3,2), C(1,3,2),
C(-2,1,3), C(-1,1,3), C(0,1,3), C(1,1,3),
C(-2,2,3), C(-1,2,3), C(0,2,3), C(1,2,3),
C(-2,3,3), C(-1,3,3), C(0,3,3), C(1,3,3).
On retiendra que c’est dans cet ordre que les éléments sont rangés dans la mémoire
de la machine, c’est à dire en faisant varier d’abord le premier index dans l’ordre croissant des
valeurs qu’il peut prendre, puis le second, etc...
La tableau D contiendra 120 éléments de types entiers puisque le premier indice peut prendre les
valeurs de 0 à 4, le second prend les valeurs de 1 à 4 et le troisième prend les valeurs de 1 à 6.
Pour un tableau bi-dimensionnel, on utilisera le vocabulaire réservé aux matrices : le premier
indice correspond à l’indice des lignes, le second à celui des colonnes.
En mémoire, les éléments d’un tableau sont donc rangés par colonnes.
Vocabulaire :
• Le nombre d’éléments dans une dimension s’appelle l’étendue (en anglais : “extent” ) du
tableau dans cette dimension.
• Le profil (shape) d’un tableau est un vecteur d’entiers, dont les éléments correspondent à
l’étendue du tableau dans chacune de ses dimensions.
• La taille (size) d’un tableau est le produit des éléments du vecteur correspondant à son
profil, c’est le nombre total d’éléments contenus dans le tableau.
• Deux tableaux sont conformants s’ils ont le même profil.
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 23
Nous serons amenés à utiliser ce vocabulaire dans la suite, nous donnerons alors quelques exem-
ples.
3.2 Utilisation
Il existe en fortran 90 plusieurs manières d’utiliser un tableau, soit en travaillant sur chacun
des éléments (c’est ce que l’on pouvait faire avec les version précédentes de fortran), soit en
travaillant sur toute une catégorie (voire la totalité) des éléments du tableau.
Chaque élément d’un tableau peut être traité de la même manière que n’importe quelle variable.
Exemple :
PROGRAM EXEMPLE3 1
IMPLICIT NONE
INTEGER, PARAMETER :: N=4
REAL, DIMENSION (N) :: A
REAL :: S=0
INTEGER :: I
DO I=1,N
PRINT*, ’ENTRER A(’,I,’)’
READ*, A(I)
END DO
DO I = 1,N
S=S+I*A(I)
END DO
PRINT*, ’S=’,S
END PROGRAM EXEMPLE3 1
ENTRER A( 1 )
3.2
ENTRER A( 2 )
2.4
Donne à l’exécution : ENTRER A( 3 )
3.1
ENTRER A( 4 )
1.2
S= 22.099998
Dans cet exemple, on voit que l’on peut modifier la valeur des éléments du tableau ( via la lecture
au clavier READ* ) , on aurait pu affecter aussi directement par une instruction d’affectation
X4
classique (par exemple A(I)=...), et on a utilisé les valeurs en lecture pour calculer i × A(i).
i=1
Fortran 90 permet de faire des opérations directement sur un tableau tout entier ou sur un
“sous-tableau” (sous ensemble d’un tableau).
Par exemple, l’instruction
“A=B”
24 Chapitre 3: Tableaux
Rappel : pour que deux tableau soient conformants, il doivent avoir la même forme. Il faut
donc que :
• Le premier index du premier tableau doit pouvoir prendre le même nombre de valeurs
différentes que le premier index du second tableau, de même pour le deuxième index, etc...
Exemples :
REAL :: A(5,6)
REAL :: B (30)
REAL :: C (-3:1,0:5)
REAL :: D (5,6,1)
REAL :: E (3,10)
Tous ces tableaux ont 30 éléments de types réels.
Le tableau C ainsi défini est un tableau à double entrée. Ses éléments sont C(i,j) avec −3 ≤ i ≤ 1
et 0 ≤ j ≤ 5.
Les tableaux A et C sont donc conformants, l’affectation A=C est correcte.
Elle est équivalente à:
DO I=1,5
DO J=1,6
A (I,J) = C (I-4,J-1)
END DO
END DO
En revanche, les tableaux B et D, bien que contenant également 30 éléments, ne sont PAS confor-
mants avec le tableau A, car B est un tableau à 1 dimension et D à 3 dimensions.
Quant au tableau E, bien qu’étant à deux dimensions et contenant 30 éléments comme A, il n’est
pas conformant avec le tableau A car chacun de ses indexes ne peut pas prendre le même nombre
de valeurs distinctes que pour A.
Les affections A=B, A=D et A=E entraı̂neraient toutes des erreurs à la compilation.
Il est non seulement possible de faire des assignations directes de cette manière, mais aussi des
opérations portant sur chacun des éléments des tableaux:
Exemple: Avec les tableaux définis ci-dessus, l’instruction
A=A+C
modifie chaque élément de A pour lui ajouter la valeur du tableau C situé au lieu correspondant.
Ce qui est équivalent à :
DO I=1,5
DO J=1,6
A (I,J) = A (I,J) + C (I-4,J-1)
END DO
END DO
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 25
Désignations de sous-tableaux
Le tableau dénommé par A(i:j:k,l:m:n) est un sous tableau de A. Ses éléments sont les éléments
de A situés aux lignes i, i+k, ..., jusqu’au plus grand nombre de la forme i+k+..+k inférieur ou
égal à j , et aux colonnes l, l+n , ... , jusqu’au plus grand nombre de la forme l+n+n+..+n inférieur
ou égal à m.
Visualisation, Exemples:
REAL A (6,8)
Alors A(2:6:2,1:7:3) est le tableau de dimension 3 × 3 contenant les éléments repérés par le
schéma ci-dessous:
1 2 3 4 5 6 7 8
1
2 X X X
3
4 X X X
5
6 X X X
REAL B (13,12)
Alors B(2:11:4,2:9:2) est le tableau de dimension 3 × 4 contenant les éléments repérés par le
schéma ci-dessous:
1 2 3 4 5 6 7 8 9 10 11 12
1
2 X X X X
3
4
5
6 X X X X
7
8
9
10 X X X X
11
12
13
Il est possible de ne pas mettre de pas (le pas par défaut est 1) ou de mettre un “pas” négatif.
Ainsi, avec les tableaux A et B ci-dessus, A(6:2:-2,1:7:3) est le même tableau que A(2:6:2,1:7:3),
si ce n’est que l’ordre des lignes est INVERSÉ.
26 Chapitre 3: Tableaux
La tableau B(2:11:4,9:2:-2) désigne cette fois le tableau de dimension 3×4 contenant les éléments
repérés par le schéma ci-dessous:
1 2 3 4 5 6 7 8 9 10 11 12
1
2 X X X X
3
4
5
6 X X X X
7
8
9
10 X X X X
11
12
13
où l’ordre des colonnes est pris de droite à gauche.
On peut effectuer avec les sous-tableaux les mêmes opérations qu’avec les tableaux.
Exemple. Avec les deux tableaux ci-dessus, et les tableaux C(5,6) et D (-2:3,4:8) on peut écrire:
A(5:1:-4,2:5)=B (7:8,1:8:2) * C (1:2,4:1:-1) + D(0:1,5:8)
Chacun des sous-tableaux mentionnés dans cette instruction est de dimensions 2 × 4.
Attention On constate que “∗” pour des matrices est le produit “terme à terme” et non pas le
produit matriciel !
A(1::,5:6) désigne le sous tableau où le premier indice prend les valeurs de 1 jusqu’à la plus
grande valeur admissible par le premier indice de A,et où le second indice prendre les valeurs 5
et 6,
A(:,5) désigne le tableau unidimensionnel correspondant à la cinquième colonne de A,
A(::6,6::) désigne le sous tableau où le premier indice prend les valeurs allant de la plus petite
valeur admissible par le premier indice de A jusqu’à 6 et où le second indice prend les valeurs
allant de 6 jusqu’à la plus grande valeur admissible par le second indice de A.
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 27
Subtilités
Soient deux tableaux définis par :
REAL :: A (5,6,4) , B (2,3)
Alors les instructions suivantes sont incorrectes :
A (2:3,6:2:-1,1) = B
A (2:3,6:2:-2,1:1) = B
Mais à:
T=A(2,4,1)
do i = 1,2
do j = 1,3
A (1+i,8-2*j,1) = T * B(i,j)
end do
end do
Nous avons vu jusqu’à présent comment utiliser des tableaux définis de manière “statique”, c’est
à dire dont les dimensions et la forme étaient définitivement fixées au moment de la déclaration.
Il est possible de définir des tableaux et d’allouer dynamiquement leur forme, c’est à dire de
modifier au cours du code les nombres de valeurs que peuvent prendre chacun des indexes.
Syntaxe :
Au moment de la déclaration, on utilise l’instruction suivante :
REAL, DIMENSION (:,:), ALLOCATABLE :: A
INTEGER :: IERR
Cette déclaration précise que le tableau A est un tableau bi-dimensionnel (il y aura donc 2
indexes), mais on ne précise pas les valeurs entre lesquelles pourront varier les indexes.
La déclaration de l’entier IERR n’est pas rigoureusement obligatoire, mais nous verrons qu’elle
n’est pas inutile non plus.
Plus loin, dans le corps du code, on précise la forme du tableau de la manière suivante :
ALLOCATE (A(5,3), STAT=IERR)
Cette instruction demande à la machine de libérer un espace mémoire nécessaire au stockage des
15 éléments du tableau réel A.
Après cette instruction, l’entier IERR est susceptible d’être modifié.
Si il a la valeur 0, cela signifie que l’allocation a bien fonctionné.
Sinon, il y a eu une erreur (par exemple, on a demandé une dimension trop grosse par rapport
à la mémoire de la machine, ou alors on avait déjà attribué des dimensions au tableau A, ...).
On fait donc traditionnellement suivre ce type d’allocation par les lignes suivantes :
IF (IERR.NE.0) then
print*, ’erreur pour le tableau A’
stop
END IF
Pour “désallouer” l’espace mémoire occupé par le tableau A, c’est à dire pour libérer cet espace,
on utilise l’instruction :
DEALLOCATE ( A , STAT=IERR )
Ici encore, l’entier IERR prendra une valeur non nulle dans le cas ou cette “désallocation” ait
entraı̂né une erreur...
Une fois que l’on a libéré l’espace de cette manière, on peut ré-attribuer une forme (éventuellement
différente) au tableau A.
Dans la phase d’allocation, on peut utiliser des variables entières qui ne sont pas forcément des
paramètres. Les valeurs auront par exemple pu être saisies au clavier (c’est en pratique l’un des
intérêts de l’allocation dynamique).
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 29
Exemple :
PROGRAM EXEMPLE3 2
IMPLICIT NONE
INTEGER :: N
REAL, DIMENSION (:), ALLOCATABLE :: A
REAL :: S=0
INTEGER :: I, IERR
PRINT*, ’ENTRER LA VALEUR DE N’
READ*, N
ALLOCATE (A(N),STAT=IERR)
IF (IERR.NE.0) STOP ’ERREUR !’
DO I=1,N
PRINT*, ’ENTRER A(’,I,’)’
READ*, A(I)
END DO
DO I = 1,N
S=S+I*A(I)
END DO
PRINT*, ’S=’,S
END PROGRAM EXEMPLE3 2
ENTRER LA VALEUR DE N
3
ENTRER A( 1 )
2.3 ENTRER LA VALEUR DE N
Donne à l’exécution : ENTRER A( 2 ) ou 1000000000
2 STOP: ERREUR !
ENTRER A( 3 )
4.3
S= 19.2
Il est bien sur possible d’effectuer avec ces tableaux toutes les opérations que l’on peut effectuer
avec les tableaux classiques (définis de manière statique), en particulier les opérations globales
décrites dans les sections 3.2.2 et 3.2.3
La fonction ALLOCATED permet de savoir si un tel tableau est déjà alloué, ou non.
Le résultat est un booléen :
• ALLOCATED(A) aura la valeur .TRUE. si le tableau A est déjà alloué, auquel cas la tentative :
ALLOCATE(A(N,N),STAT=IERR) conduira forcément à une erreur,
ALLOCATED(A) aura la valeur .FALSE. si le tableau A est n’est pas alloué, auquel cas la tenta-
tive : ALLOCATE(A(N,N),STAT=IERR) pourra être possible...
• SIZE renvoie le nombre total d’éléments du tableau, ou selon l’un des indices.
SIZE (A,1) est l’entier 12
SIZE (A) est l’entier 12×15×2=360
• RESHAPE
C’est un constructeur de tableau.
RESHAPE ((/l1,..,ln/),(/i1,i2,i3/))
est le tableau de dimensions (i1,i2,i3) contenant les éléments l1,..,ln.
Exemple :
INTEGER, DIMENSION (4,-1:2) :: C
C = RESHAPE ((/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16/),(/4,4/))
est une affectation correcte qui remplit le tableau C des éléments 1 à 16.
C = RESHAPE ((/1,2,3,4,5,6,7,8,9,10/),(/4,4/))
est incorrecte : il manque des éléments dans la liste.
C = RESHAPE ((/1,2,3,4,5,6,7,8,9,10/),(/4,4/),(/2/))
est correcte : la liste est complétée avec des 2.
Si je définis un tableau A par
REAL, DIMENSION (-1:0,2,4) :: A
alors l’affectation
A = RESHAPE (C,(/2,2,4/))
est correcte: elle remplit le tableau A avec les éléments du tableau C.
L’ordre de remplissage est l’ordre dans lequel sont rangés les éléments en mémoire (en
faisant varier le premier indice, puis le second, ...).
On peut modifier cet ordre de remplissage de la manière suivante :
A = RESHAPE ((/1,2,3,4,5,6,7,8,9,10/),(/2,2,4/),(/2/),(/3,1,2/))
remplit le tableau A des éléments de C suivant le troisième indice de A, puis le premier, puis
le second...
Attention ! Pour ce type d’affectation, deux solutions : il faut préciser un “remplissage”
éventuel, même si celui ci s’avère en fait inutile ou alors préciser
A = RESHAPE ((/1,2,3,4,5,6,7,8,9,10/),(/2,2,4/),ORDER=(/3,1,2/)) (sinon, fortran 90 ne com-
prend pas...)
Il est possible de rechercher le maximum ligne par ligne ou colonne par colonne de la
manière suivante :
MAXVAL(A,DIM=1) renvoie ((/2,5,4/)), c’est à dire le maximum dans chaque colonne (je ne
“travaille” que sur le premier indice).
et
MAXVAL(A,DIM=2) renvoie ((/4,5/)), c’est à dire le maximum dans chaque ligne (je ne “tra-
vaille” que sur le deuxième indice).
• MAXLOC renvoie la position de l’élément maximum dans le tableau A.
En reprenant l’exemple ci dessus :
MAXLOC(A) renvoie le vecteur ((/2,2/)).
Il est possible de calculer la somme ligne par ligne ou colonne par colonne de la manière
suivante :
SUM(A,DIM=1) renvoie ((/3,8,7/)), c’est à dire la somme dans chaque colonne (je ne “tra-
vaille” que sur le premier indice).
et
SUM(A,DIM=2) renvoie ((/8,10/)), c’est à dire la somme dans chaque ligne (je ne “travaille”
que sur le deuxième indice).
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 33
Le principe des routines et fonctions et de coder une seule fois une série d’instruction amenées à
être exécutées plusieurs fois, éventuellement avec des valeurs différentes pour certains paramètres.
Un deuxième intérêt est de faciliter la lecture du code.
Il y a plusieurs façons de structurer un code utilisant des procédures et fonctions, nous verrons
notamment qu’il est possible de coder les différents objets dans des fichiers séparés.
Dans cette partie, nous verrons les règles de codage dans le cas où tous les éléments du programme
sont codés dans un seul fichier.
De manière générale, le programme utilisant les routines et les fonctions a la structure suivante :
PROGRAM MACHIN
Déclarations ...
lignes de code parmi lesquelles CALL SUB (...) et/ou FONC(...) ← programme principal
..
CONTAINS
SUBROUTINE SUB (A,B,C)
Déclarations des variables locales
(parmi lesquelles A,B et C)
lignes de code utilisant/modifiant A,B et C
..
END SUBROUTINE SUB
FUNCTION FONC (X)
Déclarations des variables locales
(parmi lesquelles Xet FONC)
lignes de code utilisant X et attribuant une valeur à FONC ← routines / fonctions
..
END FUNCTION FONC
END PROGRAM MACHIN
Exemple de fonction :
PROGRAM EXEMPLE4 1
REAL :: X1,X2
PRINT*, ’ENTRER LA VALEUR DE X1’
READ*, X1
PRINT*, ’X1=’,’ F(X1)=’,X1**2+3*X1+2
PRINT*, ’ENTRER LA VALEUR DE X2’
READ*, X2
PRINT*, ’X2=’,’ F(X2)=’,X2**2+3*X2+2
END PROGRAM EXEMPLE4 1
ENTRER LA VALEUR DE X1
1.2
X1= F(X1)= 7.04
On obtient à l’exécution : ENTRER LA VALEUR DE X2
2.4
X2= F(X2)= 14.960001
Mais on peut simplifier le codage en utilisant une fonction :
PROGRAM EXEMPLE4 2
REAL :: X1,X2
PRINT*, ’ENTRER LA VALEUR DE X1’
READ*, X1
PRINT*, ’X1=’,’ F(X1)=’,F(X1)
PRINT*, ’ENTRER LA VALEUR DE X2’
READ*, X2
PRINT*, ’X2=’,’ F(X2)=’,F(X2)
CONTAINS
FUNCTION F(X)
REAL :: X,F
F=X*X+3*X+2
END FUNCTION F
END PROGRAM EXEMPLE4 2
Lorsque le compilateur rencontre l’expression F(X1) dans le programme principal, il exécute les in-
struction codées après la ligne FUNCTION F(X) en attribuant à la variable locale X la valeur contenue
dans la variable X1 au moment de l’appel.
On notera qu’il faut préciser le type du résultat de la fonction en déclarant le type de la variable
locale portant le nom de la fonction (ici :F) .
Les règles pour les noms des fonctions sont les mêmes que celles concernant les noms des variables
(ce sont aussi les même règles pour les procédures).
Le fonctionnement d’une routine est à peu près le même, une routine est cependant appelée
par une instruction CALL SUB, alors qu’on faisait directement référence à une fonction comme on
faisait référence à une variable.
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 35
Les instruction codées dans la subroutine sont exécutées, les variables locales de la subroutine
(ici :X et R) étant remplacées par les variables du programme principal apparaissant dans l’appel
(ici :X1 et RES dans un premier temps puis X2 et RES dans un second temps)
Dans la subroutine, on peut préciser au moment de la déclaration si les variables locales sont
susceptibles d’être :
Si on ne précise rien, le compilateur considère que la variable peut être lue et modifiée comme si
elle avait été déclarée avec INTENT (INOUT).
L’intérêt d’utiliser INTENT est de permettre de détecter des erreurs de codage et de faciliter la
lecture du code.
Lorsqu’on code une subroutine ou une fonction, il faut (comme pour un programme “classique”)
commencer par déclarer les différents objets qui vont être utilisés. Ces déclarations ne sont
pas rigoureusement indispensables, mais elles sont très fortement conseillées (cf remarque
§1.2.2.a).
Exemple :
L’objet du code ci dessous est de coder une routine permettant de construire le vecteur A =
(a1 , ..., an ) ∈ Rn avec aj = sin(ijπ/n) pour tout j ∈ {1, .., N }.
PROGRAM EXEMPLE4 4
IMPLICIT NONE
INTEGER, PARAMETER :: N=5
REAL :: PI=3.14159265359
REAL, DIMENSION (N) :: A
CALL CONSTRUIT (A,1)
PRINT*, A
CONTAINS
SUBROUTINE CONSTRUIT (M,I)
IMPLICIT NONE
REAL, DIMENSION (N), INTENT (OUT) :: M
INTEGER, INTENT (IN) :: I
INTEGER :: J
DO J=1,N
M(J)=SIN(I*J*PI/N)
END DO
END SUBROUTINE CONSTRUIT
END PROGRAM EXEMPLE4 4
On s’aperçoit que l’entier paramètre N n’est pas re-déclaré dans la subroutine, de même que le
réel (non paramètre) PI.
36 Chapitre 4: Subroutines et fonctions
Malgré la présence de IMPLICIT NONE, le code est normalement compilé, fortran 90 considérera
que les variables utilisées dans la subroutine CONSTRUIT et qui ne sont pas déclarées localement
dans l’entête de cette subroutine, sont des variables globales car elles sont déclarées dans le
programme principal. Si cette variable est modifiée par une ligne du programme principal (ce
qui n’est pas le cas ici), cette modification sera prise en compte lors des passages suivants dans
la subroutine CONSTRUIT. Réciproquement, si la subroutine CONSTRUIT modifie la variable globale
PI, il en sera tenu compte par la suite dans le programme principal.
Si PI n’avait été déclaré ni dans la subroutine, ni dans le programme principal, on aurait alors
obtenu une erreur à la compilation.
Il est possible de déclarer localement des variables portant le même nom que des variables du
programme principal (ou que des variables d’autres subroutines/fonctions). C’est notamment
souvent le cas pour des indexes de boucles (variables entières).
Lorsqu’on déclare ainsi des variables locales pour une subroutine ou pour une fonction, fortran
90 réserve en mémoire un espace spécifique pour stocker la valeur de ces variables. Il faut savoir
que les valeurs des variables locales des subroutines/fonctions sont préservées d’un
passage au suivant !.
Il faut notamment retenir que si on déclare une variable en lui attribuant une valeur dans une
subroutine/fonction (déclaration décrite au §1.2.2.g) l’attribution ne sera faite que pour le
premier passage dans la routine ! Pour les passages suivants, fortran 90 conserve pour
chaque variable locale la valeur qu’elle avait à la fin du passage précédent.
PROGRAM EXEMPLE4 5
REAL :: S
INTEGER :: K,L
PRINT*,’ENTRER K’
READ*, K
PRINT*,’ENTRER L’
READ*, L
DO WHILE (K.LT.L)
CALL RANDOM NUMBER (S)
IF (S.GT.0.5) THEN
CALL DOUBLE (K)
ELSE
CALL TRIPLE (K)
END IF
PRINT*, K
END DO
CONTAINS
SUBROUTINE DOUBLE (N)
INTEGER, INTENT (INOUT) :: N
INTEGER, SAVE :: COMPTEUR = 0
COMPTEUR=COMPTEUR+1
PRINT*, ’PASSAGE NUMERO ’,COMPTEUR,’ DANS LA &
& SUBROUTINE DOUBLE’
N=N*2
END SUBROUTINE DOUBLE
SUBROUTINE TRIPLE (N)
INTEGER, INTENT (INOUT) :: N
INTEGER, SAVE :: COMPTEUR = 0
COMPTEUR=COMPTEUR+1
PRINT*, ’PASSAGE NUMERO ’,COMPTEUR,’ DANS LA &
& SUBROUTINE TRIPLE’
N=N*3
END SUBROUTINE TRIPLE
END PROGRAM EXEMPLE4 5
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 37
ENTRER K
2
ENTRER L
140
PASSAGE NUMERO 1 DANS LA SUBROUTINE DOUBLE
4
PASSAGE NUMERO 2 DANS LA SUBROUTINE DOUBLE
donne à l’exécution : 8
PASSAGE NUMERO 1 DANS LA SUBROUTINE TRIPLE
24
PASSAGE NUMERO 2 DANS LA SUBROUTINE TRIPLE
72
PASSAGE NUMERO 3 DANS LA SUBROUTINE DOUBLE
144
PROGRAM EXEMPLE4 6
REAL :: A,B,C
A=2 ; B=1 ; C=2
CALL CALCUL (A,B,C,C)
PRINT*, A,B,C
CONTAINS
SUBROUTINE CALCUL (X,Y,Z,T)
REAL :: X,Y,Z,T
T=0
T=T+X
T=T+Y
T=T+Z
END SUBROUTINE CALCUL
END PROGRAM EXEMPLE4 6
Dans la routine CALCUL, Z et T font tous deux référence à la variable C du programme principal.
Attention :
On peut appeler une subroutine/fonction en mettant en argument une constante explicite ou un
paramètre qui (rappel !) n’a pas le droit d’être modifié lors de l’exécution du code.
C’est le cas dans l’exemple ci-dessus : nous avons appelé la subroutine CONSTRUIT avec la constante
explicite 1 parmi les arguments.
On comprend bien que la subroutine/fonction appelée ne doit pas tenter de modifier la variable
correspondant à cette valeur, ceci n’aurait aucun sens.
Si on commet cette erreur, on obtient soit une erreur à la compilation, soit une erreur à l’exécution
(en fonction de la machine sur laquelle on travaille...).
Nous allons détailler dans cette section ce qui se passe lorsque l’on code certaines routines/fonction
utilisant des tableaux. Nous verrons notamment que certaines erreurs difficilement détectables
peuvent apparaı̂tre (les débordements de tableaux).
38 Chapitre 4: Subroutines et fonctions
Lorsque l’un des arguments d’une subroutine/fonction est un tableau, fortran 90 se contente de
passer l’adresse du premier élément du tableau du programme principal à la routine.
Premier exemple :
PROGRAM EXEMPLE4 7
REAL, DIMENSION (5) :: A
A=0
CALL MODIF (A)
PRINT*, A
CONTAINS
SUBROUTINE MODIF (B)
REAL, DIMENSION (3) :: B
B=1
END SUBROUTINE MODIF
END PROGRAM EXEMPLE4 7
A→
B→
La subroutine demande de modifier les trois éléments du tableau B, c’est à dire les trois premier
éléments du tableau A.
Deuxième exemple :
PROGRAM EXEMPLE4 8
REAL, DIMENSION (10) :: A
A=0
CALL MODIF (A(4))
PRINT*, A
CONTAINS
SUBROUTINE MODIF (B)
REAL, DIMENSION (3) :: B
B=1
END SUBROUTINE MODIF
END PROGRAM EXEMPLE4 8
donne à l’exécution : 0.0E+0 0.0E+0 0.0E+0 1.0 1.0 1.0 0.0E+0 0.0E+0 0.0E+0 0.0E+0
Lors de l’appel, il y a correspondance entre l’adresse mémoire du quatrième élément du tableau
A du programme principal et le premier élément du tableau B de la subroutine.
La subroutine demande de modifier les trois éléments du tableau B, c’est à dire les quatrième,
cinquième et sixième éléments du tableau A.
A→
B→
PROGRAM EXEMPLE4 9
REAL, DIMENSION (4,4) :: A
A=0
CALL MODIF (A)
CALL MODIF2(A(3,1))
PRINT*, A
CONTAINS
SUBROUTINE MODIF (B)
REAL, DIMENSION (6) :: B
B=1
END SUBROUTINE MODIF
SUBROUTINE MODIF2 (B)
REAL, DIMENSION (8) :: B
B=B+1
END SUBROUTINE MODIF2
END PROGRAM EXEMPLE4 9
donne à l’exécution : 1.0 1.0 2.0 2.0 2.0 2.0 1.0 1.0 1.0 1.0 0.0E+0 0.0E+0 0.0E+0 0.0E+0 0.0E+0 0.0E+0
A→
B→
(Il faut se souvenir que c’est dans cet ordre que les éléments sont rangés en mémoire !!!)
Lors de l’appel à MODIF2, il y a correspondance entre l’adresse mémoire de l’élément A(3,1) du
tableau A du programme principal et le premier élément du tableau B de la subroutine.
Cette subroutine demande d’ajouter 1 aux huit éléments du tableau B, c’est à dire aux éléments
suivants du tableau A :
A(3,1), A(4,1), A(1,2), A(2,2), A(3,2), A(4,2), A(1,3) et A(2,3).
A→
B→
Remarque :
Si le tableau B est plus grand que le tableau A, on obtient une erreur dès la compilation :
PROGRAM EXEMPLE4 10
REAL, DIMENSION (5) :: A
A=0
CALL MODIF (A)
PRINT*, A
CONTAINS
SUBROUTINE MODIF (B)
REAL, DIMENSION (8) :: B
B=1
END SUBROUTINE MODIF
END PROGRAM EXEMPLE4 10
>f90 exemple4.5d.f90
Débordement de tableaux :
Avec l’adressage mémoire, il est possible d’aller modifier malencontreusement une variable du
programme principal qui n’apparaı̂t pas dans l’appel à une subroutine.
Exemple :
PROGRAM EXEMPLE4 11
REAL, DIMENSION (5) :: A,A2
A=0
CALL MODIF (A(4))
PRINT*, A
PRINT*, A2
CONTAINS
SUBROUTINE MODIF (B)
REAL, DIMENSION (4) :: B
B=1
END SUBROUTINE MODIF
END PROGRAM EXEMPLE4 11
A→ ←A2
B→
On peut obtenir des choses plus regrettables encore, si les débordements de tableaux se font dans
des variables de types différents :
Exemple :
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 41
PROGRAM EXEMPLE4 12
REAL, DIMENSION (4) :: A
INTEGER, DIMENSION (4) :: A2
A=0
CALL MODIF (A(3))
PRINT*, A
PRINT*, A2
CONTAINS
SUBROUTINE MODIF (B)
REAL, DIMENSION (4) :: B
B=1
END SUBROUTINE MODIF
END PROGRAM EXEMPLE4 12
Jusqu’à présent, nous avons travaillé avec des subroutines qui définissent les dimensions du
tableau en utilisant un entier explicite, ou un paramètre.
Il est possible d’utiliser une variable pour déclarer les dimensions du tableau, comme le montre
l’exemple ci-dessous :
PROGRAM EXEMPLE4 13
IMPLICIT NONE
REAL, DIMENSION (:), ALLOCATABLE :: A
REAL :: S
INTEGER N,IERR
PRINT*,’ENTRER N’
READ*, N
ALLOCATE (A(N),STAT=IERR)
CALL RANDOM NUMBER (A)
CALL SOM (A,N,S)
PRINT*, A
PRINT*, S
CONTAINS
SUBROUTINE SOM (TAB,NO,RES)
INTEGER, INTENT (IN) :: NO
REAL, INTENT (IN), DIMENSION (NO) :: TAB
REAL, INTENT (OUT) :: RES
INTEGER I
RES=0
DO I = 1, NO
RES=RES+TAB(I)*I
END DO
END SUBROUTINE SOM
END PROGRAM EXEMPLE4 13
La subroutine SOM peut ainsi être appelée avec n’importe quel vecteur A, et si l’on précise sa
dimension en deuxième argument, elle calcule alors la somme des i × A(i) pour tous les éléments
du tableau A.
Attention : il faut que l’entier NO soit déclaré AVANT le tableau TAB dans la subroutine, puisque
la déclaration du tableau fait appel à cet entier NO en lecture.
D’autre part, il est naturel que cet entier soit déclaré avec INTENT(IN).
La technique des tableaux automatiques permet de faire le type d’appel vu au §4.3.2 sans même
préciser la dimension du tableau.
42 Chapitre 4: Subroutines et fonctions
PROGRAM EXEMPLE4 14
IMPLICIT NONE
REAL, DIMENSION (:,:), ALLOCATABLE :: A
REAL :: S
INTEGER N,M,IERR
PRINT*,’ENTRER N’
READ*, N
PRINT*, ’ENTRER M’
READ*, M
ALLOCATE (A(N,M),STAT=IERR)
CALL RANDOM NUMBER (A)
CALL SOM (A,S)
PRINT*, A
PRINT*, S
CONTAINS
SUBROUTINE SOM (TAB,RES)
REAL, INTENT (IN) :: TAB (:,:)
REAL, INTENT (OUT) :: RES
INTEGER I,J
RES=0
DO I = 1, SIZE (TAB,1)
DO J=1, SIZE (TAB,2)
RES=RES+TAB(I,J)*(I+J)
END DO
END DO
END SUBROUTINE SOM
END PROGRAM EXEMPLE4 14
Dans l’exemple ci dessus, on s’aperçoit que la forme du tableau est lue dans la subroutine elle
même, en utilisant la fonction SIZE (vue au chapitre 3).
Une fonction peut appeler n’importe quelle autre subroutine/fonction. Pour qu’elle puisse
s’appeler elle même, il faut la coder de la manière suivante :
PROGRAM EXEMPLE4 15
IMPLICIT NONE
INTEGER :: N
PRINT*, ’ENTRER LA VALEUR DE L’’ENTIER N’
READ*, N
PRINT*, ’LA FACTORIELLE DE ’,N,’ EST ’,FAC(N)
CONTAINS
RECURSIVE FUNCTION FAC (N) RESULT (F N)
INTEGER :: N
INTEGER :: F N
IF (N.GT.1) THEN
F N=N*FAC(N-1)
ELSE
F N=1
END IF
END FUNCTION FAC
END PROGRAM EXEMPLE4 15
De même, pour qu’une procédure ait le droit de s’appeler elle même, on la code ainsi :
PROGRAM EXEMPLE4 16
IMPLICIT NONE
INTEGER :: N,M
PRINT*, ’ENTRER LA VALEUR DE L’’ENTIER N’
READ*, N
CALL FAC (N,M)
PRINT*, ’LA FACTORIELLE DE ’,N,’ EST ’,M
CONTAINS
RECURSIVE SUBROUTINE FAC (N,M)
INTEGER, INTENT (IN) :: N
INTEGER, INTENT (OUT) :: M
IF (N.GT.1) THEN
CALL FAC (N-1,M)
M=M*N
ELSE
M=1
END IF
END SUBROUTINE FAC
END PROGRAM EXEMPLE4 16
PROGRAM EXEMPLE4 17
IMPLICIT NONE
INTEGER, PARAMETER :: N=4
REAL, DIMENSION (N,N) :: A
REAL, DIMENSION (N) :: X,Y
CALL RANDOM NUMBER (A)
CALL RANDOM NUMBER (X)
CALL PRODUIT (VECTEUR=X,RESULTAT=Y,MATRICE=A)
PRINT*, Y
CONTAINS
SUBROUTINE PRODUIT (MATRICE,VECTEUR,RESULTAT)
REAL, DIMENSION (N,N), INTENT (IN) :: MATRICE
REAL, DIMENSION (N) , INTENT (IN) :: VECTEUR
REAL, DIMENSION (N) , INTENT (OUT) :: RESULTAT
INTEGER :: I,J
REAL :: S
DO I=1,N
S=0
DO J=1,N
S=S+MATRICE (I,J)*VECTEUR(J)
END DO
RESULTAT(I)=S
END DO
END SUBROUTINE PRODUIT
END PROGRAM EXEMPLE4 17
On voit que dans ce cas précis, il n’est pas nécessaire que l’ordre des arguments de l’appel
correspondent à l’ordre des arguments de l’entête de la subroutine.
Arguments optionnels : Exemple :
44 Chapitre 4: Subroutines et fonctions
PROGRAM EXEMPLE4 18
IMPLICIT NONE
INTEGER, PARAMETER :: N=4
REAL, DIMENSION (N,N) :: A
REAL, DIMENSION (N) :: X,Y
CALL RANDOM NUMBER (A)
CALL RANDOM NUMBER (X)
CALL PRODUIT (VECTEUR=X,RESULTAT=Y,MATRICE=A)
PRINT*, Y
CALL PRODUIT (VECTEUR=X,RESULTAT=Y)
PRINT*, Y
CONTAINS
SUBROUTINE PRODUIT (MATRICE,VECTEUR,RESULTAT)
REAL, DIMENSION (N,N), INTENT (IN), OPTIONAL :: MATRICE
REAL, DIMENSION (N) , INTENT (IN) :: VECTEUR
REAL, DIMENSION (N) , INTENT (OUT) :: RESULTAT
INTEGER :: I,J
REAL :: S
IF (PRESENT(MATRICE)) THEN
DO I=1,N
S=0
DO J=1,N
S=S+MATRICE (I,J)*VECTEUR(J)
END DO
RESULTAT(I)=S
END DO
ELSE
RESULTAT=VECTEUR
END IF
END SUBROUTINE PRODUIT
END PROGRAM EXEMPLE4 18
Dans l’exemple ci-dessus, on a précisé OPTIONAL pour la déclaration de la variable locale MATRICE
dans la subroutine PRODUIT. Cela signifie que cette subroutine peut être appelée de deux manière :
avec un argument correspondant à matrice ou sans cet argument. En tous cas, il est nécessaire
d’appeler cette subroutine en précisant la correspondance des arguments comme nous venons de
le voir (exemple 4 17).
Nous allons voir dans une premier temps comment obtenir des écritures formatées à l’écran :
L’instruction PRINT*, permet d’afficher à l’écran des chaı̂nes de caractères ou des données numériques,
mais sans préciser le format d’affichage, c’est à dire le nombre d’espaces entre les différentes
données.
Selon les compilateurs, les affichages obtenus ainsi peuvent d’ailleurs être différents
Nous allons donc voir dans un premier temps comment préciser le format d’affichage de données
à l’écran :
L’instruction
WRITE (6,*) <liste variables séparées par ,>
affiche à l’écran la liste des variables. Le 6 est un code précisant que l’écriture doit se faire à
l’écran (et non pas dans un fichier, comme nous le verrons par la suite), et * indique que cet
affichage se faire avec le format par défaut, choisi par le compilateur.
Cette instruction est donc équivalente à PRINT*, .
Un format est une chaı̂ne de caractères, qui contient la liste des formats d’affichage de chacun
des objets devant être affichés.
Il existe un format (au moins) pour chaque type de variable.
• F - est le code destiné aux réels qui sont affichés sous forme “flottante” (pas d’exposant).
Le format F15.6 précise que l’on affichera un réel sur 15 cases à l’écran au total, en réservant
6 cases après la virgule.
Avec 6 chiffres après la virgule, et la virgule elle-même, il ne reste donc que 8 caractères
pour la partie entière du flottant.
Pour afficher les 6 chiffres après la virgule, les règles d’arrondis usuelles sont respectées.
(La valeur affichée sera la valeur la plus proche possible du réel).
Si l’argument correspondant est un réel compris entre 10000000 et 99999999 ou entre -
9999999 et -1000000, il sera donc affiché normalement sur les 15 cases.
Si l’argument correspondant est un réel compris entre 0 et 9999999 ou entre -999999 et 0,
son affichage à l’écran ne nécessiterait que moins de 15 cases. L’affichage est alors complété
à gauche par le nombre d’espaces nécessaires (le réel est aligné à droite).
Si l’argument est un réel supérieur à 100000000 ou inférieur à -10000000, il est impossible
de l’afficher à l’écran sur 15 caractère : l’affichage obtenu est alors ***************.
• E - est le code destiné aux réels qui sont affichés sous forme “exponentielle” (avec exposant).
Le format E15.6 précise que l’on affichera un réel sur 15 cases à l’écran au total, en réservant
6 cases après la virgule, sachant que 4 caractères sont automatiquement réservés pour
l’exposant E+.. ou E-...
Il ne reste donc que 4 caractères pour la partie avant la virgule, mais sous cet affichage, il
n’y a qu’un chiffre avant la virgule dans tous les cas (et éventuellement le signe -).
On utilise donc généralement un format En.m avec n=m+7.
Par exemple, une instruction WRITE (6,’(A3,2X,I5,1X,E12.5)’) C,I,R affiche la chaı̂ne de caractères
Csur 3 caractères, puis 2 espaces, puis l’entier I sur 5 caractères, puis 1 espace, puis le réel R, sur
12 caractères au total avec 5 chiffres après la virgule (et sous le format “exponentiel”).
Par défaut, une instruction WRITE demande à la machine “d’aller à la ligne” après l’affichage.
Ainsi, l’affichage suivant se fera à partir de la première colonne de la ligne du dessous.
Pour éviter ceci, il suffit de préciser ADVANCE=’NO’ dans les arguments de l’instruction WRITE.
Voici un exemple de code utilisant les formats d’affichage à l’écran, suivi de ce que l’on obtient
effectivement à l’écran après l’exécution :
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 47
PROGRAM EXEMPLE5 1
IMPLICIT NONE
REAL :: A
INTEGER :: I,J
CHARACTER*15 :: C
PRINT*, ’BOUCLE 1’
DO J=1,5
A=10.0**(2*J+2) ; I=10**(J+2)
WRITE (6,*) A,I
END DO
PRINT*, ’BOUCLE 2’
DO J=1,5
A=10.0**(2*J+2) ; I=10**(J+2)
WRITE (6,’(E12.5,I7)’) A,I
END DO
PRINT*, ’BOUCLE 3’
DO J=1,5
A=10.0**(2*J+2) ; I=10**(J+2)
WRITE (6,’(E11.5,1X,I7)’) A,I
END DO
PRINT*, ’BOUCLE 4’
DO J=1,5
A=10.0**(2*J+2) ; I=10**(J+2)
WRITE (6,’(F11.5,1X,I7)’) A,I
END DO
C=’AFFICHAGE’
WRITE (6,*) C,C
WRITE (6,’(A,A)’) C,C
WRITE (6,’(A12,A12)’,ADVANCE=’NO’) C,C
WRITE (6,’(A9,A7)’) C,C
WRITE (6,’(A9,1X,A7)’) C,C
WRITE (6,’(A9,1X,A7)’) C,A
! WRITE (6,’(F11.5,1X,I7)’) C,C ! ERREUR A L’EXECUTION...
I=100 ; A=1E12
WRITE (6,’(2(I3,E12.5,A4))’) I,A,C,I,A,C
WRITE (6,’(2(I3,1X,E12.5,1X,A4))’) I,A,C,I,A,C
END PROGRAM EXEMPLE5 1
BOUCLE 1
10000.0 1000
1000000.0 10000
100000000.0 100000
1.0E+10 1000000
1.0E+12 10000000
BOUCLE 2
0.10000E+05 1000
0.10000E+07 10000
0.10000E+09 100000
0.10000E+111000000
0.10000E+13*******
BOUCLE 3
0.10000E+05 1000
0.10000E+07 10000
donne à l’exécution : 0.10000E+09 100000
0.10000E+11 1000000
0.10000E+13 *******
BOUCLE 4
10000.00000 1000
********** 10000
********** 100000
********** 1000000
********** *******
AFFICHAGE AFFICHAGE
AFFICHAGE AFFICHAGE
AFFICHAGE AFFICHAGE AFFICHAGEAFFICHA
AFFICHAGE AFFICHA
AFFICHAGE
100 0.10000E+13AFFI100 0.10000E+13AFFI
100 0.10000E+13 AFFI100 0.10000E+13 AFFI
48 Chapitre 5: Entrées / Sorties
Ce code écrit dans le fichier FIC ce que le programme de l’exemple 5 1 sortait à l’écran (sauf
BOUCLE 1 , ... qui sort toujours à l’écran : l’instruction PRINT*, donnant toujours un affichage
à l’écran...).
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 49
Il arrive fréquemment que l’on soit amené à stocker des grosses quantités de données (souvent
numériques...) dans des fichiers à la fin d’un code. Il est possible de les stocker dans des fichiers
formatés, mais ce stockage nécessite une place disque importante.
On peut les stocker sous format “unformatted”, ce qui signifie que les données sont enregistrées
sous la forme dont elle sont codées dans la mémoire de la machine.
Avantages :
• Cette forme de stockage nécessite environ 10 fois moins de place sur le disque que le
stockage “formaté”,
• le temps mis pour cette écriture est du coup beaucoup plus court.
Inconvénients :
• Il est impossible de visualiser ces données avec un éditeur de texte (l’ouverture du
fichier avec un éditeur de texte donnerait une séries de caractères spéciaux indéchiffrables...),
• il est impossible ou difficile de récupérer ces données sur un autre système, sur une
autre machines, dans un autre langage...
Pour relire de telles données, il suffit de suivre la même syntaxe en remplaçant WRITE par READ.
Il faut que les instructions suivent rigoureusement la même structure.
Exemples:
!
! !
PROGRAM EXEMPLE5 3 !
! PROGRAM EXEMPLE5 4
IMPLICIT NONE !
! IMPLICIT NONE
INTEGER, PARAMETER :: NL=40, NH=40 !
! INTEGER, PARAMETER :: NL=40, NH=40
REAL :: U(0:NL,0:NH+1),V(0:NL+1,0:NH),PHI(NL,NH) !
REAL :: UDU(NL-1,NH),UDV(NL,NH-1) REAL :: U(0:NL,0:NH+1),V(0:NL+1,0:NH),PHI(NL,NH)
! REAL :: UDU(NL-1,NH),UDV(NL,NH-1)
. !
. .
! .
OPEN (10,FILE=’RESTART’,FORM=’UNFORMATTED’) !
READ (10) U,V,UDU,UDV,PHI OPEN (10,FILE=’RESTART’,FORM=’UNFORMATTED’)
CLOSE (10) READ (10) U,V,UDU,UDV,PHI
! CLOSE (10)
. !
. .
! .
OPEN (10,FILE=’RESTART’,FORM=’UNFORMATTED’) !
WRITE (10) U,V OPEN (10,FILE=’RESTART’,FORM=’UNFORMATTED’)
WRITE (10) PHI WRITE (10) U,V,UDU,UDV,PHI
WRITE (10) UDU,UDV CLOSE (10)
CLOSE (10) !
! END PROGRAM EXEMPLE5 4
END PROGRAM EXEMPLE5 3 !
!
Pour relire les informations écrites à la fin de l’exemple 5 3, il faut utiliser la lecture écrite au
début de ce même exemple. De même, pour relire les informations écrites à la fin de l’exemple
5 4, il faut utiliser la lecture écrite au début de ce même exemple.
En revanche, si l’on essaye de relire les informations écrites à la fin de l’exemple 5 4 en utilisant
la lecture écrite au début de l’exemple 5 3 (ou inversement), on aura une erreur à l’exécution.
50 Chapitre 5: Entrées / Sorties
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 51
6.1 Pointeurs
6.1.1 Principe.
Il est souvent utile d’avoir des variables pour lesquelles l’adresse mémoire peut être manipulée
de la même manière que la valeur stockée dans cette adresse. C’est le principe d’un pointeur.
L’adresse mémoire vers laquelle une variable “pointeur” se dirige s’appelle sa cible ; une variable
de type pointeur ne contient donc pas de valeur proprement dit, mais une adresse mémoire
correspondant à une autre variable.
L’utilisation de pointeurs permet, dans certaines situations, d’économiser de l’espace mémoire.
Nous allons voir dans deux utilisations différentes des pointeurs : l’une qui permet de modi-
fier “indirectement” la valeur d’une variable (c’est le fonctionnement en “alias”), et l’autre qui
propose une alternative à l’allocation dynamique de la mémoire.
Nous allons voir, dans cette partie, comment demander à un pointeur de pointer vers l’adresse
d’une certaine variable, et ce que cela implique.
• Déclaration du pointeur :
REAL, POINTER :: PT1
La première déclaration indique que le pointeur PT1 pointe vers une variable de type REAL.
La second précise que PT2 pointera vers un tableau bi-dimensionnel.
On peut d’ores et déjà remarquer que la déclaration du pointeur fixe non seulement le type de
la variable vers laquelle il aura le droit de pointer, mais aussi le rang, dans le cas où la cible est
un tableau.
Les variables X et Y sont des variables de type REAL qui pourront être des cibles de pointeurs.
L’attribut TARGET doit absolument être présent dans la déclaration d’une variable pour que celle-
ci puisse être la cible d’un pointeur.
Les tableaux A et B pourront eux aussi être les cibles d’un pointeur, à condition que ce pointeur
ait été déclaré comme “pointeur tableau”.
Le pointeur PT1 peut donc pointer vers X et Y, le pointeur PT2 peut quand à lui pointer vers A et
B.
Cette instruction précise que le pointeur PT1 pointe vers l’adresse de la cible X.
Concrètement, ceci implique que les accès à PT1, en lecture ou en écriture, concerneront en fait
la variable X.
Exemple :
PROGRAM TESTPOINTER
REAL, POINTER :: P1
REAL, TARGET :: X
REAL, TARGET :: Y
P1=>X
X=2
PRINT*, X,Y,P1
P1=1
PRINT*, X,Y,P1
P1=>Y
PRINT*, X,Y,P1
P1=2
PRINT*, X,Y,P1
END PROGRAM TESTPOINTER
“la lecture” qui revient en fait à la lecture de la variable cible vers laquelle on a fait pointer
au préalable le pointeur,
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 53
“l’écriture” (par une instruction du type PT1=<valeur> ou READ*, PT1 ou autres ...) qui
revient aussi à une écriture sur la variable vers laquelle on a fait pointer le pointeur,
l’affectation ou la modification de la cible (par une instruction du type PT1=> . ) qui
précise la cible vers laquelle on fait pointer le pointeur.
Remarque :
Un pointeur peut pointer vers une cible, ou vers un autre pointeur. Si on tente de faire pointer
un pointeur vers une variable déclarée sans attribut TARGET ni POINTER, on aura une erreur à la
compilation
En fait, ce comportement dépend du compilateur utilisé : certains compilateurs considèrent que
toutes les variables déclarées sont susceptibles d’être les cibles d’un pointeur, ce qui revient à dire
que l’attribut TARGET est facultatif.
Lorsque l’on demande de faire pointer un pointeur vers un autre pointeur, cela signifie en fait
qu’on lui demande de pointeur vers la même cible.
Les cibles peuvent ensuite être modifiées indépendamment, comme l’illustre l’exemple ci-dessous:
PROGRAM TESTPOINTER
REAL, POINTER :: P1,P11
REAL, TARGET :: X
REAL, TARGET :: Y
P1=>X
X=2
P11=>P1
PRINT*, X,Y,P1,P11
P1=1
PRINT*, X,Y,P1,P11
P1=>Y
PRINT*, X,Y,P1,P11
P1=2
PRINT*, X,Y,P1,P11
END PROGRAM TESTPOINTER
Pour que le pointeur PT2 pointe vers un sous tableau de A, on utilise la syntaxe vue dans la section
§3.2.3.
Il est également possible de déclarer dynamiquement les dimensions du tableau pointeur PT2,
sans le faire pointer vers une cible.
Ceci se fait grâce à l’instruction :
54 Chapitre 6: Pointeurs - Types dérivés
Tout se passe alors comme si PT2 avait été défini comme un tableau “allocatable”, c’est à dire
par
Cette utilisation des pointeurs respecte les mêmes règles que l’allocation dynamique (vues à la
section §3.3); nous observerons par la suite (§6.2.2) un avantage de cette dernière technique.
Un tableau permet de regrouper au sein d’une seule variable une certaine quantité d’éléments du
même type.
Un “type dérivé” permet de faire quelque-chose de plus général : il s’agit de regrouper au sein
d’une seule variable des éléments de types différents.
Cette technique n’étant pas très utilisée dans le cadre de la programmation numérique élémentaire,
nous nous contenterons de la présenter très brièvement.
L’exemple suivant permet de comprendre la syntaxe à respecter :
PROGRAM TYPEDER CONTAINS
INTEGER, PARAMETER :: N=20 FUNCTION EVALU (P,X)
TYPE POL TYPE (POL) :: P
REAL, DIMENSION (0:N) :: COEF REAL :: X
INTEGER :: DEGRE REAL :: EVALU
END TYPE POL REAL :: S
TYPE (POL) :: R INTEGER I
R%DEGRE=3 S=P%COEF(P%DEGRE)
R%COEF=0 DO I=P%DEGRE,1,-1
R%COEF(0)=3 S=S*X+P%COEF(I-1)
R%COEF(1)=1 END DO
R%COEF(2)=2 EVALU=S
R%COEF(3)=-3 END FUNCTION EVALU
PRINT*, EVALU (R,2.0) END PROGRAM TYPEDER
On commence par définir un nouveau type, nommé POL, qui contient deux attributs : le premier
est un tableau d’éléments de type REAL de dimension (0:20) (soit 21 réels), le second est un
élément de type INTEGER.
Les différents attributs doivent être énumérés entre les lignes TYPE POL et END TYPE POL.
Lorsque l’on déclare ensuite une variable de type POL (noter que la déclaration se fait par TYPE
(POL) :: R), cette variable R regroupera en fait des éléments de types différents : R%COEF sera un
tableau d’éléments de type REAL de dimension (0:20), et R%DEGRE sera un INTEGER.
Le type défini ici correspond bien-sûr à un polynôme. R%DEGRE est supposé être le degré du
polynôme, R%COEF contient les coefficients (réels).
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 55
La fonction EVALU permet de calculer la valeur d’un polynôme en un point. La fonction ainsi
codée utilise l’algorithme de Horner que l’on peut résumer par la formule :
N !
X
Ri xi = ... RN x + RN −1 x + RN −2 x + RN −3 ... + R2 x + R1 x + R0
i=0
Remarque :
L’un des attributs dans un type dérivé peut lui même être de type dérivé.
C’est le cas dans l’exemple suivant :
PROGRAM TYPEDERDER
TYPE PTS
REAL :: X
REAL :: Y
END TYPE PTS
TYPE DISQUE
TYPE (PTS) :: CENTRE
REAL :: RAYON
END TYPE DISQUE
TYPE (DISQUE) :: C
TYPE (PTS) :: PO
.
.
.
On déclare un type PTS, puis un type DISQUE dont le premier attribut nommé CENTRE est de type
PTS.
La variable C étant de type DISQUE, alors C%CENTRE sera de type PTS, ce qui signifie que C%CENTRE%X
et C%CENTRE%Y seront de type REAL.
Il peut être commode dans certaines situations de faire en sorte que l’un des attributs d’un type
dérivé soit un tableau, dont on ne spécifie par la taille (cette taille pouvant d’ailleurs varier pour
les différentes variables de ce type...)
C’est notamment le cas pour l’exemple vu au début de la précédente section : tous les polynômes
ne sont pas forcément de degré 20 !!!
Pour utiliser l’allocation dynamique au sein d’un type dérivé, il est nécessaire d’utiliser la tech-
nique vue à la section §6.1.3 .
Si on codait de la manière vue à la section §3.3, on obtiendrait en effet une erreur à la compilation.
PROGRAM TYPEDERDYN
TYPE POL
REAL, DIMENSION (:), POINTER :: COEF
INTEGER :: DEGRE
END TYPE POL
TYPE (POL) :: R
ALLOCATE (R%COEF(0:3))
R%DEGRE=3
R%COEF=0
R%COEF(0)=3
R%COEF(1)=1
R%COEF(2)=2
R%COEF(3)=-3
PRINT*, EVALU (R,2.0)
CONTAINS
FUNCTION EVALU (P,X)
TYPE (POL) :: P
REAL :: X
REAL :: EVALU
REAL :: S
INTEGER I
S=P%COEF(P%DEGRE)
DO I=P%DEGRE,1,-1
S=S*X+P%COEF(I-1)
END DO
EVALU=S
END FUNCTION EVALU
END PROGRAM TYPEDERDYN
Notons qu’avec cette deuxième technique, il est indispensable (si on compile avec l’option -u ou
en précisant IMPLICIT NONE) de déclarer la fonction dans l’entête du programme principal, avec
l’attribut EXTERNAL.
En reprenant le premier exemple du chapitre 4, les deux codes suivants sont donc rigoureusement
équivalents.
Lorsque le code est gros (plusieurs dizaines de subroutines et fonctions, plusieurs centaines de
lignes de code au total), la compilation devient longue.
Il peut être intéressant de compiler séparément les différents éléments du code. Ceci peut se faire
en écrivant les différents éléments dans différents fichiers.
Sur notre exemple précédent, on pourrait ainsi créer deux fichiers, l’un que l’on nommera par
exemple f.f90 qui contiendra les lignes de code correspondant à la fonction F, l’autre que l’on
nommera main.f90 qui contiendra les lignes du programme principal.
(L’usage est en effet de donner à chaque fichier correspondant à une fonction le nom de cette
fonction suivi de l’extension f90, et de nommer main.f90 le fichier contenant le programme prin-
cipal. Cet usage ne constitue pas une obligation...)
FUNCTION F(X)
REAL :: X,F
Fichier f.f90 F=X*X+3*X+2
END FUNCTION F
PROGRAM EXEMPLE7 2
REAL :: X1,X2
REAL, EXTERNAL :: F
PRINT*, ’ENTRER LA VALEUR DE X1’
READ*, X1
PRINT*, ’X1=’,’ F(X1)=’,F(X1)
Fichier main.f90 PRINT*, ’ENTRER LA VALEUR DE X2’
READ*, X2
PRINT*, ’X1=’,’ F(X1)=’,F(X2)
END PROGRAM EXEMPLE7 2
La compilation se fait alors en deux étapes : il faut d’abord compiler la fonction par la commande :
f90 -c f.f90
Le compilateur génère alors le fichier f.o (fichier “objet”) qui contient sous forme binaire les
informations relatives à la fonction F.
Ensuite, on compile le programme principal avec la commande :
f90 main.f90 f.o
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 59
De manière générale, si le code complet est écrit dans plusieurs fichiers fic1.f90 fic2.f90 ... ficn.f90
et main.f90, il faut commencer par compiler tous les fichiers contenant les routines et fonctions
(peu importe l’ordre) puis compiler à la fin le programme principal :
f90 main.f90 fic1.o fic2.o ... ficn.o
Cette technique est intéressante dans le cas où l’on ait besoin de modifier le code après une
première compilation (pour corriger des erreurs, par exemple). Pour les compilations suivantes,
il n’est nécessaire de recompiler que les fichiers qui auront été modifiés. Ce gain de temps en
compilation devient intéressant pour les très gros codes.
f (a + 10−5 ) − f (a − 10−5 )
La fonction DERIV ainsi codée renverra la valeur , où f est une fonction
2 × 10−5
réelle.
Cela correspond donc à une approximation de la dérivée de f en a.
On obtient à l’écran :
6.008148
5.00679
27.08435
Exemple : on souhaite créer une bibliothèque de fonctions, procédures, ... concernant les
polynômes :
60 Chapitre 7: Compilation séparée & Modules
PROGRAM POLYNOME
READ*, R%COEF
USE POLYN
PRINT*, EVALU (R,-1.0)
TYPE (POL) :: R
PRINT*, EVALU (R,2.0)
CALL INIT ()
PRINT*, EVALU (PRODUIT(R,R),-1.0)
PRINT*, ’Entrer N’
PRINT*, EVALU (PRODUIT(R,R),2.0)
READ*, N
R=PRODUIT (R,R)
R%DEGRE=N
PRINT*, EVALU (ID,-1.0)
ALLOCATE (R%COEF(0:N),STAT=IERR)
PRINT*, EVALU (ID,2.0)
IF (IERR>0) THEN
R=PRODUIT (R,ID)
PRINT*, ’Probleme dans l’’allocation de A’
PRINT*, EVALU (R,-1.0)
STOP
PRINT*, EVALU (R,2.0)
END IF
END PROGRAM POLYNOME
PRINT*, ’Entrer les coefficients du polynome’
Le premier fichier contient les instructions du module POLYN . Les lignes sont écrites entre MODULE
POLYN et END MODULE POLYN .
Il y a donc la déclaration d’un nouveau type, et de trois variables de ce type (ID, ZERO et UN).
On constate rapidement que, si l’on appelle la procédure INIT, ces variables correspondront alors
à : ID(X)=X ZERO(X)=0 , et UN(X)=1 .
Les tableaux aux pages suivantes recensent les différentes fonctions fortran 90, avec leurs noms
génériques et spécifiques, ainsi que le type des arguments et des résultats (I pour INTEGER, R pour
REAL, D pour DOUBLE ou REAL*8, C pour COMPLEX).
ii Annexe A : Fonctions intrinsèques
Conversion DBLE - I D
en REAL*8 - R D
- D D
(conversion de la partie réelle) - C D
Produit - DPROD 2R D
Fonctions mathématiques
Erreurs à la compilation.
• La première et/ou la dernière lignes (interprétées, c’est à dire non commentées) du fichier
source toto.f90 ne respectent pas les règles énoncées page 3.
• La compilation n’a pas été effectuée dans le répertoire où se situe le code source toto.f90 .
−→ La commande > ls -l permet de s’assurer que le fichier que l’on cherche à compiler
est bien dans le répertoire courant, bien vérifier sa taille et sa date de modification.
Si la taille est nulle, cela signifie que l’éditeur de texte ne sauvegarde pas le fichier,
probablement pour des problèmes d’espace disque (vérifier les quotas).
Si la date de modification ne correspond pas à l’heure de la dernière sauvegarde, cela
signifie que l’on n’est pas dans le même répertoire que celui d’où a été édité le fichier
source.
ii Annexe B : Les erreurs les plus fréquentes...
Erreurs à l’exécution.
• Les calculs conduisent immédiatement à une division par 0 (floatting point exception).
−→ Les règles de calculs et de conversions décrites en bas de page 9 sont souvent oubliées !
Pour fortran 90, 3/4, 1/2 valent 0, de même que 1/N si N est un INTEGER dont la valeur
est supérieure ou égale à 2.
Penser à écrire 3.0/4, 1.0/2 ou 1.0/N pour obtenir les valeurs attendues.
• Une variable locale de l’une des subroutines (ou fonctions) prend des valeurs inattendues.
Bibliographie.