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

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Fortran Discussion :

Fonction qui renvoie un vecteur


Sujet :

Fortran

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite
    Avatar de Ladgalen
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Novembre 2007
    Messages
    466
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Enseignant Chercheur

    Informations forums :
    Inscription : Novembre 2007
    Messages : 466
    Par défaut Fonction qui renvoie un vecteur
    Bonjour

    D'après ce post il semble qu'en fortran 90 il soit possible d'écrire une function qui renvoi un vecteur. J'ai écris cette fonction qui me renvoit une erreur que je n'arrive pas à comprendre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    program test
      implicit none
      integer :: k
      double precision, dimension(3) :: vect_product
      double precision, dimension(3) :: u,v,w
     
      u(:) = (/ 1.d0, 0.d0, 0.d0 /)
      v(:) = (/ 0.d0, 1.d0, 0.d0 /)
      w(:) = (/ 0.d0, 0.d0, 0.d0 /)
     
      w(:) = vect_product(u(:),v(:))
     
      write(*,"(3F5.2)")(w(k),k=1,3)
     
    end program test
     
    !* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
     
    function vect_product( u, v)
        ! calcule le produit vectoriel ( u x v )
        ! retourne un vecteur norme
     
        ! la fonction :
        double precision, dimension(3)             :: vect_product
        ! arguments :
        double precision, dimension(3), intent(in) :: u, v
        ! locales :
        double precision, dimension(3)             :: w
        double precision                           :: norme
     
        w(1) = u(2)*v(3) - u(3)*v(2)
        w(2) = u(3)*v(1) - u(1)*v(3)
        w(3) = u(1)*v(2) - u(2)*v(1)
     
        norme = sqrt( sum( (w(:))**2 ) )
     
        if( norme > 1.d-15 ) then
          vect_product(:) = w(:) / norme
        else
          vect_product(:) = 0.d0
          write(*,"('ATTENTION : norme du produit vectoriel nulle')")
        end if
     
        return
      end function vect_product
    Voici l'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     In file test.f90:11
     
      w(:) = vect_product(u(:),v(:))
                         1
    Warning: Extension: REAL array index at (1)
     In file test.f90:11
     
      w(:) = vect_product(u(:),v(:))
                              1
    Warning: Extension: REAL array index at (1)
     In file test.f90:11
     
      w(:) = vect_product(u(:),v(:))
                        1
    Error: Rank mismatch in array reference at (1) (2/1)
    Merci pour votre aide

  2. #2
    Rédacteur

    Homme Profil pro
    Comme retraité, des masses
    Inscrit en
    Avril 2007
    Messages
    2 978
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : Suisse

    Informations professionnelles :
    Activité : Comme retraité, des masses
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 2 978
    Par défaut
    Salut!
    Je ne possède pas de copie de la norme Fortran 90 ou 95. En revanche, le manuel de référence de mon Compaq Fortran affirme d'une part qu'il est compatible Fortran 90 ou 95 et d'autre part qu'une fonction ne peut retourner qu'une seule valeur.
    Jean-Marc Blanc

  3. #3
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Par défaut
    Il n'y a pas de problème à retourner un vecteur en F90. Le problème de ton programme est simplement qu'il ne voie pas la fonction. Tu as besoin d'une interface.

    Je n'ai pas le temps de tester, mais le programme suivant devrait fonctionner :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
    program test
      implicit none
      integer :: k
    !  double precision, dimension(3) :: vect_product
      double precision, dimension(3) :: u,v,w
     
      u(:) = (/ 1.d0, 0.d0, 0.d0 /)
      v(:) = (/ 0.d0, 1.d0, 0.d0 /)
      w(:) = (/ 0.d0, 0.d0, 0.d0 /)
     
      w(:) = vect_product(u(:),v(:))
     
      write(*,"(3F5.2)")(w(k),k=1,3)
     
    !end program test
    contains
    !* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
     
    function vect_product( u, v)
        ! calcule le produit vectoriel ( u x v )
        ! retourne un vecteur norme
     
        ! la fonction :
        double precision, dimension(3)             :: vect_product
        ! arguments :
        double precision, dimension(3), intent(in) :: u, v
        ! locales :
        double precision, dimension(3)             :: w
        double precision                           :: norme
     
        w(1) = u(2)*v(3) - u(3)*v(2)
        w(2) = u(3)*v(1) - u(1)*v(3)
        w(3) = u(1)*v(2) - u(2)*v(1)
     
        norme = sqrt( sum( (w(:))**2 ) )
     
        if( norme > 1.d-15 ) then
          vect_product(:) = w(:) / norme
        else
          vect_product(:) = 0.d0
          write(*,"('ATTENTION : norme du produit vectoriel nulle')")
        end if
     
        return
      end function vect_product
    end program test
    Évidemment que tu peux alternativement utiliser un bloc interface ou un module plutôt que de placer la fonction en « contains » de ton programme.

  4. #4
    Membre émérite
    Avatar de Ladgalen
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Novembre 2007
    Messages
    466
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Enseignant Chercheur

    Informations forums :
    Inscription : Novembre 2007
    Messages : 466
    Par défaut
    Citation Envoyé par Sylvain Bergeron Voir le message
    Il n'y a pas de problème à retourner un vecteur en F90. Le problème de ton programme est simplement qu'il ne voie pas la fonction. Tu as besoin d'une interface.

    Je n'ai pas le temps de tester, mais le programme suivant devrait fonctionner :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
    program test
      implicit none
      integer :: k
    !  double precision, dimension(3) :: vect_product
      double precision, dimension(3) :: u,v,w
     
      u(:) = (/ 1.d0, 0.d0, 0.d0 /)
      v(:) = (/ 0.d0, 1.d0, 0.d0 /)
      w(:) = (/ 0.d0, 0.d0, 0.d0 /)
     
      w(:) = vect_product(u(:),v(:))
     
      write(*,"(3F5.2)")(w(k),k=1,3)
     
    !end program test
    contains
    !* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
     
    function vect_product( u, v)
        ! calcule le produit vectoriel ( u x v )
        ! retourne un vecteur norme
     
        ! la fonction :
        double precision, dimension(3)             :: vect_product
        ! arguments :
        double precision, dimension(3), intent(in) :: u, v
        ! locales :
        double precision, dimension(3)             :: w
        double precision                           :: norme
     
        w(1) = u(2)*v(3) - u(3)*v(2)
        w(2) = u(3)*v(1) - u(1)*v(3)
        w(3) = u(1)*v(2) - u(2)*v(1)
     
        norme = sqrt( sum( (w(:))**2 ) )
     
        if( norme > 1.d-15 ) then
          vect_product(:) = w(:) / norme
        else
          vect_product(:) = 0.d0
          write(*,"('ATTENTION : norme du produit vectoriel nulle')")
        end if
     
        return
      end function vect_product
    end program test
    Évidemment que tu peux alternativement utiliser un bloc interface ou un module plutôt que de placer la fonction en « contains » de ton programme.
    Bonjour

    Ton code compile et fonctionne correctement. J'ai rajouté une interface (je n'y connais pas grand chose en interface). Le code suivant compile mais plante à l'éxécution :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    program test
      implicit none
      integer :: k
      double precision, dimension(3) :: u,v,w
     
      interface
        function vect_product(u,v)
          double precision,dimension(3),intent(in) :: u,v
        end function vect_product
      end interface
     
      u(:) = (/ 1.d0, 0.d0, 0.d0 /)
      v(:) = (/ 0.d0, 1.d0, 0.d0 /)
      w(:) = (/ 0.d0, 0.d0, 0.d0 /)
     
      w(:) = vect_product(u(:),v(:))
     
      write(*,"(3F5.2)")(w(k),k=1,3)
     
     
    end program test
     
    !* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
     
      function vect_product( u, v)
        ! calcule le produit vectoriel ( u x v )
        ! retourne un vecteur norme
        implicit none
     
        ! la fonction :
        double precision, dimension(3)             :: vect_product
        ! arguments :
        double precision, dimension(3), intent(in) :: u, v
        ! locales :
        double precision, dimension(3)             :: w
        double precision                           :: norme
     
        w(1) = u(2)*v(3) - u(3)*v(2)
        w(2) = u(3)*v(1) - u(1)*v(3)
        w(3) = u(1)*v(2) - u(2)*v(1)
     
        norme = sqrt( sum( (w(:))**2 ) )
     
        if( norme > 1.d-15 ) then
          vect_product(:) = w(:) / norme
        else
          vect_product(:) = 0.d0
          write(*,"('ATTENTION : norme du produit vectoriel nulle')")
        end if
     
        return
      end function vect_product
    Le mesage d'erreur est le suivant :
    Fortran runtime error: Array bound mismatch for dimension 1 of array 'vect_product' (in file 'test.f90', around line 26)

    J'ai compilé avec gfortran.

    En dehors de ce problème je ne comprend pas pourquoi une interface est nécessaire. J'ai l'habitude, pour des petits codes, de mettre toutes les fonctions et subroutines dans un seul fichier les unes après les autres, sans utiliser de module ou d'interface et ça ne pose pas de problème.

    Pourquoi ce problème apparait quand j'ai une fonction qui renvoie un vecteur !

    Merci

  5. #5
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Par défaut
    Citation Envoyé par Ladgalen Voir le message
    Bonjour

    Ton code compile est fonctionne correctement. J'ai rajouté une interface (je n'y connais pas grand chose en interface). Le code suivant compile mais plante à l'éxécution :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    program test
      implicit none
      integer :: k
      double precision, dimension(3) :: u,v,w
     
      interface
        function vect_product(u,v)
          double precision,dimension(3),intent(in) :: u,v
        end function vect_product
      end interface
     
      u(:) = (/ 1.d0, 0.d0, 0.d0 /)
      v(:) = (/ 0.d0, 1.d0, 0.d0 /)
      w(:) = (/ 0.d0, 0.d0, 0.d0 /)
     
      w(:) = vect_product(u(:),v(:))
     
      write(*,"(3F5.2)")(w(k),k=1,3)
     
     
    end program test
     
    !* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
     
      function vect_product( u, v)
        ! calcule le produit vectoriel ( u x v )
        ! retourne un vecteur norme
        implicit none
     
        ! la fonction :
        double precision, dimension(3)             :: vect_product
        ! arguments :
        double precision, dimension(3), intent(in) :: u, v
        ! locales :
        double precision, dimension(3)             :: w
        double precision                           :: norme
     
        w(1) = u(2)*v(3) - u(3)*v(2)
        w(2) = u(3)*v(1) - u(1)*v(3)
        w(3) = u(1)*v(2) - u(2)*v(1)
     
        norme = sqrt( sum( (w(:))**2 ) )
     
        if( norme > 1.d-15 ) then
          vect_product(:) = w(:) / norme
        else
          vect_product(:) = 0.d0
          write(*,"('ATTENTION : norme du produit vectoriel nulle')")
        end if
     
        return
      end function vect_product
    Le mesage d'erreur est le suivant :
    Fortran runtime error: Array bound mismatch for dimension 1 of array 'vect_product' (in file 'test.f90', around line 26)

    J'ai compilé avec gfortran.
    Il manque la ligne :

    double precision, dimension(3) :: vect_product

    dans l'interface. C'est tout.

    Citation Envoyé par Ladgalen Voir le message
    En dehors de ce problème je ne comprend pas pourquoi une interaface est nécessaire. J'ai l'habitude, pour des petits codes, de mettre toutes les fonctions et subroutines dans un seul fichier les unes après les autres, sans utiliser de module ou d'interface et ça ne pose pas de problème.

    Pourquoi ce problème apparait quand j'ai une fonction qui renvoit un vecteur !

    Merci
    Première règle : le concept de fichier source n'existe pas en Fortran. Que tu mettes toutes tes routines dans le même fichier, dans n'importe quel ordre, ou dans des fichiers distincts, n'a aucun effet sur la visibilité que le compilateur a des différentes composantes : le compilateur compile un sous-programme à la fois de façon indépendante.

    Deuxième règle : en absence d'interface, le compilateur ne peut que faire des déductions sur le protocole à utiliser pour invoquer la fonction :
    • Le nom de la fonction (si c'est une fonction) est t'il déclaré ? Sinon, y a t'il une règle implicite ? implicite none ?
    • Du point précédent, le compilateur « connait » maintenant le type de résultat, qui ne peut être que scalaire, puisqu'il n'y a pas moyen de déduire que le résultat est vectoriel.
    • Reste maintenant à déduire le type des arguments. Seule source d'info disponible : les arguments utilisés.
    • Si tu passes un vecteur, l'argument dummy correspondant ne peut être que « assumed-size », soit (*), puisqu'il n'y a pas moyen de savoir si l'argument est déclaré « assumed-shape », soit (:).

    En gros, lorsqu'il n'y a pas d'interface, tu es limité à du protocole F77.

    De ces déductions, rien ne garantie qu'elles seront justes. Il est donc possible qu'il y ait plantage à l'exécution...

  6. #6
    Membre émérite
    Avatar de Ladgalen
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Novembre 2007
    Messages
    466
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Enseignant Chercheur

    Informations forums :
    Inscription : Novembre 2007
    Messages : 466
    Par défaut
    Merci, effectivement ça compile et ça marche comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    program test
      implicit none
      integer :: k
      double precision, dimension(3) :: u,v,w
     
      interface
        function vect_product(u,v)
          double precision, dimension(3)           :: vect_product
          double precision,dimension(3),intent(in) :: u,v
        end function vect_product
      end interface
     
      u(:) = (/ 1.d0, 0.d0, 0.d0 /)
      v(:) = (/ 0.d0, 1.d0, 0.d0 /)
      w(:) = (/ 0.d0, 0.d0, 0.d0 /)
     
      w(:) = vect_product(u(:),v(:))
     
      write(*,"(3F5.2)")(w(k),k=1,3)
     
     
    end program test
     
    !* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
     
      function vect_product( u, v)
        ! calcule le produit vectoriel ( u x v )
        ! retourne un vecteur norme
        implicit none
     
        ! la fonction :
        double precision, dimension(3)             :: vect_product
        ! arguments :
        double precision, dimension(3), intent(in) :: u, v
        ! locales :
        double precision, dimension(3) :: w
        double precision               :: norme
     
        w(1) = u(2)*v(3) - u(3)*v(2)
        w(2) = u(3)*v(1) - u(1)*v(3)
        w(3) = u(1)*v(2) - u(2)*v(1)
     
        norme = sqrt( sum( (w(:))**2 ) )
     
        if( norme > 1.d-15 ) then
          vect_product(:) = w(:) / norme
        else
          vect_product(:) = 0.d0
          write(*,"('ATTENTION : norme du produit vectoriel nulle')")
        end if
     
        return
      end function vect_product
    D'après ce que tu me dis l'interface est un équivalent du prototype en C qui permet au compilateur de vérifier les types et dimensions des arguments lors de l'appel ?

    En conclusion un module devrait donc ressembler à (dis moi si je me trompe) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    module mon_module
      ! variables communes au fonctions et routine du modules
     
      contains
      ! les fonctions et subroutine du modules
     
    end module mon_module
    Edit : En fait dans les modules l'interface ne sert à rien (et donne une erreur de compilation). Quand on place un sous programme dans un module, et que ce module est inclu dans les programmes appelant ces sous programme, l'interface est crée automatiquement. Une interface n'est nécessaire (conseillé en fait, obligatoire uniquement dans certains cas) que s'il s'agit d'un sous programme externe.

  7. #7
    Membre émérite
    Avatar de Ladgalen
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Novembre 2007
    Messages
    466
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Enseignant Chercheur

    Informations forums :
    Inscription : Novembre 2007
    Messages : 466
    Par défaut
    Je pensais naivement qu'un vecteur ou une matrice pouvait entrer dans la définition "ne renvoit qu'une valeur". En fait il faudrait préciser "ne renvoi qu'un scalaire".

    Il semble qu'en fortran 90 il y ait un moyen de bidouillé en définissant une structure qui contient trois réel et déclarer une fonction qui renvois cette strucutre ... je n'ai pas testé.

    De toute façon c'est pas bien grave je ferai une subroutine à la place.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Créer une fonction qui renvoie un vecteur
    Par Avatar36 dans le forum Langage
    Réponses: 22
    Dernier message: 15/05/2014, 12h59
  2. Fonction qui renvoie un vecteur (ou un tableau)
    Par ANOVA dans le forum Macros et VBA Excel
    Réponses: 7
    Dernier message: 13/05/2010, 16h20
  3. Fonction qui renvoie erreur dans mon état
    Par Daniel MOREAU dans le forum Access
    Réponses: 1
    Dernier message: 20/10/2005, 12h40
  4. [bioinfo] fonction qui renvoie chaîne à autre fonction
    Par perlaud dans le forum Bioinformatique
    Réponses: 11
    Dernier message: 16/07/2004, 15h06
  5. [VB6] Comment faire une fonction qui renvoie 2 résultats
    Par tazarine dans le forum VB 6 et antérieur
    Réponses: 10
    Dernier message: 15/01/2004, 00h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo