Fortran 77
Fortran 77
Fortran 77
FORTRAN 77
Le langage Fortran
Il s’agit de présenter le langage, donc l’outil de programmation Fortran
77 avec une vision, disons plus moderne. On essaiera donc de montrer comment
représenter et exprimer en Fortran les «entités usuelles» de la programmation :
données et procédures. On essaiera aussi d’insister sur les points forts et les points
faibles -donc les dangers- de ce langage, le tout dans une perspective réalisation
de grand logiciels scientifiques.
Cette présentation se veut une sorte de «guide» auquel on peut se référer rapi-
dement. Ainsi chaque trait du langage est illustré par un ou plusieurs exemples.
Depuis l’invention du langage Fortran dans les années 50 les calculateurs
ont largement évolué proposant à leurs utilisateurs de nouveaux modèles de pro-
grammation liés à des modifications architecturales : machines vectorielles, pa-
rallèles ; un nouveau domaine des sciences de l’ingénieur a aussi vu le jour il
s’agit du Génie Logiciel, ses techniques visent à maitriser le développement des
applications de grande taille que l’on ne pouvait pas imaginer il y a quarante ans,
citons seulement l’approche orientée objet.
Curieusement, dans le domaine du calcul scientifique, Fortran est resté
l’outil de base. Le langage lui-même et les pratiques de programmation ont bien
peu évolué au regard de l’environnement informatique. On explique cela (partiel-
lement) par la très grande quantité de logiciels déjà écrits en Fortran et par la
puissance des compilateurs donc l’efficacité du code généré sur les calculateurs
cible.
Fortran 77 est en apparence un langage simple à utiliser. En effet, il n’est
pas «contraignant» pour le programmeur et il est possible de développer rapide-
ment une petite application «numérique». Normal, c’est fait pour cela. En cari-
caturant on pourrait dire que Fortran est fait pour traiter des problèmes à une
dimension «1D». Si l’on veut passer au «2D», la situation se dégrade et lorsque
l’on arrive au «3D» l’ensemble devient souvent ingérable surtout si il est le ré-
sultat d’une «conception incrémentale» comme c’est généralement le cas. . .C’est
la rançon de l’apparente simplicité, car il n’y a pas dans Fortran d’outils pour
ii
1
elle devait voir le jour dans les années 80. . .
Table des matières
1 Les données 1
1.1 Identificateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Le type entier . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Les types réels . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Le type complexe . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4.1 Quelques fonctions . . . . . . . . . . . . . . . . . . . . . 5
1.5 Le type logique . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.6 Les chaînes de caractères . . . . . . . . . . . . . . . . . . . . . . 7
1.7 Déclarations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.7.1 La déclaration implicit . . . . . . . . . . . . . . . . . 10
1.7.2 Pas d’ «implicite» . . . . . . . . . . . . . . . . . . . . . 10
1.8 Déclarer des constantes . . . . . . . . . . . . . . . . . . . . . . . 11
1.9 Le constructeur tableau . . . . . . . . . . . . . . . . . . . . . . . 12
1.9.1 La déclaration dimension . . . . . . . . . . . . . . . . 13
1.9.2 Préciser les bornes . . . . . . . . . . . . . . . . . . . . . 14
1.10 Initialisations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.11 (pas de) data . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2 Les opérateurs 19
2.1 Opérateurs arithmétiques . . . . . . . . . . . . . . . . . . . . . . 19
2.2 Opérateurs relationnels . . . . . . . . . . . . . . . . . . . . . . . 21
2.3 Opérateurs logiques . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.4 Opérateurs sur les chaînes de caractères . . . . . . . . . . . . . . 25
2.4.1 Sous-chaîne . . . . . . . . . . . . . . . . . . . . . . . . . 26
3 Affectation et évaluation 29
3.1 Les conversions implicites . . . . . . . . . . . . . . . . . . . . . 30
3.2 Les conversions explicites . . . . . . . . . . . . . . . . . . . . . 31
3.2.1 Changement de précision . . . . . . . . . . . . . . . . . . 33
iv TABLE DES MATIÈRES
4 Les programmes 35
4.1 Formattage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.1.1 Commentaires . . . . . . . . . . . . . . . . . . . . . . . 36
4.2 Fichiers à inclure . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.3 Quelques instructions . . . . . . . . . . . . . . . . . . . . . . . . 38
4.3.1 L’instruction program . . . . . . . . . . . . . . . . . . 38
4.3.2 L’instruction end . . . . . . . . . . . . . . . . . . . . . . 38
4.3.3 L’instruction continue . . . . . . . . . . . . . . . . . . 38
4.3.4 L’instruction stop . . . . . . . . . . . . . . . . . . . . . 39
4.3.5 L’instruction pause . . . . . . . . . . . . . . . . . . . . 40
4.4 Les structures de contrôle . . . . . . . . . . . . . . . . . . . . . . 41
4.4.1 La répétition . . . . . . . . . . . . . . . . . . . . . . . . 41
4.4.2 Les formes do ...enddo et dowhile ...enddo . . 42
4.4.3 Conditionnelle . . . . . . . . . . . . . . . . . . . . . . . 44
4.4.4 Branchement inconditionnel . . . . . . . . . . . . . . . . 48
5 sous programmes 51
5.1 sous programme subroutine . . . . . . . . . . . . . . . . . . 51
5.1.1 L’instruction return . . . . . . . . . . . . . . . . . . . 53
5.1.2 L’instruction entry . . . . . . . . . . . . . . . . . . . . 54
5.2 sous programme function . . . . . . . . . . . . . . . . . . . . 55
5.3 Les arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
5.3.1 Simple, Tableau . . . . . . . . . . . . . . . . . . . . . . . 58
5.4 Argument sous programme . . . . . . . . . . . . . . . . . . . . . 66
5.5 Fonction «en ligne» . . . . . . . . . . . . . . . . . . . . . . . . . 68
7 Les entrées/Sorties 85
7.1 Unités logiques, physiques . . . . . . . . . . . . . . . . . . . . . 85
7.2 Écran-clavier . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
7.2.1 l’instruction read . . . . . . . . . . . . . . . . . . . . . 86
7.2.2 L’instruction write . . . . . . . . . . . . . . . . . . . . 87
7.2.3 Redirections . . . . . . . . . . . . . . . . . . . . . . . . 89
TABLE DES MATIÈRES v
Les données
1.1 Identificateurs
La norme Fortran 77 limite à six le nombre de caractères alphanumériques
utilisables pour un identificateur. Le premier doit être alphabétique. Il est difficile
de donner des noms parlants d’autant plus que Fortran ne distingue pas minus-
cules et majuscules. Ces identificateurs :
Attention :
. dans tous les cas on ne distingue pas minuscules et majuscules.
Conseils méthodologiques :
I utiliser l’extension Fortran 90 pour donner des noms parlants aux iden-
tificateurs ;
1
Comme en langage C
2 Les données
I il n’y a pas de «mots réservés» en Fortran mais ne pas utiliser les mots-
clef du langage comme identificateurs ;
I tout écrire avec les mêmes caractères et de préférence en minuscules plus
lisibles (sauf peut être les mots-clef).
Une déclaration integer*2 qui avait tout son sens à l’époque ou l’on cher-
chait à tout prix à économiser de la mémoire sera souvent traduite par un com-
pilateur récent en longueur standard (4 voire 8). De plus, si la longueur standard
des variables est de (par exemple) 8 octets : taille des «mots» en mémoire, on
pourra observer une dégradation des performances si l’on essaie d’accéder à des
variables codées sur des fractions de mots (2 ou 4 octets).
Conseil méthodologique :
I utiliser integer sans indication de taille pour déclarer des variables en-
tières.
Les constantes entières sont . . .des entiers signés ou non :
...
integer i,j
i=10
j=-123
...
1.3 Les types réels 3
C’est très simple en apparence mais la réalité est plus complexe ! En effet,
pour le programmeur, généralement, simple précision et double précision sous-
entendent des variables réelles codées sur 4 octets ou 8 octets : précision utilisa-
teur. Or la simple précision machine peut correspondre à 4 octets ou à 8 octets.
Dans le second cas, la double précision machine correspondra à des variables co-
dées sur 16 octets (parfois appellé quadruple précision. . .pour l’utilisateur) ce qui
est rarement l’effet recherché.
Pour tout compliquer, il est possible, comme pour les entiers de préciser la
taille occupée par une variable de type real et bien sûr, le compilateur n’est pas
obligé de tenir compte de cette information.
Il semble que pour des raisons de portabilité du code, il faille se résoudre
à utiliser les déclarations real*4 et real*8, double précision causant
trop de soucis si la taille standard est de 8.
Conseils méthodologiques :
I utiliser real*4 pour demander la simple précision «utilisateur» si elle
existe sur la machine ;
I utiliser real*8 pour demander la double précision «utilisateur» (ce peut
être la simple précision machine) ;
4 Les données
Attention :
. le paragraphe précédent invite à utiliser plutôt real*4 et real*8, pré-
cision «utilisateur» plutôt que real et double precision, précision
«machine» malheureusement cela rend non portable l’écriture des constantes
réelles. . .Néanmoins, les conversions automatiques devraient fonctionner de
manière satisfaisantes ;
. certains compilateurs possèdent des options telles que -r8 ou -dp qui
indiquent que l’on considère tous les réels comme étant des real*8 ou
des double precision. À utiliser avec précautions ! ces options ne
changent pas, bien sûr, les noms de fonctions souvent basés sur la préci-
sion machine.
Conseils méthodologiques :
I bien expliquer dans l’en-tête du programme les choix retenus ;
I commenter et regrouper au maximum les parties non-portables.
La même analyse que pour les types réels amène aux mêmes conclusions :
Conseils méthodologiques :
1.4 Le type complexe 5
Attention :
. la double précision «machine» pour les variables de type complexes est une
extension à la norme, elle n’est pas disponible sur tous les systèmes.
...
real*4 a, b
complexe*8 ca, cb
c ..........
a = real (ca)
b = imag (ca)
c ..........
cb = conjg (ca)
...
6 Les données
...
real*8 x, y
c ... (complexe*16: hors norme)
complexe*16 cx, cy
c ..........
x = real (cx)
y = imag (cx)
c ..........
cy = conjg (cx)
...
Conseils méthodologiques :
I utiliser seulement les noms «génériques» : real, imag et conjg. Il existe
aussi dans la bibliothèque standard Fortran des fonctions spécifiques
dont les noms dépendent de la précision «machine» des variables utili-
sées, par exemple aimag travaille sur un complex et retourne un résultat
real etc. . . ;
I de toutes façons il est préférable de ne pas mélanger les précisions.
Les constantes complexes sont formées de deux constantes réelles, entre pa-
renthèses séparées par une virgule. Tout ce qui a été dit sur les constantes réelles
s’applique donc !
...
complexe*8 c_1, c_2
c_1= (+1e4 , -234.67e-2)
c_2= (12.5e+23, 2.3 )
...
logical fini, ok
Comme pour les autres types, il est possible de préciser la longueur occupée
en mémoire par une variable de type logique, la taille standard sera elle de 4
1.6 Les chaînes de caractères 7
ou 8 (mais oui ! !) octets selon les machines. Si l’on précise la taille on aura les
variantes :
c .... a eviter
logical*1 ok
logical*2 fini
logical*4 test
encore une fois, il n’est pas du tout garanti que le compilateur utilisera effec-
tivement l’indication donnée par le programmeur, et les déclarations «exotiques»
seront souvent traduites en taille standard.
Conseil méthodologique :
I utiliser logical sans indication de taille pour déclarer des variables boo-
léennes.
Les constantes logiques peuvent prendre deux valeurs prédéfinies .true.
(vrai) ou .false. (faux) :
...
logical ok, fini
fini = .false.
ok = .true.
...
Conseils méthodologiques :
I utiliser seulement les formes .true. ou .false. ;
I utiliser les variables logiques uniquement pour y stocker les valeurs .true.
ou .false. (les normes précédentes de Fortran permettaient d’y mettre
à peu près n’importe quoi. . .).
character*20 mot
integer l
...
l = len(mot)
c ....donc 20, taille declaree de mot
...
...
character*15 chaine1, chaine2, chaine3
chaine1 = ’petite chaine’
chaine2 = ’p’’tite chaine’
chaine3 = ’une tres grande chaine’
...
1.7 Déclarations 9
Remarques :
⇒ l’opérateur len lui renverra toujours la valeur 15 pour chaine1, chaine2
et chaine3, c’est la dimension déclarée d’une chaîne de caractères qui
compte ;
⇒ pour initialiser «à blanc» une chaîne de longueur quelconque il suffit donc
de faire :
...
chaine = ’ ’
...
Conseil méthodologique :
I ne pas utiliser d’autres délimiteurs pour les constantes chaînes de carac-
tères, notamment la double quote (").
1.7 Déclarations
Le langage Fortran n’impose pas que toutes les entités manipulées au cours
d’un programme soient explicitement déclarées. Une variable est déclarée implici-
tement dès qu’elle est rencontrée par le compilateur. Pire, selon la première lettre
du nom de l’indentificateur ce dernier effectue un typage implicite :
– la variable sera de type integer si le nom commence par i, j, k, l,
m ou n.
– la variable sera de type real si le nom commence par tout autre lettre (de
a à h et de o à z)
Il n’est donc pas obligatoire d’utiliser les déclarations présentées aux para-
graphes précédents. Néanmoins cela est très dangereux, une faute d’orthographe
ou une faute de frappe pouvant conduire à un programme syntaxiquement correct
mais . . .faux !
Conseil méthodologique :
I toujours déclarer les variables et. . .lire la suite.
10 Les données
Dans l’exemple ci-dessus, après les déclarations implicit, les variables non
déclarées (explicitement. . .) et dont le nom commence par k ou l seront implicite-
ment typées en logical, celles dont le nom commence par c en character*20,
celles dont le nom commence par a, b, une lettre entre d et h ou une lettre entre o
et z en real*8. Rien n’est changé pour les variables dont les noms commencent
par i, j, m, n qui sont donc typées implicitement en integer.
Ces déclarations implicit doivent se trouver avant toutes les (éventuelles)
déclarations de variables.
Conseil méthodologique :
I ne jamais utiliser cette forme de la déclaration implicit et. . .lire la
suite.
...
implicit none
...
Conseil méthodologique :
I toujours utiliser implicit none et donc déclarer, par la suite, toutes les
variables.
1.8 Déclarer des constantes 11
...
implicit none
integer dimension
parameter (dimension=100)
real*8 zero, un
parameter (zero=0.0d0, un=1.0d0)
...
Conseil méthodologique :
I déclarer et initialiser avec parameter toutes les constantes utilisées dans
une unité de programmation.
La partie droite expression_constante peut être une véritable expres-
sion qui doit pouvoir être évaluée à la compilation. Ainsi, les termes doivent être
soit des constantes, soit des identificateurs déjà définis dans un ordre parameter.
...
integer nbe, dim_1, dim_2
parameter (nbe =100)
parameter (dim_1=nbe+2), dim_2=nbe*(nbe+1))
...
Remarque :
⇒ bien sûr, nbe, dim_1 et dim_2 pourraient être initialisés dans le même
ordre parameter mais il est plus lisible d’isoler, comme dans l’exemple
ci-dessus, les valeurs destinées à être modifiées.
12 Les données
...
integer taille
parameter (taille=2000)
integer table(100)
real*8 x (taille), y(100,100)
...
Les éléments sont accédés via une notation indicée entre parenthèses. Les in-
dices sont des entiers (variables, constantes ou expressions entières) et la numé-
rotation des éléments commence à 1. Ainsi, avec les déclarations ci-dessus, l’on
peut écrire :
...
c ......... acces aux elements
...
table(10)=...
... = y(10, 20)
...
En Fortran, les tableaux à deux dimensions sont rangés par colonnes. Ainsi,
dans la mémoire de l’ordinateur, les éléments sont rangés dans l’ordre suivant :
C’est la contraire de ce qui se passe avec le langage C pour lequel ils sont
rangés par lignes. D’une façon plus générale, pour le stockage des tableaux multi-
dimensionnels en Fortran, c’est l’indice le plus à gauche qui varie en premier.
Attention :
1.9 Le constructeur tableau 13
program tableau
implicit none
integer x(10)
integer i
c ... ERREUR: debordement de tableau
do i=1, 20
x(i)=i
enddo
end
real*8 x
dimension x(100)
...
...
integer table(0:99)
real*8 x (-10:+9, 10:29)
...
Dans cet exemple, table est un tableau de 100 éléments mais numérotés
à partir de 0. Ils seront donc accédés par table(0), table(1), . . .jusqu’à
table(99). De même, le premier indice de x varie entre -10 et +9 et le second
entre +10 et +29.
Conseil méthodologique :
I est-ce vraiment utile ? sans doute parfois mais il faut utiliser cette facilité
avec précautions car ce n’est pas dans les «habitudes Fortran» et donc,
à coup sûr, source de confusions.
1.10 Initialisations
La norme Fortran ne prévoit pas d’initialisations par défaut pour les va-
riables d’un programme. Dans certains dialectes, les variables sont initialisées (à
zéro) au moment de la déclaration mais il n’est pas possible d’écrire un code por-
table en s’appuyant sur cette possibilité.
Attention :
1.11 (pas de) data 15
...
...
real*8 epsil
data epsi /1.0d-6/
...
Ici epsi sera initialisé à 1.0d-6, rien n’empêche, par la suite, de modifier
cette valeur.
Remarque :
⇒ l’instruction data peut prendre des formes variées qu’il est difficile de
décrire de façon synthétique mais que l’on peut encore rencontrer, voici
quelques exemples :
...
...
real*8 epsil
integer i, j
c .... "data" regroupes sur une meme ligne.
data epsi /1.0d-6/ i, j /100, 5/
c .... (on peut mettre une virgule avant le i)
...
...
16 Les données
...
...
real*8 x(100)
integer i,j,k
c .... plusieurs fois la meme valeur
c .... (la virgule avant le i est optionnelle)
data x/100*0/, i,j,k /3*0/
...
...
...
real*8 x(10,10)
integer i,j
c .... boucles "implicites" 1 sur la diagonale
c .... des zero ailleurs
data ((x(i,j),i=1,10),j= 1,i-1)/45*0.0d0/
& ((x(i,j),i=1,10),j=i+1, 10)/45*0.0d0/
& (x(i,i),i=1,10) /10*1.0d0/
...
Conseil méthodologique :
...
c .... declaration de constante
real*8 epsil
parameter (epsi= 1.0d-6)
real*8 x(100)
integer i, j, k
c .... initialisations des variables
i =100
j = 5
c .... boucle "pour", voir plus loin
do k=1, 100
x(k)=100.0d0
enddo
c .... suite du programme
...
...
Chapitre 2
Les opérateurs
Attention :
. l’opérateur ** est associatif à droite. x**y**z est évalué comme x**(y**z) ;
. l’opérateur / appliqué à des variables de type integer est la division
euclidienne ( 5/2 vaut 2 ) ;
. on considère généralement que les opérateurs unaires ont une plus forte
priorité mais ce n’est pas le cas en Fortran.
Ainsi -1.0**2 vaut -1.0 , pour obtenir une puissance de -1 ,
il faudra écrire : (-1.0)**2 (qui ouf ! vaut bien 1.0 ).
Conseil méthodologique :
I éviter lorsque c’est possible d’utiliser l’opérateur **. La multiplication est
plus précise et plus rapide :
...
c .......... ne pas ecrire
c y = x**2
c z = t**3
c ........... mais plutot:
y = x*x
z = t*t*t
...
xi=1.0
do i=1, n
c ...... xi vaut x**i, calcul par recurrence
xi=xi*x
...
enddo
...
Remarque :
⇒ les opérateurs arithmétiques sont prioritaires sur les opérateurs relation-
nels. Il est inutile de parenthéser l’expression x+y.gt.z**t sauf
pour la rendre plus lisible. . . (x+y).gt.(z**t) ce qui est souhai-
table !.
Attention :
22 Les opérateurs
...
logical ok1, ok2, non3
character*2 ch
character*10 ch1, ch2, ch3
...
ch = ’zz’
ch1 = ’zz’
ch2 = ’zz ’
ch3 = ’zzz’
ok1 = ch.eq.ch1
ok2 = ch.eq.ch2
non3 = ch.eq.ch3
...
Dans cet exemple ok1 et ok2, ont la valeur .true. , les longueurs
utiles de ch1 et ch2 sont égales à la longueur de ch.
non3 a la valeur .false. , la longueur «utile» de ch3 est supérieure à
celle de ch.
Le résultat des opérateurs de comparaison (.lt. , .le. , .ge. , .gt.)
dépend en plus du codage interne des caractères donc de la machine utilisée.
Pour écrire un code portable, il faut utiliser les fonctions de la bibliothèque
standard Fortran : llt, lle, lge et lgt qui garantissent un résultat
conforme au codage ASCII.
Un opérateur de comparaison (.lt. , .le. , .ge. , .gt.) appliqué à
des chaînes de longueur différentes ne travaille que sur la partie «commune»
des deux chaînes, il «tronque» donc la chaîne la plus longue. Si les parties
2.3 Opérateurs logiques 23
...
logical ok1, ok2, ok3, non4
character*2 ch
character*10 ch1, ch2, ch3, ch4
...
ch =’bb’
ch1 =’zz’
ch2 =’zzzz ’
ch3 =’bbzzzzz’
ch4 =’aaa’
ok1 = ch.lt.ch1
ok2 = ch.lt.ch2
ok3 = ch.lt.ch3
non4 = ch.lt.ch4
...
Dans cet exemple, ok1, ok2 et ok3 ont la même valeur ( .true. ),
dans les deux premiers cas, la comparaison s’effectue sur la longueur «com-
mune», dans le troisième cas, ch3 a une longueur «utile» supérieure.
non4 à la valeur .false. car la comparaison s’effectue sur la longueur
«commune».
Conseils méthodologiques :
I attention, comparer à zéro des valeurs réelles ou complexes (stockées en
mode flottant) n’a pas forcément de sens ;
I attention aux chaînes de caractères, ne pas utiliser .lt. , .le. , .ge.
et .gt. mais les fonctions de la bibliothèque standard Fortran llt,
lle, lge et lgt ;
I ne pas utiliser ces opérateurs avec des variables de type logical. Il
existe d’autres opérateurs pour tester l’égalité ou l’inégalité de variables
booléennes.
Ouf ! pour une fois l’opérateur unaire a bien la plus forte priorité. Mais Les
noms des opérateurs rendent les expressions logiques parfois difficiles à déchif-
frer. . .
...
c ... pas clair:
c ... l_1.or.l_2.and..not.x.lt.eps.or.i.gt.imax
c ... un peu mieux si on parenthese:
c ...
if ((l_1.or.l_2).and.
& (.not((.x.lt.eps).or.(i.gt.imax)))) then
...
Attention :
. la norme ne prévoit pas d’effet de «court-circuit» lors de l’évaluation d’ex-
pressions impliquant les opérateurs .and. et .or.. Ainsi dans :
l_1.and.l_2
si l_1 est faux, et bien que le résultat de l’expression soit alors déjà connu,
l_2 sera aussi évalué et doit être défini. De même dans
l_1.or.l_2
2.4 Opérateurs sur les chaînes de caractères 25
si l_1 est vrai, et bien que le résultat de l’expression soit aussi déjà connu,
l_2 sera aussi évalué et de même doit être défini. Un exemple :
...
integer n, p, q
logical l
...
c .......... RISQUE D’ERREUR !!!
l = (n.ne.0).and.(p/n.ne.q)
...
ici, si n vaut zero (n.eq.0), l’expression p/n sera quand même évaluée
avec sûrement des conséquences néfastes. . .
Remarque :
⇒ dans l’exemple ci-dessus, les parenthèses ne sont pas obligatoires car les
opérateurs relationnels sont prioritaires sur les opérateurs logiques, elles
augmentent néanmoins la lisibilité du code.
Conseil méthodologique :
I toujours utiliser .eqv. et .neqv. pour comparer des variables de
type logical (et non .eq. et .ne. ) ;
I éviter toutes les variantes exotiques et aussi l’opérateur «ou exclusif » ( .xor.
) que l’on rencontre parfois.
chaine_1 = chaine_2
chaine_1 puis on remplit «à droite» avec des blancs. Cela généralise ce qui
a été exposé pour les constantes.
...
character*5 a, b
character*6 c_petit
character*10 c_grand
a=’aa’
b=’bbb’
c_petit=a//b
c_grand=a//b
c ... c_petit contient maintenant ’aa b’
c ... c_grand contient maintenant ’aa bbb’
...
Attention :
. cet opérateur ne met donc pas bout à bout les parties «utiles» des chaînes ;
. les troncations éventuelles des résultats ne sont pas des erreurs et donc
passent inaperçues. Il convient de bien s’assurer que les chaînes utilisées
ont des longueurs suffisantes.
2.4.1 Sous-chaîne
L’accès à une partie (ou sous-chaîne) d’une chaîne de caractères se fait par
une variante de la notation indicée utilisant le symbole : . Les indices sont des
entiers ou des expressions entières. Soient par exemple les déclarations :
2.4 Opérateurs sur les chaînes de caractères 27
...
character*20 var_ch
integer i,j
...
character*20 var_ch
.....
c .......... la premiere moitie de var_ch (debut a 10)
... var_ch (:10)
c .......... la deuxieme moitie (11 a la fin)
... var_ch(11:)
c........... les 4 caracteres du "milieu" (de 9 a 12)
... var_ch(9:12)
...
Attention :
. une sous-chaîne est une chaîne jusqu’a un certain point. . .Il n’est pas pos-
sible d’écrire directement une sous-chaîne de sous-chaîne ;
. il faut prendre quelques précautions sous peine de comportement imprédic-
tible :
– le premier indice pour une sous-chaîne doit être inférieur au second ;
– le second indice d’une sous-chaîne doit être inférieur ou égal à la dimen-
sion déclarée de la chaîne ;
– enfin deux sous-chaînes d’une même variable utilisées à droite et à gauche
d’une affectation ne doivent pas se chevaucher.
28 Les opérateurs
Conseils méthodologiques :
I ne pas utiliser la forme (inutile) ( :) sans indices ;
I d’une façon générale, se méfier des sous-chaînes, Fortran n’est pas un
langage fait pour manipuler des chaînes de caractères.
Chapitre 3
Affectation et évaluation
...
logical l, ok
integer i,j
real*8 x,y,z
...
l= .not.ok.and.i.lt.j.or.x+y.ge.z
...
...
l= ((.not.ok) .and. (i.lt.j)) .or. ((x+y).ge.z)
...
...
integer i,j,k
real*8 x,y,z
...
j= x*y+i/k
...
30 Affectation et évaluation
...
j= ((x*y)+(i/k))
...
Conseils méthodologiques :
I parenthéser complètement les expressions n’est jamais pénalisant et ga-
rantit un ordre d’évaluation conforme à ce que l’on croit écrire ;
I éviter de mélanger les types dans les expressions numériques. Les conver-
sions pouvant éventuellement entraîner une perte d’information et/ou de
précision.
Remarque :
⇒ si l’on convertit un entier ou un réel en complexe, on obtient un nombre
dont la partie imaginaire est nulle. Si l’on convertit un complexe en entier
ou en réel, la partie imaginaire est perdue.
Conseil méthodologique :
I ne pas laisser le compilateur effectuer des conversions implicites (donc lire
le paragraphe suivant !) et, rappel, d’une façon générale, ne pas mélanger
les types dans les expressions.
Attention :
. le type double complex et la fonction associée : dcmplx, ne font pas
partie de la norme ;
3.2 Les conversions explicites 33
Conseil méthodologique :
I toujours utiliser les noms génériques pour les fonctions de conversion.
...
real a, b
double precision x, y
complex ca, cb
c ... attention double complex n’existe pas forcement
double complex cx, cy
...
c ... real => double precision
x = dble (a)
c ... double precision => real
b = real (y)
c ... complex => double complex
c ... dcmplx -si le type double complex existe-
cx = dcmplx (ca)
c ... double complex => complex
cb = cmplx (cy)
Conseil méthodologique :
I encore une fois, ne pas mélanger plusieurs «précisions utilisateur» et/ou
«machine» à l’intérieur d’un même code.
Chapitre 4
Les programmes
4.1 Formattage
Les instructions écrites en langage Fortran doivent être «formattées» d’une
façon très rigide, héritée de l’époque des cartes perforées. De plus le langage ne
pouvant être décrit simplement par une grammaire formelle, cette syntaxe imposée
est restée.
Une instruction Fortran doit être écrite sur une ligne entre les colonnes 7 à
72. Si l’instruction comprend plusieurs lignes, les suivantes comprennent alors un
caractère suite positionné en colonne 6. La colonne 1 sert à indiquer les commen-
taires, les colonnes 2 à 5 (inclus) sont utilisées pour donner un numéro (étiquette
ou encore “label”) permettant d’identifier l’instruction. Enfin, tout ce qui suit la
colonne 72 est ignoré. Ainsi :
Un caractère dans cette colonne indique que l’instruction précédente continue sur cette ligne
1 2 3 4 5 6 7 72 73 .....
Conseil méthodologique :
I si une instruction s’étend sur plusieurs lignes, toujours utiliser le même
caractère de continuation, par exemple & :
...
integer i, k, entier_1, entier_2, entier_4,
& ix, iy, iz, encore_un, et_un_autre
...
I une instruction doit être codée au maximum sur 20 lignes. Il est prudent
de s’interroger sur la façon dont on programme avant d’atteindre cette li-
mite. . .
4.1.1 Commentaires
Toute ligne qui comporte un caractère c en colonne 1 est un commentaire.
...
c ces lignes sont ...
c... des commentaires
...
Conseils méthodologiques :
I bien sûr il ne faut pas hésiter à abuser (raisonnablement) des commentaires
et pour améliorer la lisibilité du programme, on peut suivre l’indentation
des instructions ;
I ne pas utiliser -dans ce contexte «77»- l’extension Fortran 90 qui per-
met de mettre, à la fin d’une ligne, un commentaire précédé du caractère ! ;
4.2 Fichiers à inclure 37
program essai
c
include ’definition.h’
c
c .......... variables locales
real x, y, z
c
...
Attention :
. cette extension a ses limites. Le fichier à inclure est le plus souvent re-
cherché uniquement dans le répertoire courant contrairement à ce qui se
passe en langage C ou l’on peut préciser à l’aide de l’option -I du compi-
lateur un chemin d’accès pour ces fichiers.
Conseil méthodologique :
I ne pas hésiter néanmoins à utiliser cette extension très courante. Un cas in-
téressant est de regrouper des constantes déclarées avec l’instruction parameter
et/ou des zones communes (voir plus loin).
38 Les programmes
program simple
c
c ... pas de declarations implicites
c ... voir ce qui precede!!
c
implicit none
integer i,j
...
c ... instructions du programme
...
...
...
end
Conseil méthodologique :
I toujours commencer le programme principal par l’instruction program.
...
100 continue
...
...
200 continue
...
end
Conseils méthodologiques :
I dans un programme n’étiqueter que des instructions continue. Les éti-
quettes pourront servir aussi à repérer les formats utilisés pour les en-
trées sorties ;
I en fait, on espère bien pouvoir se passer des instructions continue.
...
integer i,j
c ... norme fortran 66, l’instruction program n’existe
c ... pas encore, le programme se termine par stop end
...
stop
end
...
...
stop 4
...
...
stop ’fin anormale’
...
...
end
Conseil méthodologique :
I un programme bien construit ne se termine que d’une seule manière : à
l’instruction end du «programme principal». L’idéal serait de ne pas utili-
ser l’instruction stop. Néanmoins, ce conseil n’est pas vraiment réaliste,
il est raisonnable d’envisager un sous programme spécial : subroutine
fin_anormale (message, ...), qui imprimé un message d’erreur
passé en argument et termine le programme correctement avec un stop
(i.e. après avoir fermé les fichiers etc...).
Conseil méthodologique :
I ne pas utiliser l’instruction pause dans les programmes. Tout cela avait un
sens lorsque des interventions manuelles étaient nécessaires pour assurer le
bon déroulement des programmes.
4.4 Les structures de contrôle 41
...
do 10 i=1, 100
c ...... i va de 1 a 100 par pas de 1
c ...... valeur par defaut de l’increment
c .......la boucle s’arrete sur l’etiquette 10
...
t(i)= ...
...
10 continue
...
...
do 20 i=1, 100, 2
c ...... ici de 1 a 100 par pas de 2
c .......la boucle s’arrete sur l’etiquette 20
...
v(j)= ...
...
20 continue
...
Conseils méthodologiques :
I n’utiliser que des variables entières (integer) comme compteurs de boucle ;
I toujours terminer le corps de boucle par une instruction continue ; en
cas de boucles imbriquées utiliser plusieurs instructions continue :
42 Les programmes
...
integer i, j
real*8 a(100,100)
...
do 200 i=1, 100
do 100 j=1, 100
...
...
a(i,j)= ...
100 continue
200 continue
...
...
c ... tres mauvais style
c ... (mais ca marche quand meme)
c
do 111 i=1, 100
do 111 j=1, 100
...
...
111 a(i,j)= ...
...
...
integer i, j, k
c
integer t(100), v(100), a(100,100)
c
...
do i=1, 100
c ...... de 1 a 100 par pas de 1 (valeur par defaut)
...
t(i)= ...
...
...
enddo
...
do i=1, 100, 2
c ...... ici de 1 a 100 par pas de 2
...
v(j)= ...
...
enddo
...
...
c ...... boucles imbriquees
do i=1, 100
do j=1, 100
...
...
a(i,j)= ...
...
enddo
enddo
...
L’extension do while ..., réalisant une boucle tant que, semble aussi ré-
pandue et peut être utilisée sans problèmes surtout qu’elle n’a pas d’équivalent
en Fortran 77 standard. Le mot-clef do while est suivi d’une expression
logique. La construction se termine bien sûr par enddo :
44 Les programmes
...
real*8 eps
parameter (eps=1.0d-6)
logical ok
real*8 residu
...
ok = .true.
do while (ok)
...
...
enddo
...
...
do while (residu.gt.eps)
...
...
enddo
...
4.4.3 Conditionnelle
Le langage Fortran 77 a été doté, en son temps d’une forme conditionnelle
relativement elaborée qui est l’équivalent du si . . .alors . . .sinon . . . des langages
les plus évolués. La syntaxe utilise les mots-clef if, then, else, endif. la
partie sinon est optionnelle. Il est impératif de passer à la ligne après les mots-clef
then, else et endif.
...
integer i, j, k
real*8 x
...
if (i.gt.0) then
c ...... exemple avec if seul
...
endif
...
4.4 Les structures de contrôle 45
...
if (x.le.1.0d0) then
c ...... exemple avec partie else
...
...
else
...
...
endif
...
...
if (i.lt.0) then
...
else
if (j.gt.1000) then
...
...
else
...
...
endif
endif
...
if (i.le.0) then
...
elseif (k.lt.100) then
c ...... instructions executees si i>0 et k<100
...
elseif (m.lt.1000) then
c ...... instructions executees si i>0, k>=100 et m<1000
...
else
c ...... partie else optionnelle,
c ...... executee ici si i>0, k>=100 et m>= 1000
...
endif
...
Cette construction peut servir, bien sûr, pour simuler élégament une instruction
choix.
Le if dit logique : il s’écrit sur une seule ligne avec seulement le mot-clef if.
L’instruction est exécutée si la condition est vraie.
...
...
if (i.le.0) t(i)=x(i)+y(i)
...
...
...
if (k) 11,12,13
...
c l’execution reprend ici si k < 0
11 x = ...
...
c l’execution reprend ici si k = 0
12 x = ...
...
c l’execution reprend ici si k > 0
13 x = ...
...
Pour corser le tout, les étiquettes peuvent figurer dans le programme dans
un ordre quelconque et même se trouver avant l’instruction if considérée.
Conseils méthodologiques :
I ne pas utiliser le if logique, obsolète ; utiliser systématiquement if ...then
...endif ;
I ne jamais utiliser le if arithmétique, en contradiction totale avec une struc-
turation correcte des programmes.
48 Les programmes
goto numero
...
...
c ....simulation de "tant que x>=epsilon faire"
100 continue
if (x.lt.epsilon) then
goto 200
else
.....
.....
.....
goto 100
endif
200 continue
c ... fin de la boucle "tant que"
...
Conseils méthodologiques :
I le goto doit toujours renvoyer à une instruction continue, la seule qu’il
soit raisonnable d’«étiqueter» mais. . .
I . . .ne pas utiliser l’instruction goto sauf, éventuellement et en le signa-
lant, pour simuler une boucle tant que mais. . .
I . . .dans ce cas utiliser plutôt l’extension do while.
4.4 Les structures de contrôle 49
Inutiles car encore une fois elles correspondent à une façon de programmer qui
n’est plus de mise aujourd’hui. Donnons juste des exemples. Le (dé)branchement
«calculé» :
...
integer etiq
...
assign 100 to etiq
...
...
goto etiq
...
100 ...
...
...
goto etiq (100, 200)
...
Ce qui se passe quand l’étiquette contenu dans la variable n’est pas dans la
liste des possibles n’est pas très clair. . .
Conseils méthodologiques :
I ne jamais utiliser de débranchement calculé. Pour programmer une ins-
truction choix, il faut utiliser if ...elsif....
I . . .ne jamais utiliser de débranchement assigné.
Chapitre 5
sous programmes
Attention :
. si l’on ne précise pas à l’intérieur du sous programme, le type des argu-
ments, ceux-ci subissent le typage implicite exposé précédemment. Si l’on
utilise implicit none -et il faut le faire- il est alors obligatoire de typer
les arguments :
. un sous programme peut modifier ses arguments (cela sera détaillé par le
suite) mais Fortran n’offre pas de mécanisme pour déclarer le statut d’un
argument («donnée», «donnée modifiée» ou «résultat»).
Conseils méthodologiques :
I utiliser toujours implicit none et donc déclarer explicitement le type
des arguments ;
I dans les déclarations, bien mettre en évidence, comme dans l’exemple ci-
dessus :
– les arguments ;
– les variables locales.
et préciser à l’aide de commentaires le statut des arguments :
5.1 sous programme subroutine 53
program appli
implicit none
real*8 p1, p2
...
...
call ssp_1 (p1, p2)
...
call ssp_2 ()
...
end
Attention :
. à l’appel les listes d’arguments formels et réels doivent se correspondre
exactement (nombre et types). Le programme appelant «ne connait pas»
la séquence d’appel correcte. Il n’y a pas, en Fortran 77, de notion de
prototypes de fonctions comme (par exemple) en langage C. Les compila-
teurs qui traitent indépendament chaque unité de programmation ne peuvent
pas tester la validité de l’appel et (pire !) un appel incorrect ne provoquera
pas forcement une erreur à l’exécution.
Conseil méthodologique :
I un sous programme bien écrit ne possède qu’un seul point d’entrée et un
seul point de sortie. Il n’y a pas lieu d’utiliser l’instruction return.
program appli
implicit none
real*8 a, b, c
..
call ff_1 (a, b, c)
...
call ff_2 (a, b)
...
end
Conseil méthodologique :
I un sous programme bien écrit ne possède qu’un seul point d’entrée et un
seul point de sortie. Ne jamais utiliser l’instruction entry dans un sous
programme de type subroutine.
Il peut ne pas y avoir d’ arguments mais les parenthèses, elles, sont obligatoires
comme pour une subroutine. Si la fonction ne reçoit pas de type alors les
règles de typage implicite s’appliquent au nom de la fonction (aïe !) :
function sans_type ()
c ... donc real (ici): a eviter!!!
...
...
end
56 sous programmes
Conseils méthodologiques :
I toujours typer explicitement une fonction ;
I comme pour une subroutine, utiliser implicit none pour déclarer
le type des arguments formels ;
I un sous programme bien écrit ne possède qu’un seul point d’entrée et
un seul point de sortie. Ne jamais utiliser l’instruction entry dans un
sous programme de type function, ne pas utiliser non-plus l’instruc-
tion return.
La fonction nom_de_function retourne la dernière valeur affectée à l’iden-
tificateur nom_de_function :
Conseil méthodologique :
5.2 sous programme function 57
I pour être sûr que tout fonctionne bien, il est préférable d’utiliser des va-
riables locales et d’affecter une fois seulement nom_de_function, juste
avant l’instruction end.
La fonction peut ensuite être utilisée comme une variable de même type dans
une expression, son type doit être déclaré dans le programme appelant :
program util_calcul
implicit none
c ... fonctions
real*8 calcul
c ... variables
real x0, y0, z0, x1, y1, z1, ss
...
...
ss = calcul(x0, y0, z0) + calcul (x1, y1, z1)
...
end
Conseils méthodologiques :
I de par leur nature, les fonctions sont destinées à être appelées dans des ex-
pressions. Si une function modifie ses arguments cela peut induire des
effets de bords non désirés. Ainsi, un sous programme de type function
ne doit jamais modifier ses arguments ;
I toujours déclarer le type des fonctions utilisées dans une unité de pro-
gramme. C’est obligatoire si l’on utilise implicit none ce qui est bien
sûr conseillé ;
I enfin de même que pour les subroutines, il faut faire attention au
nombre et aux types des arguments réels lors de l’appel d’une function,
le compilateur ne faisant aucune vérification et une erreur éventuelle n’étant
pas forcément détectée à l’exécution.
Dernier problème, il existe en Fortran un grand nombre de fonctions pré-
définies (qualifiées d’«intrinsèques») par exemple cos pour cosinus, etc. . .. De
plus, ces fonctions ont souvent plusieurs noms selon le type des arguments ou du
résultat. Il peut arriver qu’un sous programme function «utilisateur» porte le
même nom qu’une de ces fonctions prédéfinie. Pour garantir que l’on appellera
effectivement la fonction «utilisateur», il faut que cette dernière soit déclarée à
l’aide du mot-clef external dans le programme appelant. Reprenons l’exemple
du programme utilisant la fonction calcul :
58 sous programmes
program util_calcul
implicit none
c ... fonctions
c ... evite les <<collisions>> de noms
external calcul
real*8 calcul
c ... variables
real x0, y0, z0, x1, y1, z1, ss
...
...
ss = calcul(x0, y0, z0) + calcul (x1, y1, z1)
...
end
Conseil méthodologique :
I dans les nouvelles normes Fortran 90 etc. . ., le nombre de fonctions
«intrinsèques» a tendance à augmenter de façon inquiétante. Il est sûrement
prudent, dès maintenant, de déclarer comme étant external toutes les
fonctions «utilisateur» ;
I on voit bien que ce mécanisme peut permettre aussi de redéfinir des fonc-
tions «intrinsèques». Cette possibilité ne doit pas être utilisée sciement !
tableau, correspond à son adresse en mémoire, c’est aussi celle du premier élé-
ment. Les suivants sont supposés être rangés de manière contigüe à partir de cette
adresse. Un élément de tableau peut bien sûr être passé comme argument simple :
2. On peut penser alors qu’il suffit de mettre n’importe quel nombre. En effet
ce qui importe c’est de préciser que l’argument formel est un tableau. On
rencontre souvent dans les programmes :
4. Pour éviter tout ennuis, il est prudent de passer aussi au sous programme,
la dimension réelle du tableau et de s’en servir pour le dimensionner. La
dimension réelle peut être testée dans le sous programme ce qui permet
d’éviter bien des mauvaises surprises.
5.3 Les arguments 61
Conseil méthodologique :
I passer toujours la dimension en même temps que le tableau et dimensionner
correctement le tableau dans le sous programme. À l’appel, on passera soit
la vrai dimension du tableau, soit sa dimension «utile» dans le contexte du
programme appelant. Par exemple, en reprenant l’exemple précédent :
programme de_test
c ... bon exemple !!
implicit none
integer dim, dim_util
parameter (dim=100)
real*8 xx (dim)
...
dim_util = 50
...
call f_tab_4 (dim_util, x)
...
end
62 sous programmes
Cette notion de dimension «utile» est souvent utilisée car il n’y a pas d’al-
location dynamique en Fortran 77 et les dimensions déclarées des ta-
bleaux sont souvent les dimensions maximales pour traiter une certaine
famille de problèmes.
x(1,1) x(2,1) x(3,1) x(4,1) x(5,1) x(1,2) x(2,2) x(3,2) x(4,2) x(5,2) x(1,3) .......... ......
.......... x(5,n))
Attention :
. il faut passer au sous programme les N-1 premières dimensions telles qu’elles
sont déclarées dans le programme appelant et pas seulement des «dimen-
sions utiles». Il n’y a pas d’allocation dynamique en Fortran 77 et une
pratique courante consiste à déclarer une taille maximale pour les tableaux
et donc à n’en utiliser qu’une partie. Cela ne pose aucun problème pour les
tableaux à une dimension mais risque de causer des ennuis avec des tableaux
à plusieurs dimensions.
programme pb_tableau
implicit none
c ...
integer dim_1, dim_2,
& dim_util_1, dim_util_2
c ...
parameter (dim=5, dim_2=3)
real*8 h (dim_1, dim_2)
c ...
dim_util_1=3
dim_util_2=2
c
c ... ATTENTION ERREUR !!!!!!
c
call f_tab_5 (dim_util_1, h)
c
c ... ATTENTION ERREUR !!!!!!
c
call f_tab_6 (dim_util_1, dimutil_2, h)
...
end
h(1,1) h(2,1) h(3,1) h(4,1) h(5,1) h(1,2) h(2,2) h(3,2) h(4,2) h(5,2) h(1,3) h(2,3) h(3,3)
...... h(4,3) h(5,3)
h(1,1) h(2,1) h(3,1) h(4,1) h(5,1) h(1,2) h(2,2) h(3,2) h(4,2) h(5,2) h(1,3) h(2,3) h(3,3)
...... h(4,3) h(5,3)
Les dimensions utiles sont passées au sous−programme: ERREUR, éléments de h accédés par ftab_5 et 6
subroutine f_tab_7
& (dim_1, dim_2, util_1, util_2, tx)
implicit none
c
c ... les dimensions reelles ET
c ... les dimensions utiles
integer dim_1, dim_2, util_1, util_2
c ... le dimensionnement doit utiliser les
c ... "n-1" premieres valeurs reelles
c
real*8 tx (dim_1, util_2)
...
..
end
programme OK_tableau
implicit none
integer dim_1, dim_2,
& dim_util_1, dim_util_2
parameter (dim_1=5, dim_2=3)
real*8 h (dim_1, dim_2 )
..
dim_util_1=3
dim_util_2=2
...
...
c
c ... cette fois ca marche
c
call f_tab_7
& (dim_1,dim_2,dim_util_1,dim_util_2, h)
...
end
Attention :
. notons qu’ici pour pouvoir utiliser aussi des fonctions prédéfinies (intrin-
sèques) on ne doit pas déclarer f comme étant a priori external ;
. en revanche, le programme qui appelle ce sous programme integration
doit obligatoirement déclarer le nom du sous programme passé en argu-
ment : si il s’agit d’un sous programme «utilisateur», il doit être déclaré
external. Cette déclaration est ici obligatoire :
programme util_integration
implicit none
real*8 xmin, xmax, result
c .......... fonction
external fff
real*8 fff
...
call integration (result, fff, xmin, xmax)
...
end
real*8 function fff (x)
implicit none
real*8 x
...
fff= ...
end
68 sous programmes
programme util_integration
implicit none
real*8 xmin, xmax, result
c .......... fonction
intrinsic dcos
real*8 dcos
...
...
call integration (result, dcos, xmin, xmax)
...
...
...
end
program ex_de_fonction
implicit none
real*8 a, b, c, d
...
c ... definition d’une fonction sum2
sum2(x,y,z)=x*x+y*y+z*z
...
d = sum2 (a, b, c)
...
end
Pratique en apparence, mais la définition étant noyée dans le reste du code tout
cela n’est pas très clair d’autant plus que cette définition à l’apparence d’une af-
fectation. Une justification possible était le coût trop élevé de l’appel à une «vrai»
fonction. Maintenant la plupart des compilateurs proposent des options permettant
de considérer certains sous programmes comme «ouverts» ou “inline”. À l’appel
d’une fonction «ouverte» le compilateur recopie le code exécutable correspondant
au lieu de générer un débranchement. Il n’y a pas de surcoût.
Conseil méthodologique :
I l’utilisation des fonction «en ligne» (aussi appelées «instructions fonc-
tions») ne se justifie plus de nos jours !
Chapitre 6
program avec_common
implicit none
integer iii
common /ok/ iii
call init()
...
call calcul(...)
...
end
subroutine init()
implicit none
integer iii
common /ok/ iii
...
iii=...
end
subroutine calcul (...)
implicit none
integer iii
common /ok/ iii
...
...
end
...
Attention :
. les anciennes versions de Fortran ne permettaient d’utiliser qu’une seule
zone commune sans nom. Il est très important en Fortran 77 de nom-
mer les zones communes. Le «common blanc» (ou sans nom) fait toujours
l’objet de la part des compilateurs actuels d’un traitement spécial qui peut
causer bien des soucis. . .
. pour que deux unités de programmation partagent effectivement une zone
commune, celle-ci doit aussi être déclaré «au dessus» dans l’arbre des ap-
pels. Les deux sous programmes calc_1 et calc_2 utilisent la zone com-
mune util. Si celle-ci n’apparaît pas «au dessus» les deux zones ne sont
pas a priori identiques. Ce qui se passe réellement dépend de la façon dont
le compilateur traite ces instructions ;
6.1 Variables partagées : le common 73
Program main
common /util/ ...
Subroutine_1(..) Subroutine_2(..)
common /util/ ... common /util/ ...
Program main
OUI
Subroutine_1(..) Subroutine_2(..)
common /util/ ... common /util/ ...
NON !!
. pour des raisons liées à l’optimisation de l’accès aux données dans la mé-
moire (problème d’alignement), si une zone commune contient des données
de plusieurs types, il faut mettre les plus longues en premier i.e. d’abord les
complex*16, complex*8 puis real*8, real*4 et enfin les integer
et les logical ;
...
complex *16 a(1000,1000),c(2000)
real*8 x(1000),y(1000),z(1000)
integer nb1, nb2
c .......... donnees bien rangees
common /data_1/ a, c, x, y, z, nb1, nb2
...
. il n’est pas possible de mélanger dans une zone commune des variable de
type character avec des variables d’autres types ;
. si deux unités de programmation partagent une zone commune, les variables
qu’elle contient ne doivent pas être passées de l’une à l’autre comme argu-
ment sous peine de provoquer de dangereux «effets de bord» (modifications
non désirées de variables).
74 Plus sur les Variables
program common_et_arg
implicit none
real*8eps
common /param/ eps
...
c ... argument et commom NON !!!!!!!!
call cal(eps)
...
end
subroutine cal (x)
implicit none
real*8 x
real*8 eps
common /param/ eps
...
...
end
Conseils méthodologiques :
I rappel, toujours nommer les zones communes ;
I on se servira des zones communes pour stocker des données dites d’envi-
ronnement, constantes physiques, un maillage etc. . .ces données sont né-
cessaires à la plupart des unités de programmation d’une application mais
elles ne sont modifiées que par un très petit nombre d’entre-elles, dûment
identifiées, typiquement les sous programmes de lecture des données ou
d’initialisations. Ainsi :
– les arguments d’une subroutine sont donc ceux sur lesquels elle tra-
vaille, en les modifiant éventuellement. Les variables «en commun» ne
doivent pas être modifiées sauf cas exceptionnel (sous programme d’ini-
tialisation, de lecture de données etc. . .) ;
– une function ne doit pas modifier ses arguments et pour la même
raison, jamais des variables «en commun».
I l’idéal est de placer dans un fichier à inclure, la déclaration des variables
et de la zone commune. Celui-ci sera recopié dans toutes les unités de
programme concernées avec une instruction include qui garantira que
toutes les déclarations sont bien identiques. Ce qui donne, en reprenant
notre premier exemple de common :
6.2 (pas de) block data 75
program include_common
implicit none
include ’comm_ok.h’
...
call init()
...
call calcul(...)
...
end
subroutine init()
implicit none
include ’comm_ok.h’
...
iii=...
end
subroutine calcul (...)
implicit none
include ’comm_ok.h’
...
...
end
...
program avec_common
implicit none
integer n
real*8 p, q
common /ok/ n, pi, q
...
...
...
end
block data pour_ok
common /ok/ n, pi, q
n =1000
pi=3.14159
q =6.0d-3
end
Conseil méthodologique :
I ne pas utiliser la construction block data. Des sous programme spé-
ciaux doivent effectuer les initialisations et les lectures de données (rap-
pellons aussi qu’il faut utiliser parameter pour les constantes). Certains
compilateurs récents ne savent même pas traiter correctement les construc-
tions block data.
Attention :
. la déclaration save doit figurer avant l’ordre data ;
. ne jamais compter sur la «rémanence par défaut».
Conseil méthodologique :
I ce mécanisme ne doit être utilisé qu’exceptionnellement ! Il y a bien sûr, le
cas (d’école) ci-dessus. Une autre utilisation est de pouvoir vérifier que cer-
taine initialisations ont été correctement effectuées et de garantir qu’elles
ne le seront qu’une seule fois.
subroutine init ()
implicit none
c .......... communs
real*8 eps, sigma
common /param/ eps, sigma
...
end
subroutine util (...)
implicit none
c .......... communs
real*8 eps, sigma
common /param/ eps, sigma
...
...
end
programme test
implicit none
c .......... communs
real*8 eps, sigma
common /param/ eps, sigma
call init ()
...
...
call util (...)
...
end
Tout se passe bien car la zone commune aux sous programmes init et à
util est aussi déclarée dans le programme principal «au dessus» ;
subroutine init ()
implicit none
c .......... communs
real*8 eps, sigma
common /param/ eps, sigma
save param
...
end
subroutine util (...)
implicit none
c .......... communs
real*8 eps, sigma
common /param/ eps, sigma
save param
...
...
end
programme test_save
implicit none
c .......... communs
call init ()
...
...
call util (...)
...
end
Conseil méthodologique :
I ce mécanisme ne doit être utilisé qu’exceptionnellement ! Il faut mieux du-
pliquer partout la déclaration des zones communes et si possible avec un
fichier à inclure. L’utilisation peut être justifiée par le fait que l’on a pas
accès au code source du programme appelant.
80 Plus sur les Variables
6.4 Le super-tableau
Il s’agit de gérer la mémoire «à la main» pour pallier l’absence d’allocation dy-
namique. Juste un exemple, le programmeur déclare dans le programme principal,
un super-tableau dans lequel il rangera tous les tableaux de reel*8 nécessaires.
Les tableaux utiles sont repérés par la position de leur premier élément dans le
super-tableau :
program test
implicit none
parameter (max_dim=10000)
c ... <<super-tableau>>
real*8 super(max_dim)
c ... pointeurs pour les tableaux
c ... des coordonnees x, y et z
integer ix, iy, iz
c ... n est la taille du probleme
integer n
...
c ... calcul des pointeurs dans super
ix=1
iy=ix+n
iz=iy+n
c ... ...
...
end
...
call util (n, super(ix), super(iy),
& super(iz), ... )
...
...
Conseil méthodologique :
I pratique car il n’y a qu’un paramètre à mettre à jour lorsque l’on change
la taille des problèmes visés. Pour que tout cela reste clair, il est préférable
que le super-tableau n’apparaîsse que dans le programme principal ;
I ne jamais mélanger les types et donc utiliser un super-tableau par type de
données (entier, réel(s), et complexe(s)).
...
real*8 x_0, x, y, z, val_1
real*8 val(100)
equivalence (x_0, val(1))
c ...
c ... x_0 <=> val(1)
...
...
real*8 a(100,100), v(100)
equivalence (v, a(1,10))
c ...
c ... v(i) <=> a(i,10)
...
L’on peut avoir plus de deux variables en «équivalence» et l’on peut aussi
regrouper les déclarations en les séparant par des virgules :
...
real*8 x_0, x, y, z. val_1
real*8 val(100), a(100,100), v(100)
equivalence ((x_0, val_1, val(1)), (v, a(1,10)))
c ... deux equivalences:
c ... x_0 <=> val_1 <=> val(1)
c ... v(i) <=> a(i,10)
...
Conseil méthodologique :
I ne jamais utiliser l’instruction equivalence source d’innombrables er-
reurs (de logique ou plus simplement d’inattention) ;
I de plus l’instruction equivalence inhibe généralement les optimisa-
tions effectuées normalement par le compilateurs : on ne peut plus garantir
que deux variables occupent en mémoire des emplacements distincts.
6.5 Synonymes : (pas d’) equivalence 83
Remarque :
⇒ cette instruction était souvent utilisée pour réaliser des système de gestion
de la mémoire palliant dans une certaine mesure l’absence d’allocation
dynamique en Fortran. Un tel système gére nous l’avons vu des «poin-
teurs» dans un «super-tableau». On peut déclarer un tableau pour chaque
type de données et les mettre en équivalence pour ne gérer qu’une seule
zone. Tout cela revient à faire à la main le travail normalement dévolu à
un compilateur. . ..
Chapitre 7
Les entrées/Sorties
7.2 Écran-clavier
Nous allons utiliser dans un premier temps le clavier et l’écran. C’est le mini-
mum pour communiquer et cela permet d’introduire simplement les instructions
86 Les entrées/Sorties
read et write.
...
integer n
real*8 x, y
...
read (5,*) n
...
read (5,*) x, y
...
...
...
integer n
real*8 x, y
...
read (unit=5,fmt=*) n
...
read (unit=5,fmt=*) x, y
...
Remarques :
⇒ la description «fine» des données à lire peut devenir nécessaire si l’on
veut lire par exemple des chaînes de caractères contenant des blancs. Le
comportement «normal» étant de retenir à partir du premier caractère non
blanc, une suite de caractères non blancs de longueur au moins égale à la
taille déclarée de la chaîne de caractère ;
⇒ pour lire des valeurs complexes, il faut taper au clavier deux réels (les
parties réelle et imaginaire) entre parenthèses et séparées par une virgule ;
⇒ les variables de type logique peuvent être entrées soit sous forme de constantes
logiques .true. (ou true) et .false. (ou false) soit sous forme
«condensée» T (ou t) pour “true” et F (ou f) “false” ;
Attention :
. tout cela ne fonctionne pas toujours aussi bien que l’on pourrait l’espérer !
Cela dépend des compilateurs, certains cherchent semble-t-il à interpréter
les entrées en ignorant a priori le type des données ce qui provoque des
erreurs avec les chaînes de caractères. Que faire ? et bien Fortran n’est
pas un langage fait pour manipuler des chaînes de caractères !
Conseil méthodologique :
I utiliser de préférence la forme sans mots-clef : read(5,*) ..., plus
«usuelle».
...
integer n
real*8 x, y
...
write (6,*) n
...
write (6,*) x, y
...
...
...
integer n
real*8 x, y
...
write (unit=6,fmt=*) n
...
write (unit=6,fmt=*) x, y
...
Remarques :
⇒ si l’on écrit une variable chaîne de caractère, c’est la longueur «utile» de
la chaîne qui est utilisée (i.e. ce qui y est stocké) ;
7.2 Écran-clavier 89
...
integer n
real*8 x, y
...
...
write (6,*) ’Voici un entier: ’, n
write (6,*) ’un reel:’, x,’ et un autre:’ y
write (6,*) ’c’’ est tout! au revoir’
write(6,*) ’ ’
...
⇒ les variables de type complexes sont écrites entre parenthèses, parties réelle
et imaginaire séparés par une virgule ;
⇒ Les variables de type logique sont écrites le plus souvent sous la forme T
et F pour (“true” et “false”) ;
⇒ normallement des instructions read (..,*) peuvent relire ce qui est
écrit avec write (..,*) mais on peut avoir des ennuis avec des chaînes
de caractères contenant des blancs.
Conseil méthodologique :
I utiliser de préférence la forme sans mots-clef : write (6,*) ..., plus
«usuelle».
7.2.3 Redirections
Il est possible (notamment sur les systèmes Unix) de «rediriger» l’entrée stan-
dard et la sortie standard d’un programme. Cela permet d’utiliser des fichiers sans
lire la suite. . .Si fpgm est le nom d’un exécutable, on peut taper les commandes
suivantes :
==> fpgm
c ........... NON
read *, x, y, n
...
c ........... mieux !!
read (5,*) x, y, n
...
Il existe enfin l’instruction print pour effectuer une écriture sur la sortie
standard :
c ........... NON
print *, x, y, n
...
c ........... mieux !!
write (6,*) x, y, n
...
7.3 Entrées-Sorties sur fichiers 91
Conseil méthodologique :
I ne pas utiliser les formes inutiles read *, ... et print *, ....
...
open (2, ...)
...
ou
...
c .......... utiliser plutot
open (unit=3, ...)
...
...
c .......... dans le repertoire "courant"
open (unit=3, file=’fpgm.don’, ...)
...
c .......... a partir du repertoire "courant"
open (unit=3, file=’data/fpgm.don’, ...)
...
c .......... chemin d’acces "absolu"
open (unit=3,
& file=’/home/anfray/data/fpgm.don’,...)
...
integer io_erreur
...
open (unit=3, file=’fpgm.don’,
& iostat=io_err, ...)
if (io_err.ne.0) then
c .......... echec !!
...
else
c .......... tout va bien
c .......... on peut continuer
...
...
...
endif
...
94 Les entrées/Sorties
Conseils méthodologiques :
I les unités «stantards» (5, et 6) sont gérées par le système et il faut mieux
éviter d’effectuer des open dessus.
Récapitulation :
7.3 Entrées-Sorties sur fichiers 95
...
close (2, ...)
...
ou
...
c .......... utiliser de preference
close (unit=3, ...)
...
En cas d’erreur : nous retrouvons ici les paramètres de l’instruction open avec
les mêmes significations. La «fermeture» du fichier peut échouer elle aussi :
(il ne peut être conservé ou détruit, etc. . .) et de même il est préférable
d’agir en conséquence avant la fin du programme. Comme au paragraphe
précédent :
– iostat a pour valeur le nom d’une variable entière qui contiendra, après
exécution de l’instruction, un code d’erreur : zéro, bien sûr si tout c’est
bien passé ;
– err a pour valeur une étiquette qui référence l’instruction du programme
à exécuter en cas d’erreur. Son utilisation n’est pas recommandée.
7.4 Informations, l’instruction inquire 97
...
integer io_erreur
...
close (unit=3, iostat=io_erreur)
if (io_erreur.eq.0) then
c .......... tout va bien
...
...
else
c .......... echec !!
...
...
endif
...
Conseil méthodologique :
I toujours refermer un fichier après usage.
Récapitulation :
– sur une «unité physique», donc un fichier, existe-t-il ?, quel est son «for-
mat», est-il relié à une unité logique ouverte etc. . . ;
– sur une «unité logique», est-elle fermée, ouverte et dans ce cas quel type de
fichier y est connecté etc. . ..
Le premier paramètre sera donc soit une unité logique soit un fichier. Les
autres paramètres possibles se donnent sous forme de mots-clef auquels on fait
correspondre des variables qui contiendront les informations désirées. On distin-
guera trois «familles» d’arguments. Ceux dont la valeur de retour à toujours un
sens, ceux qui n’ont de sens que si le fichier ou l’unité existe ou est ouvert et enfin
ceux qui ne concernent que certaine organisations de fichiers. Les deux requêtes
(unité logique ou fichier) sont similaires :
inquire pour un fichier : le premier paramètre obligatoire se code à l’aide du
motclef file, la valeur est une chaîne de caractères qui contient le nom de
fichier. Comme pour l’instruction open, le nom peut contenir un chemin
d’accès relatif ou absolu :
...
c .......... dans le repertoire "courant"
inquire (file=’fpgm.don1’, ...)
c .......... a partir du repertoire "courant"
inquire (file=’data/fpgm.don2’, ...)
c .......... chemin d’acces "absolu"
inquire (file=’/home/anfray/fpgm.don3’, ...)
inquire pour une unité logique : le premier paramètre obligatoire se code alors
à l’aide du motclef (optionnel) unit.
...
inquire (3, ...)
...
c .......... utiliser de preference
inquire (unit=3, ...)
En cas d’erreur : nous retrouvons ici les même paramètres que dans open ou
close :
7.4 Informations, l’instruction inquire 99
– iostat a pour valeur le nom d’une variable entière qui contiendra, après
exécution de l’instruction, un code d’erreur : zéro, bien sûr si tout c’est
bien passé ;
– err a pour valeur une étiquette qui référence l’instruction du programme
à exécuter en cas d’erreur. Son utilisation n’est pas recommandée.
Le fichier existe-t-il ? : le mot-clef exist associé à une variable de type logical
permet de savoir si un fichier existe :
– exist=fic_ok (avec la déclaration logical fic_ok) si fic_ok
vaut .true. le fichier existe sinon fic_ok vaut .false..
L’organisation et le contenu du fichier : si le fichier existe, il est possible d’ac-
céder aux informations nécessaires pour l’ouvrir, les valeurs que l’on ré-
cupère alors peuvent servir à l’instruction open. L’organisation du fichier
peut être connue à l’aide des deux mots-clef sequential et direct (qui
renvoient au mot-clef access de l’instruction open). Si le fichier n’existe
pas, les valeurs retournées sont sans significations :
– sequential=fic_seq avec la déclaration character*7 fic_seq,
le fichier a-t-il une organisation séquentielle les valeurs possibles sont
’yes’, ’no’ ou ’unknown’ ;
– direct=fic_dir (avec la déclaration character*7 fic_seq)
est-ce un fichier en accès direct les valeurs possibles sont ’yes’, ’no’
ou ’unknown’.
La nature du contenu du fichier peut être connue à l’aide des deux mots-
clef formatted et unformatted (qui renvoient au mot-clef form de
l’instruction open) :
– formatted=fic_form, avec la déclaration character*7 fic_form,
le fichier est-il «formatté» les valeurs possibles sont ’yes’, ’no’ ou
’unknown’ ;
– unformatted=fic_unform (avec character*7 fic_form), le
fichier est-il «non-formatté» les valeurs possibles sont ’yes’, ’no’ ou
’unknown’.
Le fichier ou l’unité logique est-il ouverte ? : le mot-clef opened associé à une
variable de type logical permet de savoir si une unité logique est ouverte
ou si un fichier est relié à une unité ouverte :
– opened=ouvert (avec la déclaration logical ouvert) les réponses
possibles sont .true. ou .false..
À quelle unité logique est relié un fichier ? si le fichier est ouvert, i.e. relié à
une unité logique on peut alors utiliser :
– number=fic_num (avec la déclaration integer fic_num), qui re-
tourne le numéro de l’unité logique reliée au fichier par une instruction
open ;
100 Les entrées/Sorties
À quel fichier est reliée une unité logique ? si l’unité est ouverte, elle peut être
reliée à un fichier dont on a précisé le nom (ce n’est pas obligatoire : cas
d’un fichier temporaire ! !) ;
– name=nom_fic avec par exemple character*80 nom_fic (il faut
prévoir assez de place), qui retourne le nom du fichier relié à l’unité lo-
gique par une instruction open ;
Comment l’unité logique a-t-elle été ouverte ? si une unité logique est ouverte,
il est possible de connaître les valeurs de des arguments passés à l’instruc-
tion open (ou les valeurs par défaut si ils ont été omis) :
– form=unit_cont (avec la déclaration character*11 unit_cont),
permet de connaître la nature de ce qui sera lu ou écrit, les valeurs pos-
sibles sont ’formatted’ ou ’unformatted’.
– form=unit_org (avec la déclaration character*10 unit_org),
permet de connaître l’organisation du fichier associé, Les valeurs pos-
sibles sont ’sequential’ ou ’direct’.
Si l’unité a été ouverte en mode «formatté» , on peut s’intéresser à l’interpré-
tation des caractères blanc éventuellement présent dans une constante nu-
mérique (exotique et rarement utile) :
– blank=unit_bl (avec la déclaration character*4 unit_bl), la
valeur blank=’null’ indique qu’ils seront ignorés en revanche, la va-
leur blank=’zero’ indique qu’ils seront considérés comme des zéros.
Si l’unité a été ouverte en accès direct , le fichier correspondant est constitué d’
«enregistrements» dont la taille maximale a été précisée lors de l’ouverture :
– recl=unit_rec (avec la déclaration integer unit_rec), retourne
la taille maximale des enregistrements ;
– nextrec= i ( integer i) retourne la position du «pointeur mobile»
dans le fichier c’est à dire la valeur 1 si l’on a encore rien fait ou le
numéro du dernier enregistrement accédé plus 1 sinon.
...
read (unit=2, ...)
...
c .......... le plus frequent
read (2, ...)
c ........... ou mieux
read (2, fmt=*) x, y, z
c ........... ou mieux
read (2, fmt=1000) x, y, z
c ........... ou mieux
read (2, fmt=’(...)’) x, y, z
En cas d’erreur : nous retrouvons ici les paramètres des instructions open et
close avec la même signification et un nouveau venu pour gérer la fin de
fichier :
– iostat a pour valeur le nom d’une variable entière qui contiendra, après
exécution de l’instruction, un code d’erreur : zéro, bien sûr si tout c’est
bien passé, sinon une autre valeur qui dépend de l’environnement d’exé-
cution. Cette valeur sera négative si l’on essaie de lire après la fin du
fichier ;
– err a pour valeur une étiquette qui référence l’instruction du programme
à exécuter en cas d’erreur. Son utilisation n’est pas recommandée.
– end a pour valeur une étiquette qui référence l’instruction du programme
à exécuter si l’on essaie de lire après la fin du fichier. Il s’agit encore une
fois d’un goto déguisé et son utilisation n’est pas recommandée d’autant
plus que iostat permet d’avoir cette information.
Conseil méthodologique :
I utiliser seulement iostat et non err ou end qui sont des débranche-
ments déguisés !
...
write (unit=10, ...)
...
c .......... le plus frequent
write (10, ...)
7.5 read et write : entrées/Sorties «formattées» 103
c ........... ou mieux
write (10, fmt=*) x, y, z
c ........... ou mieux
write (10, fmt=1000) x, y, z
c ........... ou mieux
write (10, fmt=’(...)’) x, y, z
En cas d’erreur : nous retrouvons ici les paramètres des instructions open et
close avec la même signification :
– iostat a pour valeur le nom d’une variable entière qui contiendra, après
exécution de l’instruction, un code d’erreur : zéro, bien sûr si tout c’est
bien passé ;
– err a pour valeur une étiquette qui référence l’instruction du programme
à exécuter en cas d’erreur. Son utilisation n’est pas recommandée.
Conseil méthodologique :
I utiliser seulement iostat et non err qui est débranchement déguisé !
104 Les entrées/Sorties
...
1001 format (a,i2,a,f8.2,a5)
integer ii
real*8 x
...
write (6, 10001) ’je tente ma chance ii=’, ii,
& ’ et x=’, x , ’ ....’
...
Tout se passe bien si les valeurs des variables ii et x «rentrent» bien dans
les «trous» qui leurs sont assignés sinon on récupère généralement des étoiles
(exemple ii vaut 456 et on veut l’écrire dans un champ de taille 2) :
Catastrophe surtout si les valeurs sont les résultats d’un long calcul. Plus dif-
ficile à déceler, si le format pour les réels est mal choisi on peut perdre de l’infor-
mation : ne pas afficher suffisament de chiffres significatifs, etc. . .
7.6 read et write : entrées/Sorties «binaires» 105
Conseil méthodologique :
I obsolète et dangereux. À éviter à moins d’être fanatique d’impressions bien
alignées. Utiliser systématiquement le «format *».
I si l’on ne peut pas s’en passer, on peut aussi «doubler» subtilement cer-
taines impressions dans un fichier qui fera foi.
Attention :
. avec le «format *», l’aspect des sorties peut varier d’un système à l’autre. Il
n’est pas possible de comparer deux résultats d’un même programme avec
la fonction Unix diff qui teste l’égalité de deux fichier au niveau binaire.
integer n
real*8 x,y
real*8 a(1000)
...
read (22, ...) n, x, y
read (22, ...) a
...
est fixé par les dimensions déclarées du tableau dans l’unité de programmation
qui effectue l’écriture.
integer n
real*8 x,y
real*8 a(1000)
...
write (88, ...) n, x, y
write (88, ...) a
...
...
real*8 xx(1000), yy(1000)
integer num_rec
...
num_rec= ...
...
c .......... lecture sur un fichier en acces direct
read (23, rec=num_rec, ...) xx, yy
...
...
real*8 a(1000)
...
...
c .......... ecriture sur un fichier en acces direct
write (22, rec=7) a
...
7.8.1 Rembobiner
Ce non est bien sur hérité des bandes magnétiques. Cette instruction permet
de revenir au début du fichier connecté à une unité logique. Les arguments sont :
L’ unité logique : le premier paramètre obligatoire se code de préférence à l’aide
du mot-clef unit.
...
rewind (3, ...)
...
c .......... utiliser de preference
rewind (unit=3, ...)
En cas d’erreur : nous retrouvons ici les paramètres des instructions open et
close avec la même signification :
– iostat (recommandé) et err (à éviter).
Attention :
108 Les entrées/Sorties
. ne pas utiliser avec les unités «standards» 5 et 6 qui peuvent être reliées au
clavier ou à l’écran ;
. ne pas utiliser avec les fichiers en accès direct.
Conseil méthodologique :
I peut être utile pour lire plusieurs fois le même fichier ou pour gérer des
fichier temporaires, mais son utilisation doit rester exceptionnelle.
...
backspace (25, ...)
...
c .......... utiliser de preference
backspace (unit=25, ...)
En cas d’erreur : nous retrouvons ici les paramètres des instructions open et
close avec la même signification :
– iostat (recommandé) et err (à éviter).
Attention :
. ne pas utiliser avec les unités «standards» 5 et 6 qui peuvent être reliées au
clavier ou à l’écran ;
. ne pas utiliser avec les fichiers en accès direct.
Conseil méthodologique :
I cette instruction est réputée peu efficace mais surtout ne semble pas fonc-
tionner de façon «homogène» sur tous les systèmes. À proscrire absolu-
ment !
7.9 Des exemples 109
...
endfile (25, ...)
...
c .......... utiliser de preference
endfile (unit=25, ...)
En cas d’erreur : nous retrouvons ici les paramètres des instructions open et
close avec la même signification :
– iostat (recommandé) et err (à éviter).
Attention :
. ne pas utiliser avec les unités «standards» 5 et 6 qui peuvent être reliées au
clavier ou à l’écran ;
. ne pas utiliser avec les fichiers en accès direct.
Conseil méthodologique :
I cette instruction ne semble pas fonctionner de façon «homogène» sur tous
les systèmes. À proscrire ! sauf éventuellement et exceptionnellement dans
le cas de fichiers temporaires.
exemple pour des fichiers de sorties si l’on veut être sûr de ne pas écraser des
résultats déjà obtenus :
...
integer io_erreur
c .......... fichier de donnees, doit exister
open (unit=3, file=’fpgm.don3’, status=’old’,
& iostat=io_erreur)
...
c .......... le fichier 3 est a detruire apres lecture
close (unit=3, status=’delete’, iostat=io_erreur)
...
...
integer io_erreur
c .......... fichier resultat ecrase si il existe deja
open (unit=7, file=’fpgm.res7’, status=’unknown’,
& iostat=io_erreur)
...
c .......... le fichier 7 est conserve
close (unit=7, iostat=io_erreur)
...
...
integer io_erreur
char*80 nom_file_res
...
nom_file_res= ...
...
c .......... ce fichier de resultat est a creer
c .......... obligatoirement
open (unit=8, file=nom_file_res, status=’new’,
& form=’unformatted’, iostat=io_erreur)
...
c .......... le fichier 8 est conserve
close (unit=8, iostat=io_erreur)
...
7.9 Des exemples 111
Il est souvent intéressant d’utiliser des fichiers «binaires» c’est à dire non
formattés pour stocker de grosses quantités d’informations (typiquement des ta-
bleaux de nombres).
Ces fichiers sont moins volumineux mais surtout il n’y a pas de pertes d’infor-
mation dues, par exemple, aux arrondis (contrairement à ce qui peut se passer lors
d’une écriture et d’une relecture d’un nombre représenté sous forme de chaîne de
caractères).
...
integer io_erreur
...
...
c
c .......... creation fichier de donnees binaire
c
open (unit=10, file=’fpgm.bin1’, status=’old’,
& form=’unformatted’, iostat=io_erreur)
...
write (10) ...
...
...
close (unit=10, iostat=io_erreur)
...
Cette possibilité n’existe pas toujours sur les calculateurs. . .on l’utilise le plus
souvent pour optimiser l’accès à de grandes quantités de données et donc avec des
fichiers non formattés. Le paramètre recl indique une taille maximale pour les
enregistrements lu ou écrits par le programme (bien sûr, chaque système impose
sa propre limitation «physique») :
112 Les entrées/Sorties
...
real*8 a(100), b(100), c(50)
integer io_erreur, num_rec
...
...
c
c .......... fichier de donnees (binaires)
c .......... a acces direct
c
open (unit=33, file=’newdata/fpgm.dir3’,
& status=’old’, access=’direct’,
& recl=5000, iostat=io_erreur)
...
...
c
c .......... lecture de l’enregistrement num_rec
c
read (33, rec=num_rec) a, b, c
...
...
...
close (unit=33, iostat=io_erreur)
...
...
integer io_erreur
... ...
c .......... fichier temporaire
open (unit=50, status=’scratch’,
& form=’unformatted’, iostat=io_erreur)
...
c .......... sauvegarde de donnees
write(50) ...
...
c .......... <<rembobinage>>
rewind(50)
...
c .......... relecture des donnees sauvegardees
read(50)
...
c .......... ici le statut par defaut est ’delete’
close (unit=50, iostat=io_erreur)
...
114 Les entrées/Sorties
Chapitre 8
Souvent ces fonctions ont un nom générique et des noms spécifiques dépen-
dant du type des arguments. Il est bien sûr préférable d’utiliser le nom générique !
Néanmoins, rappellons que si l’on utilise une ce ces fonctions comme argument
l’usage du nom spécifique s’impose. Il n’est pas obligatoire mais préférable d’uti-
liser la déclaration intrinsic pour exprimer que l’on utilise une fonction stan-
dard Fortran ce qui permet d’éviter les confusions avec des fonctions «utilisa-
teur».
8.1 Conversions
modulo
mod integer integer i=mod(j,k)
real real
double precision double precision
valeur absolue
abs integer integer x=abs(y)
real real
double precision double precision
complex real
double complex(∗) double precision
racine carrée
sqrt real real x=sqrt(y)
double precision double precision
complex complex
double complex(∗) double complex(∗)
exponentielle
exp real real x=exp(y)
double precision double precision
complex complex
double complex(∗) double complex(∗)
logarithme
log real real x=log(y)
double precision double precision
complex complex
double complex(∗) double complex(∗)
logarithme en base 10
log10 real real x=log10(y)
double precision double precision
8.3 Fonctions mathématiques 119
sinus
sin real real x=sin(y)
double precision double precision
complex complex
double complex(∗) double complex(∗)
cosinus
cos real real x=cos(y)
double precision double precision
complex complex
double complex(∗) double complex(∗)
tangente
tan real real x=tan(y)
double precision double precision
arc sinus
asin real real x=asin(y)
double precision double precision
arc cosinus
acos real real x=acos(y)
double precision double precision
sinus hyperbolique
sinh real real x=sinh(y)
double precision double precision
cosinus hyperbolique
cosh real real x=cosh(y)
double precision double precision
tangente hyperbolique
tanh real real x=tanh(y)
double precision double precision
partie réelle
real complex real x=real(c)
double complex(∗) double precision
partie imaginaire
imag complex real x=imag(c)
double complex(∗) double precision
8.4 chaînes de caractères 121
Comparaison, ordre lexical (llt : <, lle : <=, lge : >=, lgt : >)
Conversions
Manipulations variées
Fonctions mathématiques
Précédence et associativité
Opérateurs : Associativité :
** droite
∗ / gauche
+ (unaire et binaire) - (unaire et binaire) gauche
// (concaténation) gauche
.not. droite
.and. gauche
.or. gauche
.eqv. .neqv. gauche
Ce ne sont pas des «mots reservés» mais il est préférable d’éviter de les utiliser
pour nommer des variables.
– program, subroutine, function, block data, entry
– integer, real, logical, character, double precision,
complex
– implicit
– double complex, implicit none (extensions à la norme)
– common, dimension, equivalence, parameter, external,
intrinsic
– save, data
– assign, to, call, go to, do, if, then, else, elseif,
endif
– continue, pause, return, end, stop
– open, close, inquire, read, write, print, format, endfile
– rewind, backspace
D’autres mots-clef sont utilisés uniquement dans les ordres d’entrées/sorties (open,
close, inquire, read et rewind) :
– access, blank, direct, end, err, exit, file, fmt, form
– iostat, name, named, nextrec, number, opened, rec, recl
– sequential, status, unformatted, unit
Il faudrait rajouter à cette liste les noms de toutes les fonctions prédéfinies.