3 votes

Utiliser une précision constante dans le programme principal et les fonctions

Le petit code suivant ne fonctionne pas :

program main  
  implicit none
  integer, parameter :: dp=selected_real_kind(15)
  real(dp) :: v(9)  
  real(dp) :: vector_norm  
  v(:) = 3.14_dp
  print *, 'Vector norm = ', vector_norm(9,v)  
end program main  

function vector_norm(n,vec) result(norm)    
  integer, intent(in) :: n  
  real(dp), intent(in) :: vec(n)
  real(dp) :: norm

  norm = sqrt(sum(vec**2))  
end function vector_norm

dans le programme principal, je crée une sorte de variable dp de sorte que tout soit en double précision et je veux que la fonction vector_norm pour donner un résultat de double précison aussi. Je sais que je peux simplement utiliser double precision function au lieu de function déclaration. L'un d'entre vous peut-il m'aider à résoudre cette erreur tout en continuant à utiliser l'instruction selected_real_kind ?

Note : l'erreur est "Un paramètre de type kind doit être une constante de temps de compilation".

3voto

veryreverie Points 71

Il est pratique de disposer d'un module définissant la précision, puis d'importer ce module dans tout le code afin de s'assurer que la précision est utilisée de manière cohérente. Avec une structure de modules, votre code deviendrait

module precision_module
  implicit none
  integer, parameter :: dp=selected_real_kind(15)
end module

module vector_norm_module
  use precision_module, only : dp
  implicit none
contains
  function vector_norm(n,vec) result(norm)    
    integer, intent(in) :: n  
    real(dp), intent(in) :: vec(n)
    real(dp) :: norm

    norm = sqrt(sum(vec**2))  
  end function vector_norm
end module

program main
  use precision_module, only : dp
  use vector_norm_module, only : vector_norm 
  implicit none
  real(dp) :: v(9)
  v(:) = 3.14_dp
  print *, 'Vector norm = ', vector_norm(9,v)  
end program main

1voto

JAlex Points 827

Cela fonctionne comme prévu. L'astuce consiste à placer la définition de la fonction à l'intérieur de le bloc de code du programme en ajoutant l'élément contains mot-clé. De cette façon, le bloc de code de fonction a accès aux variables et aux paramètres du programme principal.

Code

program FortanConsole1
implicit none

integer, parameter :: dp=selected_real_kind(15)
real(dp) :: v(9)
v(:) = 3.14_dp
print *, 'Vector norm = ', vector_norm(9,v)

contains

function vector_norm(n,vec) result(norm)
integer, intent(in) :: n
real(dp), intent(in) :: vec(n)
real(dp) :: norm

norm = sqrt(sum(vec**2))
end function vector_norm

end program

Il n'est pas nécessaire de définir vector_norm en tant qu'externe ou le type dans le programme principal s'il est défini après l'élément contains mot-clé. Il n'est pas non plus nécessaire de définir un module pour le même effet. Pas besoin non plus de implicit none dans la fonction car elle tombe dans le champ d'application du programme qui a déjà cette déclaration.

BTW, toute fonction après contains peut accéder aux variables/paramètres du programme pour éviter la duplication ( dp dans ce cas).


Mise à jour 1

Suppression de la taille du tableau de vector_norm et a utilisé un tableau de formes supposées (n'importe quelle longueur). Cela simplifie l'API de la fonction.

program FortanConsole1
...
print *, 'Vector norm = ', vector_norm(v)

contains

function vector_norm(vec) result(norm)
real(dp), intent(in) :: vec(:)
...
end function vector_norm
end program FortanConsole1

1voto

francescalus Points 16310

Les éléments qui définissent les paramètres de type et les limites de tableau des objets sont connus sous le nom de expressions de spécification . Dans le code de la question, nous voyons deux expressions de spécification de ce type avec real(dp) :: v(9) le paramètre de type de type dp et la limite du tableau 9 .

Pour une expression de spécification, seule sa valeur compte. Bien que nous ne recommandions pas de telles choses, la primauté de la valeur est la raison pour laquelle real(kind=33) peut être utilisé de manière cohérente tout au long d'un programme. Ainsi, si vous voulez déclarer que deux objets sont du même type, il vous suffit d'utiliser des expressions qui ont la même valeur :

real(kind=33) x1, f1
real(kind=selected_real_kind(15)) x2, f2

x1=f1()
x2=f2()

end

function f1()
  real(kind=33) f1
  f1=1
end function f1

function f2()
  real(kind=selected_real_kind(15)) f2
  f2=2
end function

Ci-dessus sont présentés deux styles d'expressions de spécification : l'utilisation d'une constante littérale ( 33 ) et en référençant de manière appropriée une fonction intrinsèque ( selected_real_kind(15) ). Mais les expressions de spécification peuvent aussi utiliser des objets accessibles dans la portée. Nous disposons de plusieurs techniques pour "partager" des objets entre des portées, et nous pouvons utiliser ces techniques dans nos expressions de spécification.

En effet, les déclarations dans

  function vector_norm(n,vec) result(norm)    
  integer, intent(in) :: n  
  real(dp), intent(in) :: vec(n)

montrent un tel moyen avec association de noms ! L'argument factice n est utilisé dans la spécification de vec Le tableau est lié au tableau de l'utilisateur. Ce site n est l'argument associé à l'argument réel 9 du programme principal : nous avons utilisé une valeur dans le programme principal pour indiquer à la fonction quelque chose sur l'un de ses arguments.

Hélas, l'association d'arguments n'est pas une forme d'association de noms qui est utile pour les paramètres de type type, parce que les paramètres de type doivent être constants (ce que les arguments factices ne sont pas). Nous pouvons utiliser un argument factice pour nous indiquer la longueur d'un objet caractère ou la taille d'un tableau, mais pas le type du caractère.

Nous pouvons utiliser d'autres formes d'association de noms pour partager des constantes entre une portée (comme le programme principal) et une autre (une fonction).

Nous pouvons utiliser hôte association o utiliser association . Je ne vais pas recréer les exemples de code de chacune de ces réponses, mais j'espère que cette réponse motive pourquoi ces deux approches fonctionnent. Aucune des deux approches n'est nécessairement meilleure que l'autre, mais une fois que vous aurez compris ce qu'elles visent à faire en termes de portée, vous pourrez comparer leur adéquation sur d'autres aspects.

Notez que la fonction vector_norm de la première réponse liée utilise elle-même l'association use et host pour le paramètre kind (et l'association argument pour le paramètre array bound).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X