Vous êtes sur la page 1sur 73

Filière GÉNIE MATHÉMATIQUE ET MODÉLISATION

1ère Année d’École - (3ème année Universitaire)

Fortran 90 & Programmation Numérique

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.

F. Bouchon, le 8 Novembre 2021.


Plan i

Chapitre 1: Introduction.

1.1 Quelques notions élémentaires sur les ordinateurs . . . . . . . . . . . . . . . . . . . . . . . 1


1.2 Introduction au langage fortran 90 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.1 Exemple de programme fortran 90 - Règles de base. . . . . . . . . . . . . . . . . . . . 3
1.2.2 Types de données, déclaration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
a. Règles pour la déclaration des variables. . . . . . . . . . . . . . . . . . . . . . . 4
b. Caractères. (CHARACTER type) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
c. Entiers. (INTEGER type) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
d. Réels. (REAL type) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
e. Complexes. (COMPLEX type) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
f. Booléens. (LOGICAL type) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
g. Paramètres. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
h. Déclaration avec affectation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.3 Expressions arithmétiques. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
a. Opérateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
b. Affectations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

Chapitre 2: Boucles et Tests.

2.1 Expressions logiques, tests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11


2.1.1 L’instruction conditionnelle IF (the logical IF statement) . . . . . . . . . . . . . 11
2.1.2 La structure bloc IF-THEN-ELSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2 Les boucles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.1 Boucles indexées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.2 Boucles non indexées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14
2.3 Boucles et Tests ”emboı̂tés” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3.1 Principe, règles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3.2 Contrôles dans les boucles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16
2.4 Branchements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.4.1 L’instruction GOTO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.4.2 Le bloc SELECT CASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .19

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

Chapitre 4: Subroutines et fonctions.

4.1 Objectifs - Premiers exemples. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33


4.2 Variables locales & globales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.3 Subroutines, fonctions et tableaux. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.3.1 Adressage mémoire, ”débordements de tableaux” . . . . . . . . . . . . . . . . . . . . . 38
4.3.2 Passage des dimensions en arguments. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.3.3 Tableaux automatiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.4 Fonctions et procédures “récursives”. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.5 Arguments optionnels. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

Chapitre 5: Entrées / Sorties.

5.1 Formats d’entrées / sorties. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45


5.2 Lectures et écritures dans des fichiers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.2.1 Ouvertures, fermetures, écritures formatées. . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.2.2 Écritures non formatées. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

Chapitre 6: Pointeurs - Types dérivés.

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

Chapitre 7: Compilation séparée & Modules.

7.1 Compilation séparée de gros code, intérêt, syntaxe. . . . . . . . . . . . . . . . . . . . .57


7.2 Exemple de création d’un module. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

Annexe A : Fonctions intrinsèques.

Annexe B : Les erreurs les plus fréquentes....

Bibliographie.
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 1

Chapitre 1: Introduction.

1.1 Quelques notions élémentaires sur les ordinateurs

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.

L’unité de contrôle commande le fonctionnement de la machine entière. Elle permet de :

stocker les différentes instructions en mémoire,

rechercher les instructions du programme, les interpréter et les traiter,

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

Ils ont un vocabulaire spécialisé et limité, et une syntaxe assez stricte.


Ces langages ne sont pas directement compris par le processeur, on a besoin d’un compilateur
qui traduira un programme écrit en langage de niveau élevé en un programme binaire exécutable
par le processeur.

Fortran (de l’anglais FORmula TRANslation), est né au milieu des années 1950. C’était le
premier langage de niveau élevé.

• 1954 : John Backus, d’IBM, est à l’origine du projet de développement du premier


langage symbolique.
• 1957 : Sortie des premiers compilateurs Fortran.
• 1958 : Sortie de Fortran II : apparition de la “compilation séparée”.
Au début des années 1960, on s’occupe du développement de compilateurs
pour les autres constructeurs de machines.
Il naı̂t aussi une commission chargée de développer “une norme fortran”.
• 1966 : Sortie de Fortran IV (ou Fortran 66).
• 1977 : Sortie de Fortran V (ou Fortran 77).
• 1994 : Sortie des compilateurs Fortran 90.
• 1999 : Sortie des compilateurs Fortran 95.
• ???? : Sortie des compilateurs Fortran 2000.
• ???? : Sortie des compilateurs Fortran ????.

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

• renvoyer à l’écran des messages d’avertissement (“Warning”),

• créer un fichier nommé a.out, exécutable binaire compris par le processeur.

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

1.2 Introduction au langage fortran 90

1.2.1 Exemple de programme fortran 90 - Règles de base.


PROGRAM EXEMPLE1
!
INTEGER :: A,B,C
!
PRINT*, ’TAPER AU CLAVIER LA VALEUR DE A’
READ*,A
PRINT*, ’TAPER AU CLAVIER LA VALEUR DE B’
READ*,B
C=A+B
PRINT*, ’LA VALEUR DE C=A+B EST’,C
C=A-B
PRINT*, ’LA VALEUR DE C=A-B EST’,C
C=A*B
PRINT*, ’LA VALEUR DE C=A*B EST’,C
!
END PROGRAM EXEMPLE1

Ce programme élémentaire permet déjà de comprendre les points suivants :

• 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

Règles de bases concernant la structure du code source


Le code source désigne l’ensemble des instructions écrites dans le fichier portant l’extension f90.
La seule restriction concernant ce code est que seuls les 127 premiers caractères de chaque ligne
sont pris en compte. Cela signifie que si l’on code une commande sur une ligne trop longue, les
caractères tapés après la 128ème colonne ne sont pas pris en compte par le compilateur, ce qui
risque fort d’entraı̂ner une erreur de syntaxe.
Il est possible de contourner ce problème en scindant une instruction sur deux ou plusieurs lignes.
Il suffit pour cela d’ajouter le caractère & à la fin de la première ligne; le compilateur comprend
alors que cette ligne ne constitue pas une instruction à elle seule, mais que cette instruction se
prolonge sur la ligne suivante.
Exemple :
A = V+Z*(C+E)**(A-B)+D-E*A+B-T/D+(T+M/G)/R+G*E+Z*(C+E)**(C-B)+D-E*C+B-U/D+(T+A*G)/R+G*E
est équivalent à :
A = V+Z*(C+E)**(A-B)+D-E*A+B-T/D+(T+M/G)/R+G*E &
+Z*(C+E)**(C-B)+D-E*C+B-U/D+(T+A*G)/R+G*E

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.

1.2.2 Types de données, déclaration.

a. Règles pour la déclaration des variables.

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

• La taille est limitée à 31 caractères.

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 :

• t désignera en général un temps, x gauche pourra désigner l’abscisse de l’extrémité gauche


d’un segment, ...

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

b. Caractères. (CHARACTER type)

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, -*+,;.&# ...)

c. Entiers. (INTEGER type)

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.

d. Réels. (REAL type)

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,

• 0 ≤ m < 1 s’appelle la “mantisse”,

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

L’un des bits correspond à ε, son signe + ou −.


Les 8 bits suivants correspondent à l’exposant. Cet exposant peut donc prendre 28 = 256 valeurs
différentes, qui sont les entiers allant de −128 à +127 inclus.
Les 23 bits restants servent à stocker la mantisse, comprise entre 0 et 1.
Le plus grand réel stockable ainsi est donc rmax = 1 × mmax × 2127∼< 2127 ≈ 1.7014118 × 1038 .
Le plus petit est son opposé (−1.7014118 × 1038 ).

Le réel strictement positif le plus proche de 0 stockable est


rmin = 1 × mmin × 2−127 = 2−22 × 2−127 = 2−149 ≈ 1.4012985 × 10−45

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.

L’un des bits correspond à ε, son signe + ou −.


Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 7

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

Le réel strictement positif le plus proche de 0 stockable est


rmin = 1 × mmin × 2−1024 = 2−52 × 2−1024 = 2−1074 ≈ 4.940656458412465 × 10−324

La précision relative est donc ici de 2−52 , c’est à dire de l’ordre de 2.220446 × 10−16 .

e. Complexes. (COMPLEX type)

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.

f. Booléens. (LOGICAL type)

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.

h. Déclaration avec affectation.

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.

1.2.3 Expressions arithmétiques.

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.

Autre exemple conduisant au même résultat :


B=10**(-6)
est correcte, elle évalue l’expression entière 10**(-6), obtient donc l’entier 0. B prend donc encore
la valeur 0.0 et non pas 1E-6...
10 Chapitre 1: Introduction
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 11

Chapitre 2: Boucles et Tests.

2.1 Expressions logiques, tests.

Ce paragraphe a pour objet de présenter les différentes syntaxes possibles pour coder les tests
en fortran 90.

2.1.1 L’instruction conditionnelle IF (the logical IF statement)

La syntaxe est IF (booléen) <instruction>


L’instruction qui suit n’est exécutée que si le booléen a la valeur .TRUE. .

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

ENTRER LA VALEUR DU REEL A


ENTRER LA VALEUR DU REEL A
3.0
2
donne à l’exécution : ENTRER LA VALEUR DU REEL B ou ENTRER LA VALEUR DU REEL B
1.0
2
A EST STRICTEMENT PLUS GRAND QUE B

2.1.2 La structure bloc IF-THEN-ELSE

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

ENTRER LA VALEUR DU REEL A


3.0
ENTRER LA VALEUR DU REEL A
ENTRER LA VALEUR DU REEL B
2
donne à l’exécution : 1.0 ou ENTRER LA VALEUR DU REEL B
A EST STRICTEMENT PLUS GRAND QUE B
2
A= 3.0
B= 1.0
12 Chapitre 2: Boucles et Tests

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 !

2.2 Les boucles

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

2.2.1 Boucles indexées

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.

La première valeur prise par I est donc A.


Les valeurs suivantes seront donc A+αC pour α = 1, 2, ... tant que cette valeur reste comprise dans
l’intervalle [A,B] au sens large.

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.

Si le pas est nul, le code reste coincés dans la boucle indéfiniment.

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

2.2.2 Boucles non indexées

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 :

DO WHILE (expression logique)


instructions
instructions
END DO

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

2.3 Boucles et Tests ”emboı̂tés”

2.3.1 Principe, règles


Il est possible “d’emboı̂ter” (ou “d’imbriquer”, ....) des boucles et des tests les uns dans les
autres.

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

Le premier DO (indexé par I) correspond à la boucle “extérieure”. Le second (indexé par J)


correspond à la boucle intérieure.
La machine interprète de la manière suivante :
Pour I allant de 1 à 3, faire pour J allant de 1 à 5...
Elle attribue donc dans un premier temps la valeur 1 à I et pour cette valeur, fait varier J de 1
à 5.
Une fois que J a pris la valeur 5 dans la boucle interne, on passe à la valeur I=2 et on refait
varier J de 1 à 5.
Une fois que J a pris la valeur 5 dans la boucle interne, on passe à la valeur I=3 et on refait
varier J de 1 à 5.
On obtient donc à l’exécution :
16 Chapitre 2: Boucles et Tests

LE CUBE DE 1 EST SUPERIEUR OU EGAL AU CARRE DE 1


LE CUBE DE 1 EST STRICTEMENT INFERIEUR AU CARRE DE 2
LE CUBE DE 1 EST STRICTEMENT INFERIEUR AU CARRE DE 3
LE CUBE DE 1 EST STRICTEMENT INFERIEUR AU CARRE DE 4
LE CUBE DE 1 EST STRICTEMENT INFERIEUR AU CARRE DE 5
LE CUBE DE 2 EST SUPERIEUR OU EGAL AU CARRE DE 1
LE CUBE DE 2 EST SUPERIEUR OU EGAL AU CARRE DE 2
LE CUBE DE 2 EST STRICTEMENT INFERIEUR AU CARRE DE 3
LE CUBE DE 2 EST STRICTEMENT INFERIEUR AU CARRE DE 4
LE CUBE DE 2 EST STRICTEMENT INFERIEUR AU CARRE DE 5
LE CUBE DE 3 EST SUPERIEUR OU EGAL AU CARRE DE 1
LE CUBE DE 3 EST SUPERIEUR OU EGAL AU CARRE DE 2
LE CUBE DE 3 EST SUPERIEUR OU EGAL AU CARRE DE 3
LE CUBE DE 3 EST SUPERIEUR OU EGAL AU CARRE DE 4
LE CUBE DE 3 EST SUPERIEUR OU EGAL AU CARRE DE 5

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.

2.3.2 Contrôles dans les boucles


Les instructions CYCLE et EXIT permettent de “sortir” d’une boucle ou de passer à l’exécution
suivante.
Exemple :
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 17

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

2.4.1 L’instruction GOTO

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

SAISIR LES VALEURS DE A,B,C


SEPAREES PAR UNE ,
2 2 2
I= 2
ON EST SORTI DE LA BOUCLE
I EST PLUS GRAND QUE 5, JE RECOMMENCE
SAISIR LES VALEURS DE A,B,C
SEPAREES PAR UNE ,
2 6 2
I= 2
donne à l’exécution : I= 4
I= 6
I EST PLUS GRAND QUE 5, JE RECOMMENCE
SAISIR LES VALEURS DE A,B,C
SEPAREES PAR UNE ,
2 8 3
I= 2
I= 5
I= 8
I EST PLUS GRAND QUE 6, ON ARRETE

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.

2.4.2 Le bloc SELECT CASE


PROGRAM EXEMPLE2 15
INTEGER :: I
INTEGER, PARAMETER :: N=17
PRINT*, ’ENTRER I’
READ*, I
SELECT CASE (I)
CASE (2,3,5,7)
PRINT*, ’ I EST PREMIER’
PRINT*, ’ ET PLUS PETIT STRICTEMENT QUE 11’
CASE (N)
PRINT*, ’I=N’
CASE (8:10)
PRINT*, ’I EST COMPRIS AU SENS LARGE ENTRE 8 ET 10’
CASE (26:)
PRINT*, ’I EST PLUS GRAND OU EGAL A 26’
CASE (:-3)
PRINT*, ’I EST PLUS PETIT QUE -3’
CASE DEFAULT
PRINT*, ’COMPRIS ENTRE -2 ET25, MAIS&
& DIFFERENT DE 2,3,5,7,8,9,10 ...’
END SELECT
END PROGRAM EXEMPLE2 15

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

3.1.1 Tableaux monodimensionnels (“vecteurs”)

Un tableau permet de regrouper au sein de la même variable une famille de données de mêmes
types.

Par exemple, pour un tableau à 5 éléments réels, on déclare :


REAL :: A(5)
ou
REAL, DIMENSION (5) :: A

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 de faire en sorte que l’index ne commence pas à 1 :


exemples :
REAL :: A(0:3)
→ A est un tableau à 4 éléments : A(0), A(1), A(2) et A(3)
REAL, DIMENSION (-2:7) :: A
→ A est un tableau à 10 éléments : A(-2), A(-1), A(0) ..... et A(7).

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.

3.1.2 Tableaux multi-dimensionnels

On peut déclarer des tableaux à 2, 3, ... indexes :


22 Chapitre 3: Tableaux

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.

3.2.1 Opérations sur chaque élément .

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

3.2.2 Opérations globales.

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

est valide, à condition que les tableaux A et B soient conformants.


Chaque élément du tableau A prend les valeurs du tableau B.

Rappel : pour que deux tableau soient conformants, il doivent avoir la même forme. Il faut
donc que :

• Ces deux tableaux aient le même nombre d’indexes,

• 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

3.2.3 Opérations sur des “sous-tableaux”.

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.

Cette ligne de commande est en fait équivalente à


DO I=1,2
DO J=1,4
A (5-4*(I-1),J+1) = B(6+I,J*2-1)*C (I,5-J) + D(I-1,J+4)
END DO
END DO

Attention On constate que “∗” pour des matrices est le produit “terme à terme” et non pas le
produit matriciel !

Définitions plus complexes de sous-tableaux :

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

Pourtant, dans la seconde, les tableaux A(2:3,6:2:-2,1:1) et B sont de dimensions respectives


(2,3,1) et (2,3), ces deux tableaux ne sont effectivement pas conformants.

L’instruction A (2:3,6:2:-2,1) = B est correcte et comprise par fortran 90 car A (2:3,6:2:-2,1)


désigne un tableau à double entrée de dimensions (2,3).
On peut insérer des scalaires dans ce type d’instruction: ils seront interprétés comme des tableaux
de “la bonne taille” contenant le scalaire.
Ex:
A (2:3,6:2:-2,1) = B + 2
va attribuer aux éléments correspondant de A ceux de B + 2.
Remarque: lorsque fortran 90 rencontre ce type d’instruction, il réserve un espace mémoire où il
fabrique le bloc de droite avant de stocker le résultat dans le bloc de gauche.
Exemple:
L’instruction
A(2:3,6:2:-2,1) = A(2,4,1) * B
fortran 90 fabrique un tableau prenant les valeurs des élément de B multipliés par A(2,4,1) et les
stocke dans le sous-tableau de A désignés. fortran 90 ne tient pas compte du fait que A(2,4,1) a
été modifié pour les modifications suivantes...
L’instruction ci-dessus n’équivaut donc pas à
do i = 1,2
do j = 1,3
A (1+i,8-2*j,1) = A(2,4,1) * B(i,j)
end do
end do

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

Question : que fait l’instruction


B (:,i:j:j-i) = B (:,j:i:i-j)
(i et j sont deux entiers compris entre 1 et 3...)
→ cette instruction permet d’intervertir les colonnes i et j d’un tableau.
28 Chapitre 3: Tableaux

3.3 Allocation dynamique de la mémoire

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

(L’instruction stop permet d’interrompre l’exécution du programme.)

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

3.4 Fonctions intrinsèques travaillant sur les tableaux.


• SHAPE (A) : renvoie la forme du tableau A sous forme d’un tableau unidimensionnel d’entiers.
Exemples :
REAL, DIMENSION (-4:7,15,12:13) :: A
REAL, DIMENSION (3) :: B
INTEGER, DIMENSION (4,-1:2) :: C
SHAPE (A) est le tableau (/12,15,2/),
SHAPE (B) est le tableau (/3/)
et SHAPE (C) est le tableau (/4,4/)

Remarque : l’affectation B=SHAPE(A) est valide !


30 Chapitre 3: Tableaux

• LBOUND : limites inférieures.


Renvoie un tableau unidimensionnel d’entiers, contenant les valeurs inférieurs pouvant être
prises par les indices successifs.
LBOUND (A) est le tableau : (/-4,1,12/)
LBOUND (A,1) est l’integer -4
LBOUND (A,2) est l’integer 1
LBOUND (A,3) est l’integer 12

• UBOUND : limites supérieures.


Renvoie un tableau unidimensionnel d’entiers, contenant les valeurs supérieures pouvant
être prises par les indices successifs.

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

Attention, pour ce type d’affectation, on ne peut pas utiliser la technique du remplissage


ci-dessus.
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 31

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

• CSHIFT : décale les éléments dans un tableau :


REAL, DIMENSION (4) :: A,B
A= RESHAPE ((/1,2,3,4/),(/4/))
B=CSHIFT (A,-1)
décale les éléments de A vers la droite.
B est le tableau : (/4,1,2,3/)

Avec les tableau multi-dimensionnels :


REAL, DIMENSION (4,-1:2) :: C
CSHIFT (C,1,2) décale selon la deuxième dimension de 1.

• Affectations masquées : WHERE

Exemples : WHERE (A.GT.3) A=A+1


avec l’exemple ci-dessus : A devient (/1,2,3,5/).
Cette écriture permet donc de condenser une combinaison de boucles et tests.

Deuxième type d’utilisation:


REAL, DIMENSION (4,4) :: A,B,C
WHERE (B.LT.3)
A=LOG(3-B)
C=A*A
ELSEWHERE
B=3
ENDWHERE

Il est Possible de travailler sur des sous-tableaux avec WHERE.


32 Chapitre 3: Tableaux

• MAX Renvoie le maximum d’une liste d’objets.


Par exemple : MAX(12,5,4,17,5) renvoie 17.
Le résultat est du même type que chacun des objets. On peut travailler avec n’importe
quel type d’objets : entiers, réels et même tableaux !
Par exemple :
MAX((/1,2/),(/-3,4/))
Le résultat est un vecteur de deux éléments : chacun des éléments étant le maximum de
ceux des deux tableaux : on obtient ici (/1,4/).

Attention : du-coup : MAX((/12,5,4,17,5/)) est le tableau ((/12,5,4,17,5/)) !


• MAXVAL
renvoie le plus grand élément contenu dans le tableau A.
MAXVAL(A)
 
1 3 4
Par exemple : si A= alors MAXVAL(A) renvoie 5.
2 5 3

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

• MIN, MINVAL, MINLOC fonctionnent de la même manière, mais recherchent le minimum.


• SUM
SUM(A)renvoie la somme des éléments contenus dans le tableau A.
 
1 3 4
On reprend l’exemple : A= alors SUM(A) renvoie 18.
2 5 3

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

Chapitre 4: Subroutines et fonctions.

4.1 Objectifs - Premiers exemples.

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 :

On veut afficher la valeur de x2 + 3x + 2 pour deux valeurs successivement saisies au clavier. On


peut coder ceci tout simplement de la manière suivante :
34 Chapitre 4: Subroutines et fonctions

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

On peut également coder ceci en utilisant une subroutine :


PROGRAM EXEMPLE4 3
REAL :: X1,X2,RES
PRINT*, ’ENTRER LA VALEUR DE X1’
READ*, X1
CALL F(X1,RES)
PRINT*, ’X1=’,’ F(X1)=’,RES
PRINT*, ’ENTRER LA VALEUR DE X2’
READ*, X2
CALL F(X2,RES)
PRINT*, ’X2=’,’ F(X2)=’,RES
CONTAINS
SUBROUTINE F(X,R)
REAL,INTENT (IN) :: X
REAL,INTENT (OUT):: R
R=X*X+3*X+2
END SUBROUTINE F
END PROGRAM EXEMPLE4 3

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 :

• lues (on précise alors INTENT (IN)),

• modifiées (on précise alors INTENT (OUT)),

• lues et modifiées (on précise alors INTENT (INOUT)).

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.

4.2 Variables locales & globales.

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

Il est possible d’utiliser une variable ou un paramètre du programme principal.

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

Cas des variables figurant parmi les arguments de la subroutine/fonction :


Ces variables locales ne nécessitent pas de réservation supplémentaire d’espace mémoire. En effet,
fortran 90 lit ou modifie directement les arguments qui figurent dans le programme principal dans
“l’appel” à la subroutine/fonction.

Cas où la même variable apparaı̂t plusieurs fois dans l’appel


Il est possible de faire apparaı̂tre plusieurs fois la même variable dans l’appel, comme dans
l’exemple ci-dessous.

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.

Ainsi, lorsqu’on modifie T,on modifie C, et on modifie de même Z !!!


On obtient à l’exécution : 2.0 1.0 6.0

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

4.3 Subroutines, fonctions et tableaux.

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

4.3.1 Adressage mémoire, ”débordements de tableaux”

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

donne à l’exécution : 1.0 1.0 1.0 0.0E+0 0.0E+0


Lors de l’appel, il y a correspondance entre l’adresse mémoire du premier élément du tableau A
du programme principal et le premier élément du tableau B de la subroutine.

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→

Troisième exemple : avec des tableaux bidimensionnels dans le programme principal :


Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 39

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

Lors de l’appel à MODIF, il y a correspondance entre l’adresse mémoire du premier élément du


tableau A du programme principal et le premier élément du tableau B de la subroutine.
Cette subroutine demande de modifier les six éléments du tableau B, c’est à dire les six premiers
éléments du tableau A, c’est à dire A(1,1), A(2,1), A(3,1), A(4,1), A(1,2) A(2,2).

A(1,1) A(4,1)A(1,2) A(4,2)A(1,3) A(4,3)A(1,4) A(4,4)

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(1,1) A(4,1)A(1,2) A(4,2)A(1,3) A(4,3)A(1,4) A(4,4)

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

Le message d’erreur à la compilation est le suivant :


40 Chapitre 4: Subroutines et fonctions

>f90 exemple4.5d.f90

CALL MODIF (A)


^
"exemple4.5d.f90", Line = 4, Column = 15: ERROR: The overall size of the
dummy argument array is greater than the size of this actual argument.

f90: COMPILE TIME 0.050000 SECONDS


f90: MAXIMUM FIELD LENGTH 4758540 DECIMAL WORDS
f90: 11 SOURCE LINES
f90: 1 ERRORS, 0 WARNINGS, 0 OTHER MESSAGES, 0 ANSI

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

0.0E+0 0.0E+0 0.0E+0 1.0 1.0


donne à l’exécution : 1.0 1.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 quatre éléments du tableau B, c’est à dire les quatrième et
cinquième éléments du tableau A... ainsi que des éléments situés aux adresses mémoires suivantes,
ici les deux premiers éléments du tableau A2.

A(1) A(5) A2(1) A2(5)

A→ ←A2
B→

Attention : Ce type de comportement est très “machine/compilateur-dépendant”, ce qui signifie


qu’on obtiendra pas forcément exactement le même résultat selon la machine sur laquelle on
travaille.
Par exemple, certains compilateurs ne stockeront pas le tableau A2 immédiatement après le
tableau, comme ça semble être le cas ici.

Il est naturellement souhaitable d’éviter ce type de débordement de tableau. Un moyen simple


de détecter ce type de problème est de compiler avec l’option “-C” ou “-fbounds-check” selon la
machine utilisée.
Ainsi, si le code ci-dessus est compilé avec cette option, on obtiendra une erreur à l’exécution,
précisant qu’il y a eu “débordement de tableau”.

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

0.0E+0 0.0E+0 1.0 1.0


donne à l’exécution : 1065353216 1065353216 0 0

4.3.2 Passage des dimensions en arguments.

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

4.3.3 Tableaux automatiques

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

4.4 Fonctions et procédures “récursives”.

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

ENTRER LA VALEUR DE L’ENTIER N


donne à l’exécution : 10
LA FACTORIELLE DE 10 EST 3628800
Entêtes équivalentes :
INTEGER RECURSIVE FUNCTION FAC (N) RESULT (F N)
ou encore :
RECURSIVE INTEGER FUNCTION FAC (N) RESULT (F N)
à condition d’enlever, pour cette dernière, la ligne : INTEGER :: F N qui ferait “double effet”...

On s’aperçoit qu’il est nécessaire de déclarer de manière spécifique la variable correspondant au


résultat de la fonction (ici : F N) de manière à éviter toute confusion avec certaines valeurs de la
fonction que la fonction utilise elle-même (ici : FAC(N-1)).
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 43

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

(Ce code fournit les mêmes résultats que le précédent...)

4.5 Arguments optionnels.


Appel à une subroutine en précisant les arguments:
On peut préciser explicitement, lors de l’appel à une subroutine, la correspondance entre les
variables du programme principal et les variables locales de la subroutine.
Exemple :

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

La fonction PRESENT, à résultat booléen, permet de savoir si l’argument correspondant à la matrice


était présent dans l’appel ou non.
Pour le premier appel (CALL PRODUIT (VECTEUR=X,RESULTAT=Y,MATRICE=A)), la fonction PRESENT ren-
verra le résultat .TRUE. et on fera donc bien le produit matrice vecteur.
Pour le deuxième appel (CALL PRODUIT (VECTEUR=X,RESULTAT=Y)), la fonction PRESENT renverra le
résultat .FALSE. et on fera donc simplement une copie de VECTEUR dans RESULTAT, c’est à dire une
copie de X dans Y.
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 45

Chapitre 5: Entrées / Sorties.

5.1 Formats d’entrées / sorties.

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*, .

Pour obtenir une écriture formatée, il suffit de remplacer * par un format.

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.

• A - est le code destiné aux chaı̂nes de caractères.


Le format A10 précise que l’on affichera une chaı̂nes de 10 caractères.
Si l’argument correspondant est une chaı̂ne de moins de 10 caractères, elle sera complétée
à droite par des espaces pour occuper au total 10 cases à l’écran.
Si l’argument correspondant est une chaı̂ne de plus de 10 caractères, seuls les 10 premiers
seront affichés.
• I - est le code destiné aux entiers (INTEGER).
Le format I5 précise que l’on affichera un entier sur 5 cases à l’écran.
Si l’argument correspondant est un entier compris entre 10000 et 99999 ou entre -9999 et
-1000, il sera donc affiché normalement sur les 5 cases.
Si l’argument correspondant est un entier compris entre 0 et 9999 ou entre -999 et 0, son
affichage à l’écran ne nécessiterait que moins de 5 cases. L’affichage est alors complété à
gauche par le nombre d’espaces nécessaires (on dit que l’entier est aligné à droite).
Si l’argument est un entier supérieur à 100000 ou inférieur à -10000, il est impossible de
l’afficher à l’écran sur 5 caractère : l’affichage obtenu est alors *****.
46 Chapitre 5: Entrées / Sorties

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

• X permet d’insérer des espaces entre les différentes données.

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

5.2 Lectures et écritures dans des fichiers.

5.2.1 Ouvertures, fermetures, écritures formatées.


Il est également possible d’écrire directement dans des fichiers en utilisant l’instruction WRITE.
Il faut, au préalable, “ouvrir” le fichier avec l’instruction OPEN.
Il faut respecter la syntaxe suivante :
OPEN (I,FILE=’nom fic’,FORM=’FORMATTED’).
où I est un entier, compris entre 7 et 20.
En suite les instruction WRITE (I,...) permettront d’écrire directement dans le fichier nom fic au
fur et à mesure, et l’instruction CLOSE (I) ferme le fichier (ce qui signifie simplement qu’on ne
peut plus écrire dedans de cette manière).
On précise le format d’écriture dans le fichier exactement de la même manière que pour les
affichages à l’écran.
Attention : le premier WRITE (I,...) suivant le OPEN (I,FILE=’nom fic’,...) “écrase” le fichier,
ce qui signifie que si ce fichier existait déjà avant l’instruction OPEN, alors son contenu est
définitivement perdu.
Exemple :
PROGRAM EXEMPLE5 2
IMPLICIT NONE
REAL :: A
INTEGER :: I,J
CHARACTER*15 :: C
OPEN (13,FILE=’FIC’,FORM=’FORMATTED’)
PRINT*, ’BOUCLE 1’
DO J=1,5
A=10.0**(2*J+2) ; I=10**(J+2)
WRITE (13,*) A,I
END DO
PRINT*, ’BOUCLE 2’
DO J=1,5
A=10.0**(2*J+2) ; I=10**(J+2)
WRITE (13,’(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 (13,’(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 (13,’(F11.5,1X,I7)’) A,I
END DO
C=’AFFICHAGE’
WRITE (13,*) C,C
WRITE (13,’(A,A)’) C,C
WRITE (13,’(A12,A12)’,ADVANCE=’NO’) C,C
WRITE (13,’(A9,A7)’) C,C
WRITE (13,’(A9,1X,A7)’) C,C
WRITE (13,’(A9,1X,A7)’) C,A
! WRITE (13,’(F11.5,1X,I7)’) C,C ! ERREUR A L’EXECUTION...
I=100 ; A=1E12
WRITE (13,’(2(I3,E12.5,A4))’) I,A,C,I,A,C
WRITE (13,’(2(I3,1X,E12.5,1X,A4))’) I,A,C,I,A,C
CLOSE (13)
END PROGRAM EXEMPLE5 2

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

5.2.2 Écritures non formatées.

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

Chapitre 6: Pointeurs - Types dérivés.

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.

6.1.2 Pointeurs et cibles.

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

REAL, DIMENSION (:,:), POINTER :: PT2

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.

• Déclaration des cibles :


REAL, TARGET :: X,Y

REAL, DIMENSION (4,3), TARGET :: A

REAL, DIMENSION (3,4), TARGET :: B


52 Chapitre 6: Pointeurs - Types dérivés

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.

• Attribution d’une cible à un pointeur :


PT1=>X

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

2.0 0.0 2.0


1.0 0.0 1.0
1.0 0.0 0.0
1.0 2.0 2.0

Dans un premier temps, le pointeur PT1 pointe vers X.


Ainsi, au premier affichage, la dernière valeur écrite sur la ligne est celle de la variable X qui a
été affectée à 2 juste avant l’affichage.
Ensuite, la ligne PT1=1 ne modifie pas la valeur de PT1 (qui n’est pas une variable, mais un pointeur
!) : elle précise que la variable vers laquelle pointe PT1 doit être modifiée pour prendre la valeur
1.
C’est pourquoi, après cette instruction, X prend la valeur 1.
On modifie ensuite l’adresse vers laquelle pointe PT1 pour le faire pointer vers Y, l’instruction
PT1=2 modifiera donc la valeur de la variable Y.

Trois types d’instructions différents peuvent donc concerner un pointeur :

“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

qui donne à l’exécution:


2.0 0.0 2.0 2.0
1.0 0.0 1.0 1.0
1.0 0.0 0.0 1.0
1.0 2.0 2.0 1.0

6.1.3 Pointeurs et tableaux, allocation dynamique.

On peut demander à un pointeur-tableau de pointer vers un tableau tout entier, ou vers un


sous-tableau.
Par exemple, avec les déclarations écrites dans la section précédente, l’instruction PT2=>A demande
au pointeur PT2 de pointer vers le tableau A tout entier.

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

ALLOCATE (PT2 (80,80))

Tout se passe alors comme si PT2 avait été défini comme un tableau “allocatable”, c’est à dire
par

REAL, DIMENSION (:,:), ALLOCATABLE :: PT2

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.

6.2 Types dérivés

6.2.1 Principe, exemple.

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

Le polynôme R de notre code est le polynôme −3X 3 + 2X 2 + X + 3.


Sa valeur pour X = 2 est égale à −11. L’exécution donnera à l’écran cette valeur −11.

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.

6.2.2 Types dérivés et allocation dynamique.

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.

Lorsque l’on exécute le code suivant,


56 Chapitre 6: Pointeurs - Types dérivés

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

on retrouve le résultat −11.


Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 57

Chapitre 7: Compilation séparée & Modules.

7.1 Compilation séparée de gros code, intérêt, syntaxe.


Nous avions vu dans le chapitre 4 une première technique pour coder des subroutines et des
fonctions, la syntaxe générale était :
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
routines / fonctions
FUNCTION FONC (X) 

Déclarations des variables locales




(parmi lesquelles Xet F)




lignes de code utilisant X et attribuant une valeur à FONC





.. 
END FUNCTION FONC
END PROGRAM MACHIN
Une deuxième possibilité est la suivante :
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 routines / fonctions
FUNCTION FONC (X) 


Déclarations des variables locales 



(parmi lesquelles Xet F) 



lignes de code utilisant X et attribuant une valeur à FONC 




..
END FUNCTION FONC
PROGRAM MACHIN
Déclarations parmi lesquelles : REAL, EXTERNAL :: FONC ← programme principal
lignes de code parmi lesquelles CALL SUB (...) et/ou FONC(...)
..
END PROGRAM MACHIN
58 Chapitre 7: Compilation séparée & Modules

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.

PROGRAM EXEMPLE4 2 FUNCTION F(X)


REAL :: X1,X2 REAL :: X,F
PRINT*, ’ENTRER LA VALEUR DE X1’ F=X*X+3*X+2
READ*, X1 END FUNCTION F
PRINT*, ’X1=’,’ F(X1)=’,F(X1) PROGRAM EXEMPLE7 1
PRINT*, ’ENTRER LA VALEUR DE X2’ REAL :: X1,X2
READ*, X2 REAL, EXTERNAL :: F
PRINT*, ’X2=’,’ F(X2)=’,F(X2) PRINT*, ’ENTRER LA VALEUR DE X1’
CONTAINS READ*, X1
FUNCTION F(X) PRINT*, ’X1=’,’ F(X1)=’,F(X1)
REAL :: X,F PRINT*, ’ENTRER LA VALEUR DE X2’
F=X*X+3*X+2 READ*, X2
END FUNCTION F PRINT*, ’X1=’,’ F(X1)=’,F(X2)
END PROGRAM EXEMPLE4 2 END PROGRAM EXEMPLE7 1

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.

Fonction dont l’argument est une fonction :


Lorsque l’on souhaite coder une fonction pour laquelle l’un des arguments est une fonction, la
syntaxe est la suivante :
FUNCTION DERIV (A,F)
REAL :: A,DERIV
INTERFACE
REAL FUNCTION F(X)
REAL, INTENT(IN) :: X
END FUNCTION F
END INTERFACE
DERIV = (F(A+1E-5)-F(A-1E-5))/2E-5
END FUNCTION DERIV

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.

Ainsi, le code suivant permettra le calcul de trois dérivées approximatives successives :


FUNCTION F1(X)
REAL FUNCTION F(X)
REAL :: X,F1
REAL, INTENT(IN) :: X
F1=X*X
END FUNCTION F
END FUNCTION F1
END INTERFACE
FUNCTION F2(X)
DERIV = (F(A+1E-5)-F(A-1E-5))/2E-5
REAL :: X,F2
END FUNCTION DERIV
F2=X*X-X
PROGRAM CALCUL DERIV
END FUNCTION F2
REAL :: A
FUNCTION F3(X)
REAL, EXTERNAL :: F1,F2,F3,DERIV
REAL :: X,F3
A=3
F3=X*X*X
PRINT*, DERIV (A,F1)
END FUNCTION F3
PRINT*, DERIV (A,F2)
FUNCTION DERIV (A,F)
PRINT*, DERIV (A,F3)
REAL :: A,DERIV
END PROGRAM CALCUL DERIV
INTERFACE

On obtient à l’écran :
6.008148
5.00679
27.08435

7.2 Exemple de création d’un module.

Un module permet de regrouper des déclarations de variables, de subroutines, de fonctions et de


types dérivés qui vont être communs à plusieurs éléments d’un code.

Exemple : on souhaite créer une bibliothèque de fonctions, procédures, ... concernant les
polynômes :
60 Chapitre 7: Compilation séparée & Modules

MODULE POLYN S=P%COEF(P%DEGRE)


TYPE POL DO I=P%DEGRE,1,-1
REAL, DIMENSION (:), POINTER :: COEF S=S*X+P%COEF(I-1)
INTEGER :: DEGRE END DO
END TYPE POL EVALU=S
TYPE (POL) :: ID,ZERO,UN END FUNCTION EVALU
CONTAINS TYPE (POL) FUNCTION PRODUIT (Q,R)
SUBROUTINE INIT () TYPE (POL) :: Q,R
ID%DEGRE=1 INTEGER :: N,M,P
ALLOCATE (ID%COEF(0:1)) INTEGER :: I,J
ID%COEF=(/0,1/) N=Q%DEGRE
ZERO%DEGRE=0 M=R%DEGRE
ALLOCATE (ZERO%COEF(0:0)) P=M+N
ZERO%COEF=(/0/) ALLOCATE (PRODUIT%COEF(0:P),STAT=IERR)
UN%DEGRE=0 PRODUIT%DEGRE=P
ALLOCATE (UN%COEF(0:0)) PRODUIT%COEF=0
UN%COEF=(/1/) DO I=0,N
END SUBROUTINE INIT DO J = 0 , M
FUNCTION EVALU (P,X) PRODUIT%COEF(I+J)=Q%COEF(I)*R%COEF(J)&
TYPE (POL) :: P +PRODUIT%COEF(I+J)
REAL :: X END DO
REAL :: EVALU END DO
REAL :: S END FUNCTION PRODUIT
INTEGER I END MODULE POLYN

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 .

La compilation se fait de la manière suivante : si le fichier contenant le module s’appelle mod.f90


et le fichier principal main.f90 :
f90 -c mod.f90
puis f90 main.f90 mod.o
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 i

Annexe A : Fonctions intrinsèques.


Il existe un grand nombre de fonctions numériques en fortran 90. Pour les utiliser, il n’est pas
nécessaire de faire appel à des extensions, librairies, ...
La plupart des fonctions fortran 90 ont des noms spécifiques, selon les types de l’argument et
du résultat.
Cela dit, il est toujours autorisé d’utliser le nom générique, fortran 90 reconnaı̂t alors le type
de l’argument et utilise la fonction spécifique correspondante.
Exemple :
MOD est une fonction prenant deux arguments integer, et renvoyant un résultat de type integer
(égal au reste de la division euclidienne du premier argument par le second).
Il existe une version faisant la même chose, mais avec des élément real : c’est la fonction AMOD.
Le nom générique de cette fonction est MOD, les noms spécifiques sont MOD et AMOD pour les
versions integer et real respectivement.
Ainsi, lorsque l’on utilise la fonction AMOD, ce ne peut être que pour des élément de type real. En
revanche, si l’on utilise la fonction MOD, fortran choisit la fonction spécifique MOD version integer
si les arguments sont integer ou AMOD version real si les élément sont real.
Exemple :
PROGRAM MODUL
PRINT*, AMOD(3.0,2.0) ! Nom spécifique de la fonction mod utilisée
! pour des real (> résultat real)
! PRINT*, AMOD(3,1) -> provoque une erreur a la compilation

PRINT*, MOD(3.0,2.0) ! Fortran 90 reconna^


ıt des arguments real et utilisera
! donc la fonction amod (avec résultat real)
PRINT*, MOD(3,2) ! Fortran 90 reconna^
ıt des arguments integer et
! utilisera donc la fonction mod (avec résultat integer)
! PRINT*, MOD(3.0,2) -> provoque une erreur a la compilation (les arguments
! sont de types différents, fortran 90 ne peut donc
! pas choisir...)
END PROGRAM MODUL

donne comme résultat :


1.000000
1.000000
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

Fonctions Numériques (conversions, arrondis, ...)

Objet de la Nom Nom Type Type


fonction Générique Spécifique argument(s) résultat
Conversion INT - I I
en INTEGER INT R I
IFIX R I
IDINT D I
(conversion de la partie réelle) - C I

Conversion REAL REAL I R


en REAL FLOAT I R
- R R
SNGL D R
(conversion de la partie réelle) - C R

Conversion DBLE - I D
en REAL*8 - R D
- D D
(conversion de la partie réelle) - C D

Conversion CMPLX - I (2I) C


en COMPLEX - R (2R) C
- D (2D) C
- C C

Troncature AINT AINT R R


DINT D D

Arrondi ANINT ANINT R R


DNINT D D
NINT NINT R I
IDNINT D I

Valeur ABS IABS I I


absolue ABS R R
DABS D D
CABS C R

Reste (div. eucl.) MOD MOD 2I I


AMOD 2R R
DMOD 2D D
MODULO - 2I I
- 2R R
- 2D D
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 iii

Objet de la Nom Nom Type Type


fonction Générique Spécifique argument(s) résultat
Arrondi par défaut FLOOR - I I
- R R
- D D

Arrondi par excès CEILING - I I


- R R
- D D

Signe (1) SIGN ISIGN 2I I


SIGN 2R R
DSIGN 2D D

Différence Positive (2) DIM IDIM 2I I


DIM 2R R
DDIM 2D D

Produit - DPROD 2R D

Maximum MAX MAX0 I I


AMAX1 R R
DMAX1 D D
- AMAX0 I R
- MAX1 R I

Minimum MIN MIN0 I I


AMIN1 R R
DMIN1 D D
- AMIN0 I R
- MIN1 R I

Partie imaginaire - AIMAG C R

Conjugué complex - CONJG C C


iv Annexe A : Fonctions intrinsèques

Fonctions mathématiques

Objet de la Nom Nom Type Type


fonction Générique Spécifique argument(s) résultat
Racine carrée SQRT SQRT R R
DSQRT D D
CSQRT C C

Exponentielle EXP EXP R R


DEXP D D
CEXP C C

Logarithme Népérien LOG ALOG R R


DLOG D D
CLOG C C

Logarithme base 10 LOG10 ALOG10 R R


DLOG10 D D

Sinus SIN SIN R R


DSIN D D
CSIN C C

Cosinus COS COS R R


DCOS D D
CCOS C C

Tangente TAN TAN R R


DTAN D D

Arcsinus ASIN ASIN R R


DASIN D D

Arccosinus ACOS ACOS R R


DCOS D D

Arctangente ATAN ATAN R R


DATAN D D
ATAN2 ATAN2 2R R
DATAN2 2D D

Sinus hyperbolique SINH SINH R R


DSINH D D

Cosinus hyperbolique COSH COSH R R


DCOSH D D

Tangente hyperbolique TANH TANH R R


DTANH D D
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 i

Annexe B : Les erreurs les plus fréquentes....


Les erreurs les plus fréquemment observées (commises par les étudiants pendant leurs premières
séances de Travaux Pratiques... mais aussi par les utilisateurs plus expérimentés !) sont présentées
dans cette partie.

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 première ligne doit être de la forme


PROGRAM NOM PROGRAM
et la dernière doit être de la forme
END PROGRAM NOM PROGRAM
en reprenant le même nom de programme.
La dernière ligne peut être tout simplement : END PROGRAM

• La commande de compilation n’est pas correctement tapée.

−→ > f90 toto.f90

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

−→ La règle de déclaration/affectation présentée dans le paragraphe h. de la section 1.2.2


ne doit (généralement) pas être utilisée dans les subroutines.
Comme il est expliqué dans la section 4.2, les variables locales des subroutines conser-
vent leurs valeurs d’un passage au suivant dans la subroutine. Ainsi, une déclaration
et affectation du type
REAL :: S=0
ne fixera la valeur de la variable S à 0 que pour le premier passage.
Pour les passages suivants, la valeur qu’avait la variable S à la fin du passage précédent
est conservée.
Pour que cette variable S reprenne bien la valeur 0 à chaque passage, il faut donc la
déclarer de manière plus classique:
REAL :: S
et ajouter
S=0
parmi les premières instructions de la subroutine.
Polytech Clermont-Fd 3AGMM - Fortran 90 & Programmation Numérique - Version Novembre 2021 i

Bibliographie.

• C. Delannoy, Programmer en Fortran 90, Eyrolles (1997).

• M. Metcalf, J. K. Reid, Fortran 90, Les concepts fondamentaux, AFNOR (1993).

• M. Metcalf, J. K. Reid, Fortran 90/95 explained, Oxford University Press (1999).

• W. H. Press, S. A. Teukolsky, W. T. Vetterling, Numerical recipes in Fortran 90, (the


art of parallel scientific computing) 2ème édition, Cambridge University Press (1996).
http://www.nr.com

Vous aimerez peut-être aussi