resueltos - Diferencia del compilador entre gfortran e ifort(matrices asignables y variables globales)
programas en fortran ejemplos (2)
El código
El siguiente MWE describe lo que quiero usar (tenga en cuenta que no diseñé esto, simplemente estoy tratando de usar el código de alguien, normalmente no usaría variables globales).
PROGRAM MAIN
IMPLICIT NONE
integer :: N
real(8), allocatable :: a(:,:)
N=3
allocate(a(N,3))
a=initialize_array()
CONTAINS
function initialize_array() result(a)
IMPLICIT NONE
real(8) :: a(N,3)
a=1
end function initialize_array
END PROGRAM MAIN
El problema
gfortran da un error que dice Error: Variable ''n'' cannot appear in the expression at (1)
, apuntando al real(8) :: a(N,3)
dentro de la función. En una subrutina funcionaría, ¿cuál podría ser el problema aquí?
La pregunta
¿Por qué ifort (v. 15.0.3) compila esto, mientras que gfortran (v. 4.8.4) no lo hace?
Creo que esto podría ser una explicación, aunque al igual que @VladimirF, no puedo recordar ni encontrar la sección relevante (si la hay) del estándar.
Esta línea
real(8) :: a(N,3)
declara que el resultado de la función es una matriz llamada a
. Esto enmascara la posibilidad de que el mismo nombre se refiera a la matriz a
por asociación de host . El a
dentro del alcance de la función no está en el alcance del programa.
La declaración de una matriz con una dimensión que depende del valor de una variable, como a(N,3)
, requiere que el valor de la variable sea conocido (o al menos cognoscible) en tiempo de compilación. En este caso, al dar n
en el ámbito de host, el parameter
atributo corrige el problema. Aunque no soluciona el pobre diseño, pero las manos de OP parecen estar unidas en ese punto.
No me sorprende que el compilador de Intel compile esto, compila todo tipo de rarezas que sus antepasados han compilado a lo largo de los años por el bien de la compatibilidad con versiones anteriores.
Solo ofrezco esta explicación a medias porque la experiencia me ha enseñado que tan pronto como lo haga uno de los verdaderos expertos de Fortran (IanH, Francescalus, (normalmente) VladimirF) se indignará tanto como para publicar una corrección y todos aprenderemos alguna cosa.
Como ha sido comentado por otros, es difícil decir si algo está claramente permitido: el lenguaje se basa principalmente en reglas y restricciones que dan restricciones.
Por lo tanto, no probaré que el código no es erróneo (y que gfortran no puede rechazarlo), pero veamos qué está pasando.
Primero, me opondré a una cosa dada por High Performance Mark ya que esto es ligeramente relevante:
La declaración de una matriz con una dimensión que depende del valor de una variable, como
a(N,3)
, requiere que el valor de la variable sea conocido (o al menos cognoscible) en tiempo de compilación.
Los límites de una matriz de formas explícitas no siempre deben estar dados por expresiones constantes (lo que definimos vagamente como "conocido / cognoscible en tiempo de compilación"): en algunas circunstancias una matriz de formas explícita puede tener límites dados por variables. Estos se conocen como objetos automáticos (y los límites dados por las expresiones de especificación ).
El resultado de una función es uno de esos lugares donde se permite un objeto automático. En el ejemplo de la pregunta para la declaración del resultado de la función, N
está asociado al host y forma una expresión de especificación.
En lugar de agotar todas las demás restricciones para ver que la declaración de a
verdad está permitida, veamos cómo responde gfortran a pequeñas modificaciones del programa.
Primero, una versión recortada del código de la pregunta a la que se opone gfortran.
integer n
contains
function f() result(g)
real g(n)
end function f
end program
El resultado de la función para f
tiene el nombre g
. No importa lo que llamamos el resultado de la función, entonces, ¿qué sucede cuando lo llamamos f
?
integer n
contains
function f()
real f(n)
end function f
end program
Esto compila felizmente para mí.
¿Qué pasa si enmarcamos este primer bulto en un módulo en lugar de un programa principal?
module mod
integer n
contains
function f() result(g)
real g(n)
end function f
end module
Eso también compila.
La conclusión natural: incluso si gfortran es correcto (hemos omitido alguna restricción bien escondida) para rechazar el primer código, es terriblemente inconsistente al no rechazar a los demás, o la restricción es realmente bastante extraña.