Buscar..


Tipos de variables implícitas

Cuando Fortran se desarrolló originalmente, la memoria era muy importante. Las variables y los nombres de los procedimientos podrían tener un máximo de 6 caracteres, y las variables a menudo se escribían de forma implícita . Esto significa que la primera letra del nombre de la variable determina su tipo.

  • variables que comienzan con i, j, ..., n son integer
  • todo lo demás (a, b, ..., h, yo, p, ..., z) son real

Programas como los siguientes son aceptables Fortran:

program badbadnotgood
  j = 4
  key = 5 ! only the first letter determines the type
  x = 3.142
  print*, "j = ", j, "key = ", key, "x = ", x
end program badbadnotgood

Incluso puede definir sus propias reglas implícitas con la declaración implicit :

! all variables are real by default 
implicit real (a-z)

o

! variables starting with x, y, z are complex
! variables starting with c, s are character with length of 4 bytes
! and all other letters have their default implicit type
implicit complex (x,y,z), character*4 (c,s) 

La tipificación implícita ya no se considera la mejor práctica. Es muy fácil cometer un error al utilizar la escritura implícita, ya que los errores tipográficos pueden pasar desapercibidos, por ejemplo,

program oops
  real :: somelongandcomplicatedname

  ...

  call expensive_subroutine(somelongandcomplEcatedname)
end program oops

Este programa estará felizmente ejecutado y hará lo incorrecto.


Para desactivar la escritura implícita, se puede usar la instrucción implicit none .

program much_better
  implicit none
  integer :: j = 4
  real :: x = 3.142
  print*, "j = ", j, "x = ", x
end program much_better

Si no hubiéramos usado implicit none en el programa oops arriba, el compilador se habría dado cuenta de inmediato y produjo un error.

Aritmética si declaración

La instrucción aritmética if permite usar tres ramas dependiendo del resultado de una expresión aritmética

if (arith_expr) label1, label2, label3

Esta instrucción if transfiere el flujo de control a una de las etiquetas de un código. Si el resultado de arith_expr es negativo, label1 está involucrado, si el resultado es cero, se usa label2 y si el resultado es positivo, se aplica la última label3 . Aritmética if requiere las tres etiquetas, pero permite la reutilización de las etiquetas, por lo tanto, esta declaración se puede simplificar a una rama dos if .

Ejemplos:

if (N * N - N / 2) 130, 140, 130

if (X) 100, 110, 120

Ahora esta función es obsoleta con la misma funcionalidad ofrecida por el if declaración y if-else construcción. Por ejemplo, el fragmento.

    if (X) 100, 110, 120
100 print*, "Negative"
    goto 200
110 print*, "Zero"
    goto 200
120 print*, "Positive"
200 continue

puede ser escrito como la construcción if-else

if (X<0) then
  print*, "Negative"
else if (X==0) then
  print*, "Zero"
else
  print*, "Positive"
end if

Un sustituto if de

    if (X) 100, 100, 200
100 print *, "Negative or zero"
200 continue

tal vez

if (X<=0) print*, "Negative or zero"

Construcciones de OD no en bloque

La no-bloque do construir parece

    integer i
    do 100, i=1, 5
100 print *, i

Es decir, donde la instrucción de terminación etiquetada no es una instrucción de continue . Hay varias restricciones en la declaración que pueden usarse como la declaración de terminación y todo es generalmente muy confuso.

Dicha construcción no de bloque se puede reescribir en forma de bloque como

    integer i
    do 100 i=1,5
      print *, i
100 continue

o mejor, usando una sentencia de end do terminación,

integer i
do i=1,5
  print *, i
end do

Retorno alternativo

El rendimiento alternativo es una facilidad para controlar el flujo de ejecución en el retorno desde una subrutina. A menudo se utiliza como una forma de manejo de errores:

real x

call sub(x, 1, *100, *200)
print*, "Success:", x
stop

100 print*, "Negative input value"
stop

200 print*, "Input value too large"
stop

end

subroutine sub(x, i, *, *)
  real, intent(out) :: x
  integer, intent(in) :: i
  if (i<0) return 1
  if (i>10) return 2
  x = i
end subroutine

El retorno alternativo está marcado por los argumentos * en la lista de argumentos ficticios de subrutina.

En la declaración de call anterior *100 y *200 refieren a las declaraciones etiquetadas 100 y 200 respectivamente.

En la subrutina, las declaraciones de return correspondientes a la devolución alternativa tienen un número. Este número no es un valor de retorno, pero denota la etiqueta proporcionada a la cual se pasa la ejecución en el retorno. En este caso, el return 1 pasa la ejecución a la declaración etiquetada 100 y el return 2 ejecución pasa a la declaración etiquetada 200 . Una declaración de return sin adornos, o la finalización de la ejecución de subrutina sin una declaración de return , la ejecución de Passess inmediatamente después de la instrucción de llamada.

La sintaxis alternativa de retorno es muy diferente de otras formas de asociación de argumentos y la instalación introduce un control de flujo contrario a los gustos modernos. El control de flujo más agradable se puede administrar con la devolución de un código de "estado" entero.

real x
integer status

call sub(x, 1, status)
select case (status)
case (0)
  print*, "Success:", x
case (1)
  print*, "Negative input value"
case (2)
  print*, "Input value too large"
end select

end

subroutine sub(x, i, status)
  real, intent(out) :: x
  integer, intent(in) :: i
  integer, intent(out) :: status

  status = 0

  if (i<0) then
    status = 1
  else if (i>10)
    status = 2
  else
    x = i
  end if

end subroutine

Forma de fuente fija

Fortran originalmente fue diseñado para un formato de formato fijo basado en una tarjeta perforada de 80 columnas:

introduzca la descripción de la imagen aquí

Sí: esta es una línea del propio código del autor.

Estos fueron creados en una máquina perforadora de tarjetas, muy similar a esto:

introduzca la descripción de la imagen aquí

Las imágenes son fotografías originales del autor.

El formato, como se muestra en la tarjeta de muestra ilustrada, tenía las primeras cinco columnas reservadas para las etiquetas de estados de cuenta. La primera columna se usó para denotar los comentarios mediante una letra C. La sexta columna se usó para denotar una continuación de la declaración (insertando cualquier carácter que no sea un cero '0'). Las últimas 8 columnas se usaron para la identificación y secuenciación de las tarjetas, ¡lo cual fue muy valioso si dejaste caer el mazo de cartas en el suelo! La codificación de caracteres para tarjetas perforadas tenía solo un conjunto limitado de caracteres y solo estaba en mayúsculas. Como resultado, los programas de Fortran se parecían a esto:

       DIMENSION A(10)                                                    00000001
C THIS IS A COMMENT STATEMENT TO EXPLAIN THIS EXAMPLE PROGRAM             00000002
       WRITE (6,100)                                                      00000003
 100   FORMAT(169HTHIS IS A RATHER LONG STRING BEING OUTPUT WHICH GOES OVE00000004
      1R MORE THAN ONE LINE, AND USES THE STATEMENT CONTINUATION MARKER IN00000005
      2COLUMN 6, AND ALSO USES HOLLERITH STRING FORMAT)                   00000006
       STOP                                                               00000007
       END                                                                00000008

El carácter de espacio también se ignoró en todas partes, excepto dentro de una constante de carácter Hollerith (como se muestra arriba). Esto significaba que los espacios podían aparecer dentro de palabras y constantes reservadas, o se podían perder por completo. Esto tuvo el efecto secundario de algunas afirmaciones bastante engañosas como:

       DO 1 I = 1.0

es una asignación a la variable DO1I mientras que:

       DO1I = 1,0 

es en realidad un bucle de DO en la variable I


Fortran moderno ahora no requiere esta forma fija de entrada y permite la forma libre usando cualquier columna. Los comentarios ahora están indicados por un ! que también se puede añadir a una línea de declaración. Los espacios ahora no están permitidos en ningún lugar y deben usarse como separadores, como en la mayoría de los otros idiomas. El programa anterior se podría escribir en Fortran moderno como:

! This is a comment statement to explain this example program
Print *,"THIS IS A RATHER LONG STRING BEING OUTPUT WHICH no longer GOES OVER MORE THAN ONE LINE, AND does not need to USE THE STATEMENT CONTINUATION MARKER IN COLUMN 6, or the HOLLERITH STRING FORMAT"

Aunque la continuación de estilo antiguo ya no se usa, el ejemplo anterior ilustra que todavía se producirán declaraciones muy largas. Modern Fortran usa un símbolo & al final y al comienzo de la continuación. Por ejemplo, podríamos escribir lo anterior en una forma más legible:

! This is a comment statement to explain this example program
Print *,"THIS IS A RATHER LONG STRING BEING OUTPUT WHICH still &
         &GOES OVER MORE THAN ONE LINE, AND does need to USE THE STATEMENT &
         &CONTINUATION notation"

Bloques comunes

En las primeras formas de Fortran, el único mecanismo para crear un almacén de variables global visible desde subrutinas y funciones es usar el mecanismo de bloque COMMON . Esto permitió que las secuencias de variables fueran nombres y se compartieran en común.

Además de los bloques comunes con nombre, también puede haber un bloque común en blanco (sin nombre).

Un bloque común en blanco podría ser declarado como

common i, j

mientras que las variables bloque nombradas podrían ser declaradas como

common /variables/ i, j

Como ejemplo completo, podríamos imaginar una tienda de almacenamiento dinámico utilizada por rutinas que pueden agregar y eliminar valores:

       PROGRAM STACKING
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       ICOUNT = 0
       READ *, IVAL
       CALL PUSH(IVAL)
       CALL POP(IVAL)
       END

       SUBROUTINE PUSH(IVAL)
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       ICOUNT = ICOUNT + 1
       ISTACK(ICOUNT) = IVAL
       RETURN
       END

       SUBROUTINE POP(IVAL)
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       IVAL = ISTACK(ICOUNT)
       ICOUNT = ICOUNT - 1
       RETURN
       END

Las declaraciones comunes se pueden usar para declarar implícitamente el tipo de una variable y para especificar el atributo de dimension . Este comportamiento solo es a menudo una fuente suficiente de confusión. Además, la asociación de almacenamiento implícita y los requisitos para definiciones repetidas en las unidades del programa hacen que el uso de bloques comunes sea propenso a errores.

Finalmente, los bloques comunes están muy restringidos en los objetos que contienen. Por ejemplo, una matriz en un bloque común debe ser de tamaño explícito; objetos asignables no pueden ocurrir; Los tipos derivados no deben tener inicialización por defecto.

En Fortran moderno, este uso compartido de variables se puede manejar mediante el uso de módulos . El ejemplo anterior se puede escribir como:

module heap
  implicit none
  ! In Fortran 2008 all module variables are implicitly saved
  integer, save :: count = 0
  integer, save :: stack(1023)
end module heap

program stacking
  implicit none
  integer val
  read *, val
  call push(val)
  call pop(val)

contains
  subroutine push(val)
    use heap, only : count, stack
    integer val
    count = count + 1
    stack(count) = val
  end subroutine push

  subroutine pop(val)
    use heap, only : count, stack
    integer val
    val = stack(count)
    count = count - 1
  end subroutine pop
end program stacking

Los bloques comunes nombrados y en blanco tienen comportamientos ligeramente diferentes. De nota:

  • Los objetos en bloques comunes nombrados pueden definirse inicialmente; Los objetos en blanco no serán comunes.
  • los objetos en bloques comunes en blanco se comportan como si el bloque común tuviera el atributo de save ; los objetos en bloques comunes nombrados sin el atributo de save pueden volverse indefinidos cuando el bloque no está en el alcance de una unidad de programa activa

Este último punto puede contrastarse con el comportamiento de las variables del módulo en el código moderno. Todas las variables de módulo en Fortran 2008 se guardan implícitamente y no se vuelven indefinidas cuando el módulo queda fuera del alcance. Antes de que las variables del módulo Fortran 2008, como las variables en bloques comunes con nombre, también se volvieran indefinidas cuando el módulo quedaba fuera del alcance.

Asignado GOTO

El GOTO asignado utiliza una variable entera a la que se asigna una etiqueta de declaración utilizando la instrucción ASSIGN.

100 CONTINUE

...

ASSIGN 100 TO ILABEL

...


GOTO ILABEL

El GOTO asignado es obsolescente en Fortran 90 y se elimina en Fortran 95 y posteriores. Se puede evitar en el código moderno utilizando procedimientos, procedimientos internos, indicadores de procedimientos y otras características.

GOTO computado

El GOTO computado permite la bifurcación del programa según el valor de una expresión entera.

GOTO (label_1, label_2,... label_n) scalar-integer-expression

Si scalar-integer-expression es igual a 1, el programa continúa en la etiqueta label_1 , si es igual a 2, va a label_2 y así sucesivamente. Si es menos de 1 o mayor que n programa continúa en la siguiente línea.

Ejemplo:

ivar = 2

...

GOTO (10, 20, 30, 40) ivar

saltará a la etiqueta de declaración 20.

Esta forma de goto es obsolescente en Fortran 95 y versiones posteriores, siendo reemplazada por el constructo de select case .

Especificadores de formato asignado

Antes de Fortran 95 era posible usar formatos asignados para entrada o salida. Considerar

integer i, fmt
read *, i

assign 100 to fmt
if (i<100000) assign 200 to fmt

print fmt, i

100 format ("This is a big number", I10)
200 format ("This is a small number", I6)

end

La declaración de assign asigna una etiqueta de declaración a una variable entera. Esta variable entera se usa más tarde como el especificador de formato en la declaración de print .

Dicha asignación de especificador de formato se eliminó en Fortran 95. En su lugar, un código más moderno puede usar alguna otra forma de control de flujo de ejecución

integer i
read *, i

if (i<100000) then
  print 100, i
else
  print 200, i
end if

100 format ("This is a big number", I10)
200 format ("This is a small number", I6)

end

o se puede usar una variable de carácter como el especificador de formato

character(29), target :: big_fmt='("This is a big number", I10)'
character(30), target :: small_fmt='("This is a small number", I6)'
character(:), pointer :: fmt

integer i
read *, i

fmt=>big_fmt
if (i<100000) fmt=>small_fmt

print fmt, i

end

Funciones de sentencias

Considerar el programa

implicit none
integer f, i
f(i)=i

print *, f(1)
end

Aquí f es una función de declaración. Tiene un tipo de resultado de entero, tomando un argumento ficticio de entero. 1

Dicha función de declaración existe dentro del alcance en el que se define. En particular, tiene acceso a variables y constantes con nombre accesibles en ese ámbito.

Sin embargo, las funciones de declaración están sujetas a muchas restricciones y son potencialmente confusas (mirando a simple vista como una instrucción de asignación de elementos de matriz). Las restricciones importantes son:

  • El resultado de la función y los argumentos ficticios deben ser escalares.
  • Los argumentos ficticios están en el mismo ámbito que la función.
  • funciones de declaración no tienen variables locales
  • Las funciones de sentencias no se pueden pasar como argumentos reales.

Los beneficios principales de las funciones de sentencias son repetidos por las funciones internas.

implicit none

print *, f(1)

contains

  integer function f(i)
    integer i
    f = i
  end function

end

Las funciones internas no están sujetas a las restricciones mencionadas anteriormente, aunque quizás vale la pena señalar que un subprograma interno puede no contener un subprograma interno adicional (pero puede contener una función de declaración).

Las funciones internas tienen su propio alcance, pero también tienen una asociación de host disponible.


1 En los ejemplos de código antiguo anterior, no sería extraño ver que los argumentos ficticios de una función de declaración se escriben de forma implícita, incluso si el resultado tiene un tipo explícito.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow