IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Les notions de base du Fortran

Support de cours


précédentsommairesuivant

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.
Image non disponible
Schéma passage arguments

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.

Exemple
Sélectionnez
1.
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.

Exemple
Sélectionnez
1.
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.

Exemple
Sélectionnez
1.
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.

Exemple
Sélectionnez
1.
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 :

 
Sélectionnez
@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.

Exemple
Sélectionnez
1.
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.

Exemple
Sélectionnez
1.
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.

Exemple
Sélectionnez
1.
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.

Exemple
Sélectionnez
1.
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 SAVE permet 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 SAVE sans 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 SAVE dans 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 SAVE a été précisé,
    • celles initialisées à la déclaration (via l'instruction DATA ou à l'aide du signe =).
 
Sélectionnez
1.
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 :

  • IABS pour un argument entier ;
  • ABS pour un argument réel simple précision ;
  • DABS pour un argument réel double précision ;
  • CABS pour un argument complexe.

Une liste des procédures intrinsèques est fournie en annexe BAnnexe B : procédures intrinsèques.


précédentsommairesuivant

Copyright © 2006 Patrick Corde et Anne Fouilloux. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.