8. Procédures▲
8-1. Arguments▲
Très souvent, dans un programme, on a besoin d'effectuer un même traitement plusieurs fois avec des valeurs différentes. La solution est de définir ce traitement une seule fois à l'aide d'une unité de programme de type procédure (SUBROUTINE ou FUNCTION). Les unités de programmes désirant effectuer ce traitement feront appel à cette procédure en lui transmettant des valeurs via des variables appelées arguments d'appel (actual-arguments). La procédure appelée récupère les valeurs qu'on lui a transmises via des variables appelées arguments muets (dummy arguments).
En Fortran le passage de ces valeurs s'effectue par référence :
- les adresses des arguments d'appel sont transmises à la procédure appelée ;
- dans la procédure appelée, les arguments muets sont des alias des arguments d'appel.

8-2. Subroutines▲
L'appel d'une procédure de type SUBROUTINE s'effectue à l'aide de l'instruction CALL suivie du nom de la procédure à appeler avec la liste des arguments d'appels entre parenthèses.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
REAL, DIMENSION(100) :: tab
REAL :: moyenne, maximum
...
CALL SP( tab, moyenne, maximum )
PRINT *,moyenne, maximum
END
SUBROUTINE SP( t, moy, max )
REAL, DIMENSION(100) :: t
REAL :: moy, max
INTEGER :: i
max = t(1); moy = t(1)
DO i=2,100
IF ( t(i) > max ) max = t(i)
moy = moy + t(i)
END DO
moy = moy/100
END SUBROUTINE SP
8-3. Fonctions▲
Un autre moyen de transmettre des valeurs à une unité de programme est l'utilisation d'une procédure de type FUNCTION.
À la différence d'une SUBROUTINE, une FUNCTIONretourne une valeur, celle-ci est donc typée. De plus, son appel s'effectue en indiquant uniquement son nom suivi entre parenthèses de la liste des arguments d'appels.
Au sein de la fonction l'instruction return sert à transmettre à la procédure appelante la valeur à retourner. Celle-ci n'est nécessaire que dans le cas où on désire effectuer ce retour avant la fin de la définition de la fonction.
Dans la procédure appelante, l'expression correspondant à l'appel de la fonction est remplacée par la valeur retournée.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
REAL, DIMENSION(100) :: tab
REAL :: moyenne, maximum
REAL :: maxi
...
maximum = maxi( tab, moyenne )
PRINT *,moyenne, maximum
...
END
FUNCTION maxi( t, moy )
REAL, DIMENSION(100) :: t
REAL :: moy, maxi
INTEGER :: i
maxi = t(1); moy = t(1)
DO i=2,100
IF ( t(i) > maxi ) maxi = t(i)
moy = moy + t(i)
END DO
moy = moy/100
END FUNCTION maxi
8-4. Arguments de type chaîne de caractères▲
Lorsqu'une chaîne de caractères est transmise en argument, Fortran passe également sa longueur de façon implicite.
Dans la procédure appelée, celle-ci peut être récupérée à l'aide de la fonction intrinsèque LEN.
La déclaration de la chaîne de caractères au sein de la procédure appelée est faite en spécifiant le caractère ∗ à la place de la longueur.
La procédure appelée fait alors référence à une chaîne de caractères à taille implicite (assumed-size string).
Dans l'exemple ci-dessous les fonctions ICHAR/ACHAR permettent de mettre en relation un caractère et son rang dans la table des caractères ASCII.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
program arg_chaine
implicit none
character(len=10) :: ch
read '(a)',ch
call conv( ch )
print *,ch
end program arg_chaine
subroutine conv( chaine )
implicit none
character(len=*) :: chaine
integer i, j
do i=1,len(chaine)
if( ichar( chaine(i:i) ) < 97 .or. &
ichar( chaine(i:i) ) > 122 ) cycle
j = ichar( chaine(i:i) ) - 32
chaine(i:i) = achar( j )
end do
end subroutine conv
8-5. Arguments de type tableau▲
Lorsque l'on transmet un tableau en argument, il est commode de transmettre également ses dimensions afin de pouvoir déclarer l'argument muet correspondant au sein de la procédure appelée à l'aide de celles-ci ; de ce fait le tableau est ajustable.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
program arg_tab
implicit none
integer, parameter :: n = 3, m = 2
real, dimension(n,m) :: tab
real :: somme
read *,tab; print *,somme( tab, n, m )
end program arg_tab
real function somme( t, n, m )
integer :: n,m,i,j
real, dimension(n,m) :: t
somme = 0.
do i=1,n
do j=1,m
somme = somme + t(i,j)
end do
end do
end function somme
Lorsqu'un tableau est passé en argument, c'est l'adresse de son premier élément qui est transmise.
La procédure appelée doit posséder les informations lui permettant d'adresser les différents éléments de ce tableau. De façon générale, supposons que l'on dispose d'un tableau tab à 2 dimensions constitué de n lignes et m colonnes. L'adresse de l'élément tab(i,j) est :
@tab(i,j) = @tab(1,1) + [n*(j-1)+(i-1)]*taille(élt)Le nombre de colonnes m n'intervient pas dans ce calcul. Souvent en Fortran, lors de l'appel d'une procédure, seule la première dimension d'un tableau à 2 dimensions est transmise.
Dans la procédure appelée, celui-ci est déclaré en indiquant le caractère ∗ à la place de la deuxième dimension. On fait alors référence à un tableau à taille implicite (assumed-size array).
Dans un tel cas, il faut faire preuve d'une certaine prudence, car dans la procédure appelée on ne maîtrise pas l'espace mémoire total occupé par le tableau.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
program taille_implicite
implicit none
integer, parameter :: n = 5, m = 6
real, dimension(n,m) :: tab
real :: somme, som
read *, tab
somme = som( tab, n )
print *,somme
end program taille_implicite
real function som( t, lda )
implicit none
real, dimension(lda,*) :: t
integer :: lda
integer :: i,j
som = 0.
do i=1,lda
do j=1,lda
som = som + t(i,j)
end do
end do
end function som
8-6. Arguments de type procédure▲
Une procédure peut être transmise à une autre procédure. Il est nécessaire de la déclarer dans la procédure appelante avec l'attribut EXTERNAL ou INTRINSIC si elle est intrinsèque.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
program arg_proc
implicit none
double precision b_inf, b_sup, aire
double precision integrale
integer pas
double precision, external :: carre
b_inf = 1.
b_sup = 6.
pas = 200000
aire = integrale( b_inf, b_sup, pas, carre )
print '("Aire : ", f11.6)', aire
end program arg_proc
function integrale( borne_i, borne_s, pas, f )
implicit none
double precision borne_i, borne_s
double precision integrale
integer pas, i
double precision h, f
h = (borne_s - borne_i)/pas
integrale = 0.
do i=0, pas-1
integrale = integrale + h*f(borne_i+i*h)
end do
end function integrale
function carre( x )
implicit none
double precision x
double precision carre
carre = x*x
end function carre
8-7. Procédures internes▲
En Fortran une procédure peut en contenir d'autres. Ces procédures sont appelées procédures internes. Elles ne peuvent être appelées que depuis la procédure les contenant.
Les définitions des procédures internes sont faites dans la procédure les incluant après l'instruction CONTAINS.
Il n'y a pas d'imbrications possibles : une procédure interne ne peut pas elle-même en contenir.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
program proc_interne
implicit none
character(len=10) :: ch
read '(a)',ch
call conversion( ch )
print *,ch
end program proc_interne
subroutine conversion( chaine )
implicit none
character(len=*) :: chaine
integer i
do i=1,len(chaine)
if( ichar( chaine(i:i) ) < 97 .or.
ichar( chaine(i:i) ) > 122 ) cycle
chaine(i:i) = car_majuscule( chaine(i:i) )
end do
CONTAINS
function car_majuscule( c )
character(len=1) :: c, car_majuscule
integer :: i
i = ichar( c ) - (ichar('a') - ichar( 'A' ))
car_majuscule = achar( i )
end function car_majuscule
end subroutine conversion
Dans une procédure interne, toute variable déclarée dans l'unité de programme qui la contient est accessible, à moins qu'elle n'ait fait l'objet d'une redéclaration.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
program visibilite
implicit none
integer i, j
i = 10; j = 20
call sub
print '("i =",i3,", j =",i3)', i, j
contains
subroutine sub
integer j ! masque le "j" de l'appelant
j = 100; i = i + 1
end subroutine sub
end program visibilite
|
Sortie |
|---|
|
i^=^11,^j^=^20 |
8-8. Durée de vie et visibilité des identificateurs▲
On appelle durée de vie d'un identificateur, le temps pendant lequel il existe en mémoire. Il est visible s'il existe en mémoire et est accessible, car il peut exister, mais être masqué par un autre de même nom (c.f. procédure interne).
- Par défaut, une variable a une durée de vie limitée à celle de l'unité de programme dans laquelle elle a été définie ;
- l'attribut
SAVEpermet de prolonger la durée de vie à celle de l'exécutable : on parle alors de variable permanente ou statique ; - dans une unité de programme l'instruction
SAVEsans spécification de liste de variables indique que toutes les variables de cette unité sont permanentes ; - une compilation effectuée en mode static force la présence de l'instruction
SAVEdans toutes les unités de programme, ce qui implique que toutes les variables sont permanentes ; -
par contre si elle est faite en mode stack, les variables permanentes sont :
- celles pour lesquelles l'attribut
SAVEa été précisé, - celles initialisées à la déclaration (via l'instruction
DATAou à l'aide du signe =).
- celles pour lesquelles l'attribut
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
program newton
double precision :: valeur = 50.d0
double precision :: tolerance
double precision :: racine, x
tolerance = 1.0d-1
x = racine( valeur, tolerance )
print '("Racine de ",f5.1," = ", d16.8)', valeur, x
tolerance = 1.0d-6
x = racine( valeur, tolerance )
print '("Racine de ",f5.1," = ", d16.8)', valeur, x
end program newton
function racine( valeur, tol )
double precision :: valeur, tol
double precision :: racine
double precision :: x = 1.0d0, x_prev
integer :: nb_iterations
nb_iterations = 0
do
nb_iterations = nb_iterations + 1
x_prev = x
x = 0.5 * (x_prev + valeur/x_prev)
if ( abs(x-x_prev)/x < tol ) exit
end do
print *,"Nombre d'itérations = ", nb_iterations
racine = x
end function racine
8-9. Procédures intrinsèques▲
Le compilateur Fortran dispose d'une bibliothèque de procédures couvrant différents domaines : mathématique, conversion de type, manipulation de chaînes de caractères, comparaison de chaînes de caractères…
Pour une procédure donnée, le nom d'appel diffère suivant le type des arguments transmis. Un nom générique permet de s'affranchir de ces types : c'est la solution fortement conseillée, car elle facilite la portabilité.
Par exemple un appel à la procédure générique ABS, retournant la valeur absolue de son argument, est transformé par le compilateur en un appel à la procédure :
IABSpour un argument entier ;ABSpour un argument réel simple précision ;DABSpour un argument réel double précision ;CABSpour un argument complexe.
Une liste des procédures intrinsèques est fournie en annexe BAnnexe B : procédures intrinsèques.


