IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo
Sommaire > Le programme principal et les sous programmes
        Quelle est la différence entre une FUNCTION et une SUBROUTINE ?
        Comment récupérer un paramètre/argument en ligne de commande ?
        Qu'est ce qu'une variable locale/globale ?
        Comment passer des variables en arguments vers/depuis une subroutine ?
        Comment utiliser un common pour partager des variables entre sous programmes (F77) ?
        Comment utiliser un module pour partager des variables entre sous programmes (F90) ?



Quelle est la différence entre une FUNCTION et une SUBROUTINE ?
auteur : Germain Salvato-Vallverdu
Les function et les subroutine sont littéralement traduits de l'anglais par fonction et sous-programme. Ce sont les deux types de sous programmes disponnibles en Fortran.

Les différences majeures entre une fonction et une subroutine sont :
  • Une function est également une variable qui contient le résultat de la fonction alors que le ou les résultats d'une subroutine sont en paramètres. Il s'ensuit qu'une fonction doit être déclarée.
  • Pour appeler une subroutine on utilise la commande call alors qu'une function n'en a pas besoin.
  • Une function doit forcément renvoyer un résultat stocké dans une variable (qui peut être un tableau). Une subroutine peut ne renvoyer aucun résultat et juste réaliser une action (écrire dans un fichier, nettoyer l'écran ...).
Les fonctions

Voyons un exemple simple d'une fonction et de son appel. Une fonction est, par exemple, de la forme f(x) = a*x + b. Voici un programme qui utilise cette fonction :
Un exemple de fonction
 PROGRAM test_function
 ! programme principal
 implicit none
 integer::i
 real::f,a,b,x,y

 a = 1.d0
 b = 2.d0

 x=0.d0
 Do i=1,100
    x = x + 0.1d0
    write(*,*)x,f(a,b,x)  ! appel de la fonction
 Enddo

 ! autre exemple
 x=0.d0
 Do i=1,100
    x = x + 0.1d0
    y = f(a,b,x)          ! appel de la fonction 
    write(*,*)x,y 
 Enddo

 END PROGRAM test_function

! * * * * * * * * * * * *

 FUNCTION f(a,b,x)
 implicit none
 real,intent(in)::a,b,x
 real::f     ! dans une fonction son nom est déclaré

 f = a*x + b ! quelque part dans une fonction on doit assigner une valeur à f

 END FUNCTION f
Les subroutines

Pour continuer l'exemple précédent, on peut programmer une subroutine qui va lire les paramètres a et b de la fonction f(a,b,x).
Un Exemple de subroutine
 PROGRAM test_function
 ! programme principal
 ! la subroutine n'est pas déclarée
 implicit none
 integer::i
 real::a,b,f,x
 
 call lec(a,b)   ! on utilise call pour appeler une subroutine
 
 x = 0.d0
 Do i=1,100
    x = x + 0.1d0
    write(*,*)x,f(a,b,x)
 Enddo
 
 END PROGRAM test_function
 
! * * * * * * * * * * * * * *
 
 SUBROUTINE lec(a,b)
 implicit none
 real,intent(out)::a,b   ! on précise que a et b sont des argument de sortie
 
 write(*,*)"entrer a et b"
 read(*,*)a,b
 write(*,*)"a = ",a
 write(*,*)"b = ",b
 
 END SUBROUTINE lec
 
! * * * * * * * * * * * * * *

 FUNCTION f(a,b,x)
 implicit none
 real,intent(in)::a,b,x
 real::f     ! dans une fonction son nom est déclaré
 
 f = a*x + b ! quelque part dans une fonction on doit assigner une valeur à f
 
 END FUNCTION f
Les argument d'une subroutine peuvent être de plusieurs types
  • argument sortant : integer,intent(out)::p1
  • argument entrant : integer,intent(in)::p2
  • argument entrant/sortant : integer,intent(inout)::p3
Les arguments entrants ne peuvent pas être modifiés dans la subroutine. Une subroutine doit assigner une valeur à un argument sortant.


Comment récupérer un paramètre/argument en ligne de commande ?
auteur : Germain Salvato-Vallverdu
Quand on travaille dans un terminal il arrive souvant qu'on rajoute à la suite d'un programme des paramètres. par exemple : mon_programme.x p1 p2 p3. Pour récupérer p1, p2 et p3 on utilise la subroutine getarg.
Utilisation de la subroutine getarg
call getarg( entier , chaîne de caractère)
L'entier correspond à la place de l'argument. Par exemple, dans notre cas, 1 correspond à p1, 2 à p2 et 3 à p3. La valeur 0 permet de récupérer le nom du programme. Ceci peut être mis à profit pour si l'exécutable est enregistré sous des noms différents afin d'avoir une exécution différente selon le nom du programme. Les paramètres p1, p2 ou p3 sont enregistrés dans une variable de type chaîne de caractères. Voici un exemple d'utilisation :
Exemple d'utilisation de getarg
 PROGRAM test_getarg
 implicit none
 integer::i,p1,p2,p3
 integer,dimension(3)::p
 character(len=10)::parm,nom

 ! on récupère le nom du programme
 call getarg(0,nom)

 ! on récupère les valeurs des paramètres
 call getarg(1,parm)
 read(parm,*)p1

 call getarg(2,parm)
 read(parm,*)p2

 call getarg(3,parm)
 read(parm,*)p3

 ! on peut faire une boucle
 Do i=1,3
    call getarg(i,parm)
    read(parm,*)p(i)
 Enddo

 END PROGRAM test_getarg

Qu'est ce qu'une variable locale/globale ?
auteur : Germain Salvato-Vallverdu
Une variable est une zone mémoire à laquelle on associe un nom pour pouvoir écire ou lire ce qu'elle contient. Lorsqu'on utilise des sous programmes il faut savoir si les variables qu'on utilise sont accessibles par tous les sous programmes (variables globales) ou juste dans le programme ou sous programme dans lequel elles sont déclarées.

En fortran toutes les variables déclarées au début d'un programme principal, d'une fonction ou d'une subroutine sont des variables locales. Ainsi si l'on déclare un entier i dans 3 sous programme, ces 3 variables i seront associées à 3 zones mémoires différentes et indépendantes.

Pour utiliser des variables globales, communes à plusieurs sous programmes, on utilise les common (fortran77) ou des module (fortran90).


Comment passer des variables en arguments vers/depuis une subroutine ?
auteur : Germain Salvato-Vallverdu
La méthode la plus simple pour qu'une subroutine et son programme appelant se passent des variables est de les mettre comme arguments de la subroutine. Il faut ensuite préciser s'ils sont entrant (ils viennent du programme appelant et ne doivent pas être modifié), sortant (ils viennent de la subroutine vers le programme appelant et doivent être assignés) ou les deux.
Exemple d'arguments
 PROGRAM test_arg
 implicit none
 integer::a,b,c

 a = 2
 c = 1

 call sub(a,b,c)

 END PROGRAM test_arg

! * * * * * * * 

 SUBROUTINE sub(a,b,c)
 ! il n'est pas nécessaire que les arguments aient le même nom, seule la position est importante
 ! mais ça facilite la lecture du programme
 implicit none
 integer,intent(in)::a       ! a n'est pas modifiable
 integer,intent(out)::b      ! b doit être assigné
 integer,intent(inout)::c    ! c peut être modifié

 b = a + c

 c = c + 1

 END SUBROUTINE sub
Il n'est pas obligatoire de préciser l'intent, cela peut cependant éviter certaines erreurs et facilite la lecture du programme.


Comment utiliser un common pour partager des variables entre sous programmes (F77) ?
auteur : Germain Salvato-Vallverdu
Le common permet de déclarer un zone mémoire commune dans laquelle seront enregistrées des variables. Elles seront accessibles par tous les sous programmes dans lesquels le common est déclaré. Reprenons l'exemple utilisé par les arguments pour comparer.
Utilisation d'un common pour transferer des variables
! * * * *
! syntaxe d'un common
 common /nom de la zone commune/ liste des variables
! * * * * 

 PROGRAM test_arg
 implicit none
 integer::a,b,c
 common /arg/ a,b,c  ! je déclare le common

 a = 2
 c = 1

 call sub

 END PROGRAM test_arg

! * * * * * * * 

 SUBROUTINE sub
 implicit none
 integer::a,b,c
 common /arg/ a,b,c ! j'utilise le common 

 b = a + c

 c = c + 1

 END SUBROUTINE sub
Il n'est plus nécessaire de donner les variables a,b et c en argument de la subroutine sub car elles sont accessibles par l'intermédiaire du common.

Dans ce cas les variables de la zone commune sont toutes modifiables par la subroutine, pour préciser un intent il faut utiliser les paramètres.

Pour ne pas avoir à reécrire dans chaque sous programme le common, il était courant d'inclure un fichier qui contenait les variables du common. Ceci avait également l'avantage de ne pas avoir à modifier tous les common dans tous les sous programmes à chaque modification. Voici un exemple :
Utilisation de include
 PROGRAM test_arg
 implicit none
 include "arg"

 a = 2
 c = 1

 call sub

 END PROGRAM test_arg

! * * * * * * * 

 SUBROUTINE sub
 implicit none
 include "arg"

 b = a + c

 c = c + 1

 END SUBROUTINE sub

! * * * * * * * * * * * * * * * 
!contenu du fichier arg
 integer::a,b,c
 common /arg/ a,b,c 

Comment utiliser un module pour partager des variables entre sous programmes (F90) ?
auteur : Germain Salvato-Vallverdu
Les modules sont la grande nouveauté du fortran 90 et apporte au fortran un soupçon de programmation orientée objet. L'utilisation des modules pour partager des variables entre des sous programmes n'est qu'une infime partie de ce qu'ils apportent. Dans ce cas, leur utilisation est similaire à celle du common. On va créer un module, dans lequel seront déclarées des variables qui seront disponnibles dans tous les sous programmes qui utilisent le module.
Utilisation d'un common pour transferer des variables
 MODULE arg
 implicit none
 integer::a,b,c
 END MODULE arg

! * * * * * * * 

 PROGRAM test_arg
 USE arg
 implicit none

 a = 2
 c = 1

 call sub

 END PROGRAM test_arg

! * * * * * * * 

 SUBROUTINE sub
 USE arg
 implicit none

 b = a + c

 c = c + 1

 END SUBROUTINE sub
L'utilisation d'un module apporte cependant une contrainte. Ils doivent être compilés avant le programme principal. Plusieurs solutions sont possibles :

  • Lors de la compilation placer le nom du module en premier, par exemple : ifort module.f90 program.f90
  • Si le programme est court et que tous les sous programmes et modules sont dans un même fichier, placer les modules en premier, en tête du fichier dans l'ordre qu'ils apparaissent. Puis compiler simplement le fichier comme un programme normal.
  • Compilez à l'avance vos modules (s'arréter à la compilation, création de l'objet). Puis lors de la compilation du programme ajouter les .o des modules.
Pour les compilateurs ifort, g95 ou gfortran, la compilation (création de l'objet) se fait en ajoutant l'option -c.

Il est possible de n'utiliser qu'une partie d'un module avec l'instruction only. On va ainsi sélectionner les variables qui seront accessibles et celles qui ne le seront pas. Voici un exemple :
Utilisation de only
 MODULE arg
 implicit none
 integer::a,b,c
 double precision::x
 END MODULE arg

! * * * * * * * 

 PROGRAM test_arg
 USE arg, only : a,c      ! seuls a et c sont utiles
 implicit none

 a = 2
 c = 1

 call sub

 END PROGRAM test_arg

! * * * * * * * 

 SUBROUTINE sub
 USE arg, only : a,b,c    ! seuls a b et c sont utiles
 implicit none

 b = a + c

 c = c + 1

 END SUBROUTINE sub


Consultez les autres F.A.Q's


Valid XHTML 1.1!Valid CSS!

Copyright © 2008 developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.