Guión Fortran
Guión Fortran
Guión Fortran
Fortran 90
Dpto. de Matem
atica Aplicada a la
Ingenier
a Aeroespacial
Índice general
1. Algoritmos y programas 1
1.1. Arquitectura de un ordenador . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2. Introducción a la programación . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.1. Análisis del problema . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.2. Diseño y verificación del algoritmo . . . . . . . . . . . . . . . . . . 4
1.2.3. Codificación del algoritmo en el programa . . . . . . . . . . . . . . 6
1.2.4. Ejecución y verificación del programa . . . . . . . . . . . . . . . . . 7
1.2.5. Documentación de un programa . . . . . . . . . . . . . . . . . . . . 7
2. Bases de Fortran 9
2.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2. Notación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3. Normas de escritura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.4. Estructura general de un programa . . . . . . . . . . . . . . . . . . . . . . 11
2.5. Salidas de un programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3. Tipos de datos 15
3.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.2. Tipos de datos intrı́nsecos . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.2.1. Datos enteros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.2.2. Datos reales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2.3. Datos complejos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2.4. Datos lógicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.2.5. Datos caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.3. Tipos de datos derivados . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.4. Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.5. Parámetros dentro de un programa . . . . . . . . . . . . . . . . . . . . . . 32
3.6. La sentencia implicit none . . . . . . . . . . . . . . . . . . . . . . . . . . 32
i
3.7. Definición en la lı́nea de declaración . . . . . . . . . . . . . . . . . . . . . . 34
3.8. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4. Operaciones básicas 37
4.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.2. Expresiones aritméticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.3. Expresiones relacionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.4. Expresiones lógicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.5. Operaciones con caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.6. Operaciones con arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
4.7. Definición en la lı́nea de declaración . . . . . . . . . . . . . . . . . . . . . . 47
5. Control de flujo 49
5.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.2. Estructura condicional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.2.1. Estructura condicional simple . . . . . . . . . . . . . . . . . . . . . 51
5.2.2. Estructura condicional doble . . . . . . . . . . . . . . . . . . . . . . 52
5.2.3. Estructura condicional múltiple . . . . . . . . . . . . . . . . . . . . 53
5.3. Estructura iterativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
5.3.1. Bucle controlado por un contador . . . . . . . . . . . . . . . . . . . 58
5.3.2. Bucle controlado por una expresión lógica . . . . . . . . . . . . . . 61
5.3.3. Sentencia cycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
6. Funciones intrı́nsecas 65
6.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
6.2. Funciones intrı́nsecas con datos numéricos . . . . . . . . . . . . . . . . . . 66
6.2.1. Funciones de conversión . . . . . . . . . . . . . . . . . . . . . . . . 67
6.2.2. Funciones de truncamiento y redondeo . . . . . . . . . . . . . . . . 68
6.2.3. Funciones matemáticas . . . . . . . . . . . . . . . . . . . . . . . . . 69
6.3. Funciones intrı́nsecas especı́ficas de caracteres . . . . . . . . . . . . . . . . 70
6.3.1. Funciones de conversión . . . . . . . . . . . . . . . . . . . . . . . . 70
6.3.2. Funciones de manipulación . . . . . . . . . . . . . . . . . . . . . . . 71
6.4. Funciones intrı́nsecas especı́ficas de arrays . . . . . . . . . . . . . . . . . . 74
6.4.1. Funciones de cálculo . . . . . . . . . . . . . . . . . . . . . . . . . . 74
6.4.2. Funciones de búsqueda . . . . . . . . . . . . . . . . . . . . . . . . . 76
6.4.3. Funciones de dimensiones . . . . . . . . . . . . . . . . . . . . . . . 79
ii
7. Objetos compuestos 83
7.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
7.2. Datos array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
7.2.1. Secciones de un array . . . . . . . . . . . . . . . . . . . . . . . . . . 84
7.2.2. Asignación dinámica de memoria . . . . . . . . . . . . . . . . . . . 87
7.2.3. Arrays de tamaño cero . . . . . . . . . . . . . . . . . . . . . . . . . 90
7.3. Datos de tipo derivado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
7.3.1. Componente de tipo array . . . . . . . . . . . . . . . . . . . . . . . 92
7.3.2. Componente de tipo estructura . . . . . . . . . . . . . . . . . . . . 94
iii
9.5. Array como resultado de una función . . . . . . . . . . . . . . . . . . . . . 139
9.6. Variables locales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
9.7. Tipos de subprogramas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
9.8. Subprograma interno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
9.9. Subprograma module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
B. Bibliografı́a 157
iv
Algoritmos
1 y
programas
Índice
1.1. Arquitectura de un ordenador . . . . . . . . . . . . . . . . . . . 2
1.2. Introducción a la programación . . . . . . . . . . . . . . . . . . 3
1.2.1. Análisis del problema . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.2. Diseño y verificación del algoritmo . . . . . . . . . . . . . . . . 4
1.2.3. Codificación del algoritmo en el programa . . . . . . . . . . . . 6
1.2.4. Ejecución y verificación del programa . . . . . . . . . . . . . . 7
1.2.5. Documentación de un programa . . . . . . . . . . . . . . . . . 7
1
2 1.1 Arquitectura de un ordenador
• Memoria Solo de Lectura (ROM, Read Only Memory), de la que solo se puede leer.
La información reside en ella de forma permanente, aunque no exista suministro de
energı́a eléctrica. Esta memoria está reservada para instrucciones de arranque del
ordenador y otra información crı́tica.
Los dispositivos I/O son aquellos que aceptan datos para ser procesados (Entrada)
o presentan los resultados del procesamiento (Salida).
Unidad de Memoria
2.- Debe estar definido, si se sigue un mismo algoritmo dos veces se debe obtener idéntico
resultado.
Análisis
del problema
-
?
-
? ?
Verificación Ejecución
manual
del algoritmo del programa
Verificación
del programa
Documentación
o bien
Problema
Problema
area rectangulo
area =
base altura base × altura area
reglas de sintaxis propias de cada lenguaje. El algoritmo, una vez codificado, se denomina
programa.
Existen dos fases previas que debe realizar el ordenador antes de la ejecución del
programa
9
10 2.1 Introducción
2.1. Introducción
El objetivo principal de la programación tal y como debe entenderse en un ámbito
cientı́fico e ingenieril, es la resolución numérica a través de un ordenador del problema
planteado. En este sentido Fortran constituye un lenguaje de programación estructurado
y de alto nivel orientado desde sus orı́genes, hace más de 40 años, a la resolución de
problemas cientı́ficos. De hecho su nombre no es más que la contracción de FORmula
TRANslation.
La primera versión de Fortran surgió a mediados de los sesenta como un intento
de unificar diferentes dialectos creados con el fin de conseguir un lenguaje intermedio
entre el lenguaje matemático y el lenguaje máquina (único conocido hasta esa fecha).
El resultado final, conocido como Fortran77, constituyó el paradigma de programación
durante muchos años, de ahı́ que muchas librerı́as estándar matemáticas como IMSL
(International Mathematics and Statistics Library) o NAG (Numerical Algorithmis Group)
usadas por cientı́ficos e ingenieros estuviesen escritas en esa versión. Durante los siguientes
veinte años, aproximadamente, fueron surgiendo otros lenguajes de alto nivel (Pascal, Ada,
C, etc), que abordaban de modo más eficiente ciertos aspectos particulares del cálculo
cientı́fico. Ante la necesidad de que Fortran contemplase estos avances se creó en 1991
una nueva versión, objeto de estudio en el presente curso, denominada Fortran90. Esta
versión se diseñó con el objetivo de incorporar utilidades avanzadas (manipulación de
arrays, tipos de datos definidos por el usuario, asignación dinámica de memoria y manejo
de punteros, etc), manteniendo la compatibilidad con la versión anterior debido a la gran
cantidad de programas que ya estaban escritos en Fortran77.
Posteriormente han surgido dos nuevas versiones Fortran95 y, más recientemente
Fortran 2003. El objetivo de la primera fue eliminar los aspectos considerados obsoletos
de la versión anterior y que, por tanto, no entrarán a formar parte del temario aquı́
expuesto. La última versión, Fortran 2003, aborda aspectos que superan los objetivos del
presente curso.
En este capı́tulo se expondrán las normas generales de escritura de un programa
Fortran, ası́ como la estructura general de dicho programa.
2.2. Notación
A lo largo de todo el texto vamos a utilizar las siguientes convenciones, aunque en
ocasiones, por cuestiones de claridad, no seremos muy rigurosos en su cumplimiento.
program nombre
Dec laración e inicialización de parámetros
Dec laración [ e inicialización ] de variables
sent encias de ejecución
end program nombre
• El nombre del programa no tiene porqué coincidir con el nombre del fichero que lo
contiene. En realidad, nombre es una variable más del programa, por lo que no puede
coincidir con el nombre de ninguna de las variables, constantes o subprogramas
referenciados en el propio programa.
• La frase a imprimir por pantalla es opcional pero, si se utiliza, debe ir entre comillas
(dobles o simples).
durante la implementación del código (división entre cero, fichero de lectura incorrecto,
memoria disponible insuficiente, . . . ). La sentencia stop constituye una manera de con-
trolar estas eventualidades por el propio programador. Aborta la ejecución del programa
y, por medio de una frase suficientemente clara, advierte del problema o error que se ha
producido.
Hay que tener en cuenta ciertas normas de uso extendido
• No hay que abusar del uso de la sentencia stop. Cuando se elabora el algoritmo hay
que intentar dar una solución a los posibles problemas que se pueden producir, sin
necesidad de abortar el programa.
15
16 3.1 Introducción
3.1. Introducción
Los programas, con independencia del lenguaje en que se escriban, están diseñados
para manipular información o datos. En Fortran se pueden definir y manipular varios tipos
de datos. Por ejemplo, se puede asignar el valor 10 a una variable llamada i definida como
entera. En este caso tanto 10 como i son de tipo entero. 10 es un valor constante mientras
que i es una variable que puede modificar su valor a lo largo del programa. Además de
las constantes y variables existe la posibilidad de definir un parámetro, un dato cuyo valor
no cambia durante la ejecución del programa.
Un tipo de dato consiste en
• Un identificador de tipo
• Un conjunto válido de valores
• Una forma de denotar sus valores
• Un conjunto de operaciones válidas
Por ejemplo, para un dato de tipo entero, el identificador de tipo es integer, el
conjunto válido de valores es {..., -3, -2, -1, 0, 1, 2, 3, ...} entre ciertos lı́mi-
tes que dependen de la especie (en inglés, kind) de entero definido y del procesador. Tales
sı́mbolos se denominan constantes literales y cada tipo de dato tiene su propia forma de
expresarlos. Las operaciones válidas entre datos enteros son las tı́picas de la aritmética,
por ejemplo si a la variable i le hemos asignado el valor 10, el resultado de la operación
i + 3 es 13, como era de esperar.
Las propiedades arriba mencionadas están asociadas a todos los tipos de datos de
Fortran y será lo que desarrollaremos a lo largo de este capı́tulo. El propio lenguaje
de Fortran contiene 5 tipos de datos cuya existencia siempre se puede asumir. Estos
tipos se conocen como tipos de datos intrı́nsecos. Tres de ellos son numéricos: integer,
real y complex y dos no numéricos: logical y character. De cada tipo intrı́nseco
existe una especie por defecto (en inglés, default kind) y un número variable de especies
dependientes del ordenador (en adelante, utilizaremos preferentemente el término inglés
kind para referirnos a la especie de un tipo de dato). Cada kind está asociado a un
entero no negativo conocido como parámetro identificador de especie (en inglés, kind type
parameter).
Además de los datos de tipo intrı́nseco, Fortran permite definir nuevos tipos de
datos, denominados tipos derivados, generalmente utilizados para materializar objetos
matemáticos o geométricos (un intervalo, una circunferencia, etc) en un tipo de dato.
1 program main
2 integer :: n
3 n = 20
4 write (* ,*) 5* n
5 n = n + 1
6 end program main
En la figura 3.1 se muestra un ejemplo del uso de una variable entera llamada n. En la
lı́nea 2 se realiza la declaración de la variable. En ese momento, la variable está indefinida,
es decir no tiene un valor asignado. En la lı́nea 3 se asigna a n el valor 20 y pasa a estar
definida. En la lı́nea 4, después de asignarle un valor, ya puede ser referenciada, es decir
podemos utilizar la variable, y por tanto el dato que contiene, para realizar operaciones.
En el momento de la declaración (lı́nea 2), el procesador habilita una zona de me-
moria con la etiqueta n a la que puede acceder a lo largo de la ejecución del programa. En
este paso, la variable está indefinida ya que, aunque la zona de memoria está reservada,
en ella no hay ningún dato almacenado. En la lı́nea 3 se produce una asignación y el
El rango de valores que puede tomar un dato de tipo entero depende, por una
parte, del procesador (32-bit ó 64-bit) y, por otra, del parámetro kind especificado en la
declaración.
program main
integer :: n
n = 20
n = -2
n = 0
n = 9999
end program main
program main
integer ( kind =1) :: i
integer (1) :: j
integer ( kind =4) :: k
integer (4) :: l
integer ( kind =8) :: m
integer (8) :: n
end program main
Las constantes literales asociadas a un dato real pertenecen al conjunto de los núme-
ros reales. Se pueden representar en modo decimal o en modo exponencial. Las constantes
reales negativas deben estar precedidas por el signo menos, sin embargo, en las no nega-
tivas el signo es opcional.
Si un dato real se representa en modo decimal es necesario utilizar el punto decimal
(la coma decimal no está permitida). La representación en modo exponencial consiste en
un número entero o real seguido por la letra e y el número entero como exponente. En
la figura 3.3 se muestran distintas formas de representar la constante real 20.508, todas
ellas equivalentes entre sı́.
program main
real :: x
x = 20.508
x = 205.08 e -1
x = 2.0508 e +1
x = 0.20508 e +2
end program main
El rango de valores que puede tomar un dato de tipo real depende, por una parte, del
procesador (32-bit ó 64-bit) y, por otra, del parámetro kind especificado en la declaración.
Los identificadores de especie más comunes son:
◦ kind = 4 (valor por defecto)
El dato ocupa 4 bytes de memoria y se pueden representar datos reales comprendidos
entre 1.18×10−38 y 3.40×1038 . La precisión en coma flotante es 1.19×10−7 . Cuando
un dato se declara con kind=4 se dice que es un dato en simple precisión.
◦ kind = 8
El dato ocupa 8 bytes de memoria y se pueden representar datos reales comprendidos
entre 2.23 × 10−308 y 1.79 × 10308 . La precisión en coma flotante es 2.22 × 10−16 .
Cuando un dato se declara con kind=8 se dice que es un dato en doble precisión.
◦ kind = 16
El dato ocupa 16 bytes de memoria. Generalmente los ordenadores personales no
tienen capacidad para trabajar con este kind, pero sı́ las estaciones de trabajo y los
ordenadores de gran potencia de cálculo.
program main
real ( kind =4) :: x
real (4) :: y
real ( kind =8) :: z
real (8) :: t
end program main
Tanto el rango valores como la precisión de los datos reales en simple y doble pre-
cisión presentados anteriormente son meramente orientativos.
Los datos de tipo complex admiten los mismos identificadores de especie ya definidos
para datos de tipo real, y se aplican tanto a la parte real como a la imaginaria. Por tanto,
si el kind es 8, el dato complejo ocupará 16 bytes de memoria (8 la parte real + 8 la parte
imaginaria). Si no se especifica el kind, por defecto se asume que vale 4.
program main
complex :: z
z = (20.508 , 3.7)
z = (205.08 e -1 , 3.7)
z = (2.0508 e +1 , 37 e -1)
z = (20.508 , 0.37 e +1)
end program main
program main
complex ( kind =4) :: x
complex (4) :: y
complex ( kind =8) :: z
complex (8) :: t
end program main
Las constantes literales asociadas a un dato lógico son, en su forma más básica,
.true. (verdadero) o .false. (falso).
program main
logical :: x
x = . true .
x = . false .
end program main
Al igual que en el caso de los datos de tipo numérico, los datos de tipo lógico admiten
un identificador de especie. El valor por defecto del identificador o default kind depende
del procesador.
’ Esto es un mensaje ’
" Esto tambien "
’D . E . Knuth & M . Metcalf ’
Las comillas dobles o simples son solo delimitadores, no forman parte del valor del
dato. El valor de la constante literal ’hola’ es hola. Sı́ hay que tener en cuenta que
los espacios en blanco son caracteres, y que, como carácter, las mayúsculas son distintas
de las minúsculas. Ası́, las constantes ’un saludo’ y ’ un saludo’ son distintas y las
constantes ’Hola’ y ’hola’ también son distintas.
En caso de que necesitemos utilizar comillas simples o dobles como parte de la cons-
tante, basta con usar lo contrario como delimitador. Por ejemplo,
Una forma alternativa de introducir una comilla simple en una constante literal es
mediante dos comillas simples seguidas, sin ningún carácter entre ellas. El valor de la
constante ’don’’t work’ es don’t work.
La longitud de una constante literal de tipo carácter coincide exactamente con el
número de caracteres de impresión contenidos entre los delimitadores.
program main
character :: c_1
character ( len =4) :: c_2
character ( len =10) :: c_3
character ( len =13) :: c_4
character ( len =13) :: c_5
c_1 = ’P ’
c_2 = " Hola "
c_3 = ’ Adios ’
c_4 = " Hola & Adios "
c_5 = ’ Hola & Adios ’
end program main
Un dato de tipo character, por ejemplo ch, declarado con una longitud especı́fica,
por ejemplo 10, se puede entender como una cadena de 10 caracteres de longitud 1.
Podemos acceder a la subcadena formada por los caracteres que van desde el carácter
i-ésimo hasta el j-ésimo utilizando la expresión ch(i:j), siendo i y j dos datos simples
de tipo integer (Fig. 3.10).
program main
character ( len =10) :: ch
integer :: i
integer :: j
ch = ’ carbonilla ’
i = 1
j = 6
write (* ,*) ch ( i : i ) ! ’c ’
write (* ,*) ch ( i : j ) ! ’ carbon ’
write (* ,*) ch ( i +1: j -1) ! ’ arbo ’
write (* ,*) ch ( i +2: i +2) ! ’r ’
end program main
type persona
character ( len =10) :: nombre
character ( len =20) :: apellido
integer :: edad
real :: altura
end type persona
Mientras que para declarar un dato, llamado yo, del tipo derivado persona, la sen-
tencia serı́a
type ( persona ) :: yo
estructura %componente
persona %nombre
persona %apellido
persona %edad
persona %altura
Hay que tener en mente que cuando trabajamos con una componente, estamos traba-
jando con un dato de tipo intrı́nseco. Por ejemplo, persona %edad es una variable de tipo
entero, con las mismas propiedades y caracterı́sticas que cualquier otra variable integer
del programa. Sus constantes literales pertenecen al conjunto de los números enteros,
puede estar declarada con un kind especı́fico, etc.
Una estructura se dice que está definida si, y solo si, lo están cada una de sus
componentes. Para definir una estructura podemos utilizar dos estrategias (Fig. 3.11)
a) Definir las componentes una a una. Para ello, se accede a cada una de las componen-
tes de forma independiente y se le asigna una constante literal apropiada a su tipo
intrı́nseco y en la forma habitual para ese tipo intrı́nseco. Como estamos trabajando
de forma independiente, el orden en el que se definen las componentes no afecta al
resultado final.
b) Definir todas las componentes a la vez. Para ello, se utiliza la fórmula: nombre del
tipo derivado seguido, entre paréntesis, por las constantes literales asignadas a las
componentes, en el mismo orden en el que han sido declaradas.
program main
type persona
character ( len =10) :: nombre
character ( len =20) :: apellido
integer :: edad
real :: altura
end type persona
3.4. Arrays
Un array es una colección de datos, denominados elementos, todos ellos del mismo
tipo y kind, situados en posiciones contiguas de memoria. Los arrays se clasifican en
unidimensionales (vectores), bidimensionales (matrices) y multidimensionales (tablas).
Existen varias formas de declarar un array pero, por el momento, utilizaremos el
modo más sencillo de declarar arrays de forma explı́cita, consistente en especificar el tipo,
el kind, el nombre y la extensión de cada dimensión del array, utilizando (Fig. 3.13) o no
(Fig. 3.12) el atributo dimension.
program main
integer :: U (5) ! Vector
real :: V (10) ! Vector
real :: A (2 ,3) ! Matriz de 2 x3
real :: Z (3 ,2) ! Matriz de 3 x2
real :: T (0:2 , -1:0) ! Matriz de 3 x2
character ( len =2) :: Mch (3 ,2) ! Matriz de 3 x2
integer :: Tabla (2 ,3 ,4) ! Tabla de 2 x3x4
end program main
program main
integer , dimension (5) :: U ! Vector
real , dimension (10) :: V ! Vector
real , dimension (2 ,3) :: A ! Matriz de 2 x3
real , dimension (3 ,2) :: Z ! Matriz de 3 x2
real , dimension (0:2 , -1:0) :: T ! Matriz de 3 x2
character ( len =2) , dimension (3 ,2) :: Mch ! Matriz de 3 x2
integer , dimension (2 ,3 ,4) :: Tabla ! Tabla de 2 x3x4
end program main
• Lı́mites del array. Son los lı́mites inferior y superior de los ı́ndices de las dimensiones.
Si no se especifica el lı́mite inferior, su valor por defecto es 1. U tiene lı́mite superior
5, V tiene lı́mite superior 10, A tiene lı́mites superiores 2 y 3, Z y Mch tiene lı́mites
superiores 3 y 2, T tiene lı́mites superiores 2 y 0 y Tabla tiene lı́mites superiores
2, 3 y 4. Todos los arrays tienen lı́mite inferior 1 en cada una de sus dimensiones
excepto T que tiene lı́mites inferiores 0 y -1.
• Extensión del array. Es el número de elementos (puede ser cero) en cada dimensión.
U tiene extensión 5, V tiene extensión 10, A tiene extensiones 2 y 3, Z, T y Mch tienen
extensiones 3 y 2, y Tabla tiene extensiones 2, 3 y 4.
• Tamaño del array. Indica el número total de elementos. U tiene tamaño 5, V tiene
tamaño 10, A, Z, T y Mch tienen tamaño 6, y Tabla tiene tamaño 24.
• Forma del array. Viene dada por el rango y la extensión. U tiene forma 5, V tiene
forma 10, A tiene forma 2 × 3, Z, T y Mch tiene forma 3 × 2, y Tabla tiene forma
2 × 3 × 4.
• Conforme. Dos arrays se dice que son conformes, si tienen la misma forma.
Un array se identifica por su nombre, que debe seguir las mismas reglas que los
identificadores de los datos simples. Por ejemplo: A, Tabla, . . . Un elemento de un array
se referencia por el nombre del mismo y su posición. Esta posición viene dada por uno o
varios subı́ndices dados entre paréntesis. Por ejemplo, U(3) es el tercer elemento del vector
U; A(2,3) es el elemento de la fila 2 y columna 3 de la matriz A y T(0,-1) es el elemento
de la fila 1 y columna 1 de la matriz T. El subı́ndice debe ser o bien una constante literal
entera, o bien un dato simple de tipo integer.
Un array se dice que está definido si, y solo si, lo están todos sus elementos. Para
definir un array podemos utilizar dos estrategias dependiendo de si todos los elementos
se van a inicializar con la misma constante literal o no (Fig. 3.14).
program main
integer :: U (5) ! Vector
real :: V (10) ! Vector
real :: A (2 ,3) ! Matriz de 2 x3
real :: Z (3 ,2) ! Matriz de 3 x2
real :: T (0:2 , -1:0) ! Matriz de 3 x2
character ( len =2) :: Mch (3 ,2) ! Matriz de 3 x2
integer :: Tabla (2 ,3 ,4) ! Tabla de 2 x3x4
V = 2.0
Tabla = 8
U = (/2 , -3 , 0 , 5 , 8/)
A = reshape ((/1.1 , 1.2 , 3.8 , 5.5 , 4.3 , 7.0/) , (/2 ,3/))
Z = reshape ((/1.1 , 1.2 , 3.8 , 5.5 , 4.3 , 7.0/) , (/3 ,2/))
T = reshape ((/1.1 , 1.2 , 3.8 , 5.5 , 4.3 , 7.0/) , (/3 ,2/))
Mch = reshape ((/ ’ ab ’ , ’ cd ’ , ’ ef ’ , ’ uv ’ , ’ wx ’ , ’ yz ’/) , (/3 ,2/))
end program main
a) Para asignar el mismo valor a todos los elementos del array, se utiliza el modo ha-
bitual de asignación:
dado que una constante literal se considera conforme a cualquier array. Por ejemplo,
las sentencias
V = 2.0
Tabla = 8
• En lenguaje matemático:
V1 = 2 V2 = 2 . . . V10 = 2
T abla111 = 8 T abla211 = 8 . . . T abla234 = 8
• En lenguaje de programación:
V(1)=2.0 V(2)=2.0 . . . V(10)=2.0
Tabla(1,1,1)=8 Tabla(2,1,1)=8 . . . Tabla(2,3,4)=8
b) Para asignar distintas constantes literales, tantas como indique el tamaño del array,
se introduce la lista de las constantes entre los sı́mbolos de apertura y cierre (/ y
/), respectivamente. Además,
U = (/2 , -3 , 0 , 5 , 8/)
teniendo siempre en cuenta que, en el orden natural de los elementos del array,
los ı́ndices varı́an más rápidamente de izquierda a derecha (Fig. 3.15)
• En lenguaje de programación:
program main
real , parameter :: g = 9.80665
integer , parameter :: l = 5
integer , parameter :: m = 2
integer , parameter :: n = 3
integer , parameter :: s = 4
integer , parameter :: n1 = 0
integer , parameter :: m1 = -1
integer , dimension ( l ) :: U ! Vector
real , dimension (n , m ) :: Z ! Matriz de 3 x2
real :: A (m , n ) ! Matriz de 2 x3
real :: T (0: m , m1 : n1 ) ! Matriz de 3 x2
character ( len =2) :: Mch (n , m ) ! Matriz de 3 x2
integer :: Tabla (m ,n , s ) ! Tabla de 2 x3x4
end program main
algún dato y además, olvidar esta regla, con lo que es posible que datos que queremos
que sean integer el programa los trate como real y viceversa.
Para evitar este riesgo, es aconsejable utilizar la sentencia implicit none. Esta
sentencia, situada antes del cuerpo de las declaraciones, invalida todas las declaraciones
implı́citas y obliga a declarar todos los objetos que vayan a ser utilizados a lo largo del
programa.
program main
implicit none
integer :: m
integer :: n
real :: z
.
.
end program main
integer , parameter :: n = 5
integer , parameter :: m = 2
integer , dimension (3) :: U = (/1 , 5 , 8/)
real , dimension (n , m ) :: A = 33.0
character ( len =4) :: Mch = ’ hola ’
3.8. Resumen
Como resumen de lo visto a lo largo de este capı́tulo hay que resaltar los siguientes
puntos:
• Además de los 5 tipos intrı́nsecos, Fortran posee dos herramientas muy poderosas
para ampliar los tipos de datos:
◦ Los datos derivados, útiles para crear objetos abstractos que agrupan datos de
distintos tipos.
◦ Los arrays, asociados al concepto matemático de vector o matriz.
• Declarar un dato significa asignarle un tipo. Cada tipo tiene su propio rango de
valores válidos. Si el tipo del dato no coincide con el tipo de la constante literal que
se pretende asignar, siempre prevalece el tipo con el que se ha declarado el dato.
type persona
character(len=20) :: nombre
tipo
integer :: edad componente
derivado
real :: altura
end type persona
5
3.8
constante
(2.0, 3.5) literal
’hola’
.true.
A(1,3)
U(2) elemento
ellos(10)
Índice
4.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.2. Expresiones aritméticas . . . . . . . . . . . . . . . . . . . . . . . 39
4.3. Expresiones relacionales . . . . . . . . . . . . . . . . . . . . . . 41
4.4. Expresiones lógicas . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.5. Operaciones con caracteres . . . . . . . . . . . . . . . . . . . . . 44
4.6. Operaciones con arrays . . . . . . . . . . . . . . . . . . . . . . . 47
4.7. Definición en la lı́nea de declaración . . . . . . . . . . . . . . . 47
37
38 4.1 Introducción
4.1. Introducción
En el lenguaje natural existen letras que forman palabras que, combinadas siguiendo
las reglas gramaticales establecidas, generan las frases lógicas con las que nos comunica-
mos. Del mismo modo en Fontran existen los datos que, como las letras forman expresiones
que se combinan siguiendo las reglas propias de este lenguaje de programación, para for-
mar sentencias.
A diferencia de lo que ocurre en el lenguaje natural donde la comunicación es posible
aun cuando la frase sea gramaticalmente incorrecta, en programación las reglas “grama-
ticales” se deben cumplir de forma estricta, pues la comunicación se establece con una
máquina, es decir un objeto incapaz de interpretar una ambigüedad.
Una expresión en Fortran está formada por operandos y operadores, combinados
siguiendo las reglas sintácticas propias del lenguaje. Una expresión simple se puede cons-
truir utilizando un operador binario en la forma
por ejemplo
x *5
operador operando
por ejemplo
-x
Los operandos pueden ser constantes literales, datos o incluso otras expresiones,
dando lugar a expresiones más complejas del tipo
Evidentemente, cada operando debe estar definido antes de ser utilizado en una ex-
presión y la propia expresión debe ser conceptualmente correcta. Por ejemplo, matemáti-
camente es incorrecto establecer una relación de orden entre dos números complejos.
La regla seguida en Fortran para la evaluación de las diferentes partes de una expre-
sión compleja es que son evaluadas sucesivamente de izquierda a derecha, para operadores
de la misma precedencia, salvo en el caso de la potenciación. Si, al margen de esta regla,
interesa evaluar primero ciertas subexpresiones, éstas deben ir encerradas entre paréntesis.
Solo es posible que en una expresión aparezcan dos operadores seguidos si el segundo
es unario. Es decir en una expresión del tipo
el segundo operador nunca puede ser un operador binario. En cualquier caso, sea obliga-
torio o no, por cuestiones de claridad es recomendable utilizar paréntesis para separar las
distintas operaciones de una misma sentencia.
En las siguientes tres secciones de este capı́tulo expondremos las propiedades de
las expresiones intrı́nsecas de Fortran que involucran como operandos datos simples (ex-
presiones aritméticas, relacionales y lógicas). Las dos últimas secciones se ocupan de dos
casos particulares: los datos de tipo character y los arrays.
a*b/c
es equivalente a
( a * b )/ c
mientras que
a ** b ** c
se evalúa como
a **( b ** c )
Cuando se opera con datos numéricos de distinto tipo y kind, es necesario tener en
cuenta que el resultado es del tipo con mayor rango de los involucrados en la operación.
De hecho, antes de evaluar la expresión se convierten los operandos al tipo más fuerte
salvo cuando se eleva un dato de tipo real o complex a una potencia de tipo integer,
en el que no se convierte el tipo del exponente (Tablas 4.2 y 4.3)
Se recomienda que en la potenciación el exponente sea, siempre que sea posible, un
dato integer para asegurar mayor precisión del resultado. Si el exponente es integer, el
ordenador interpreta la potenciación como: “multiplica la base tantas veces como indique
el exponente”, mientras que si es real lo que hace es la exponencial del producto del
exponente por el logaritmo de la base (resultado menos preciso).
En la tabla 4.4 se muestran algunos ejemplos prácticos, muy útiles para comprender
mejor las reglas de conversión.
tipo. Los operadores relacionales que Fortran dispone de modo intrı́nseco vienen dados
en la tabla 4.5.
1 i <= 0
2 a > b
3 ( a + b ) > (i - j )
4 a+b > i-j
5 ch == ’Z ’
Las expresiones de las lı́neas 3 y 4 son de tipo mixto en el sentido de que en ellas
aparecen datos de distinto tipo. Además, intervienen relaciones aritméticas. Como regla
general, siempre que en una expresión relacional intervengan datos numéricos de distinto
tipo o kind, antes de evaluar la expresión relacional, los datos numéricos se convierten
al tipo y kind de mayor rango de los involucrados. Ası́, en las sentencias de las lı́neas
3 y 4, después de realizar la operación (i-j) el resultado se convierte a tipo real y se
compara con el resultado de la operación (a+b). Respecto al orden en el que se evalúan las
expresiones, primero se realizan las operaciones aritméticas y luego las relacionales, por
lo que las sentencias de las lı́neas 3 y 4 son equivalentes. Para evitar confusiones conviene
utilizar siempre los paréntesis.
Operadores binarios:
.and. intersección lógica
.or. unión lógica
.eqv. y .neqv. equivalencia y no equivalencia lógica
La figura 4.3 recoge algunos ejemplos de expresiones que involucran los 3 tipos de
operadores vistos hasta ahora.
Cuando en una expresión lógica interviene alguno de los operadores .and. u .or.
no existe una regla definida sobre el orden en el que se evalúan los operandos. Incluso,
dependiendo del procesador, puede ocurrir que alguno de los operandos no llegue a ser
evaluado. Por ejemplo, dadas dos variables de tipo integer con valores i=6 y j=4, en la
expresión
( j < 5) . or . ( i < 5)
a = .true. y b = .false.
.true. Si o
a = .false. y b = .true.
a.neqv.b
a = .true. y b = .true.
.false. Si
o
a = .false. y b = .false.
tendrán que evaluar también la de la izquierda. Por último, existen procesadores que, al
margen del valor de los operandos, evalúan todas las subexpresiones involucradas.
’ Agente ’ // ’ 007 ’
program main
type persona
character ( len =20) :: nombre
integer :: edad
end type
integer :: i
integer :: j
integer :: k
integer :: U (4)
logical :: F1
logical :: F2
type ( persona ) :: yo
i = 6
j = 4
k = 10
U = (/1 , -2 , 8 , 0/)
yo %edad = 20
write (* ,*) i < 0 ! falso
write (* ,*) i <= k ! verdadero
write (* ,*) ( i + j ) <= k ! verdadero
write (* ,*) ( i < 20) . and . ( j < 20) ! verdadero
write (* ,*) ( i < 5) . and . ( j < 5) ! falso
write (* ,*) ( i < 5) . or . ( j < 5) ! verdadero
write (* ,*) U ( j ) == 1 ! falso
write (* ,*) U ( j )+ U (j -1) > 0 ! verdadero
write (* ,*) i + U (1) == 7 ! verdadero
write (* ,*) yo %edad >= 20 ! verdadero
F1 = (( i + j ) == k ) ! verdadero
F2 = (( i - j ) > 0) ! falso
write (* ,*) . not . F1 ! falso
write (* ,*) F1 . eqv . F2 ! falso
write (* ,*) F1 . neqv . F2 ! verdadero
end program main
el valor del resultado con tantos caracteres blanco a la derecha como sea necesario para
completar la longitud long dato. Si por el contrario es menor, se trunca el valor del
resultado a los primeros long dato caracteres (Fig. 4.4).
Mención especial merecen las expresiones relacionales en las que los operandos son
de tipo character. En todos los procesadores los caracteres poseen una propiedad de-
nominada secuencia de comparación, que ordena la colección de caracteres asignándoles
un número de orden. Aunque cada procesador puede tener su propia secuencia, la ma-
yorı́a utiliza la secuencia definida por el estándar ASCII (del inglés, American Standard
Code for Information Interchange). Sin embargo, Fortran está diseñado para adaptarse
a otras secuencias como, por ejemplo la secuencia EBCDIC (del inglés, Extended Binary
Coded Decimal Interchange Code) desarrollada por IBM. Esto implica que, en general,
por cuestiones de portabilidad, no es conveniente que un programa fundamente parte de
su algoritmo en la relación entre datos de tipo character. En el apéndice A se muestra
una tabla completa del conjunto de caracteres ASCII ası́ como su número de orden.
En cualquier caso, la comparación entre dos operandos de tipo character se realiza
carácter a carácter de izquierda a derecha siguiendo el orden alfabético para las letras y
el numérico para los dı́gitos. Si los operandos no tienen la misma longitud, el de menor
longitud se rellena con espacios en blanco a la derecha hasta completar la longitud máxima
antes de realizar la comparación (Fig 4.5).
program main
character ( len =3) :: ch
ch = ’abc ’
write (* ,*) ch == ’Abc ’ ! falso
write (* ,*) ch == ’ abc ’ ! falso
write (* ,*) ch == ’ abc ’ ! verdadero
write (* ,*) ch > ’abg ’ ! falso
write (* ,*) ch > ’aba ’ ! verdadero
write (* ,*) ch < ’ ab ’ ! falso
write (* ,*) ch < ’ ab ’ ! falso
write (* ,*) ch > ’ abc ’ ! falso
write (* ,*) ch >= ’ abc ’ ! verdadero
end program main
integer , parameter :: n = 3
integer , parameter :: m = n -1
integer , dimension (3) :: U = n * m
real , dimension (n , m ) :: A = reshape ((/1 , 0 , 2 , 8 , 3 , 1/) , (/ n , m /))
character ( len =8) :: Mch = ’ hola ’// ’ pepe ’
logical :: flag = ( m < n )
program main
integer :: U (3)
integer :: V (3)
logical :: Luv (3)
integer :: a (2 ,3)
integer :: b (2 ,3)
integer :: c (2 ,3)
U = (/1 , 2 , 3/)
V = 2
Luv = ( U >= V ) ! Luv = (/ F , T , T /)
U = U + V ! U = (/3 , 4 , 5/)
U = U*V ! U = (/6 , 8 , 10/)
Luv = . not . Luv ! Luv = (/ T , F , F /)
a = reshape ((/1 , 0 , 2 , 8 , 3 , 1/) , (/2 ,3/))
b = reshape ((/0 , 4 , 1 , 2 , 5 ,9/) , (/2 ,3/))
c = a*b ! c = (/0 ,0 ,2 ,16 ,15 ,9/)
end program main
49
50 5.1 Introducción
5.1. Introducción
Para aumentar la eficiencia de la programación es necesario que los programas tengan
una estructura fácil de interpretar, manejar y modificar. Los criterios de programación que
cumplen estos objetivos son la programación estructurada y la programación modular. No
son criterios contrapuestos, sino complementarios. El modular tiende a dividir el programa
en programas más pequeños, llamados subprogramas, mientras que el estructurado se
encarga de desarrollar estructuradamente cada uno de los subprogramas.
En este capı́tulo nos centraremos en la programación estructurada, dejando la mo-
dular para capı́tulos posteriores.
En un programa, las sentencias se ejecutan de forma secuencial o lineal. A menudo,
conviene no utilizar esta secuencia sino modificarla a medida que se van haciendo los
cálculos. La base de la programación estructurada es que todo programa puede ser escrito
utilizando solo tres tipos de estructuras de control de ejecución,
• secuencial
• condicional
• iterativa
que se pueden anidar (pero no solapar) adecuadamente cuando sea necesario.
La estructura secuencial es aquella en la que las acciones se realizan de forma se-
cuencial (una a continuación de la otra), sin posibilidad de omitir ninguna. Es el caso de
los programas vistos en los capı́tulos anteriores. Este paradigma de programación resulta
muy sencillo pero de escasa utilidad en la práctica. Es habitual que se requiera que se
ejecute determinado grupo de sentencias si se cumple determinada condición (por ejem-
plo si cierto número es positivo), y otro grupo distinto de sentencias en caso contrario.
También suele ser necesario realizar el mismo grupo de operaciones varias veces en deter-
minado punto del programa. Por ejemplo, si se quiere calcular la suma de los mil primeros
números naturales resulta ineficiente y tedioso escribir un programa de forma secuencial
con mil sentencias en las que se realiza la misma operación. En este caso se requiere la
posibilidad de realizar una única adición de forma iterativa. Fortran dispone de dos herra-
mientas para controlar el flujo lógico del programa: la estructura condicional, que permite
la bifurcación en determinado punto de un programa, y la estructura iterativa, indicada
para los procesos iterativos.
Como norma general, existe una palabra clave que inicia la estructura (if, select,
do) y otra que la cierra (end if, end select, end do). Entre ambas, se encuentra el
grupo de sentencias sometidas a las condiciones impuestas. En todos los casos tenemos
Por ejemplo, queremos intercambiar los valores de x e y solo en el caso en que x sea
menor que y. El algoritmo serı́a:
if ( x < y ) then
temp = x
x = y
y = temp
end if
Como simplificación, en el caso de que solo haya una sentencia de ejecución dentro
de la estructura, el lenguaje permite la siguiente variación
Figura 5.2 Ejemplo con estructura condicional simple. Cálculo del valor absoluto
program ValorAbsoluto
real :: x
write (* ,*) ’ Introducir el valor de x ’
read (* ,*) x
if ( x < 0.0) x = -x
write (* ,*) ’ El valor absoluto de x es ’, x
end program ValorAbsoluto
program raiz
real :: a
real :: b
real :: x
write (* ,*) ’ Introducir los valores de a y b ’
read (* ,*) a , b
if ( a /= 0.0) then
x = -b / a
write (* ,*) ’ La solucion de la ecuacion es x = ’, x
else
write (* ,*) ’ La ecuacion planteada es incorrecta ’
end if
end program raiz
5.2.3.1. Construcción if
sentencias 1
else if (expr. lógica2) then
sentencias 2
else if (expr. lógica3) then
sentencias 3
..
.
[ else
sentencias n]
end if [ nombre ]
program raices
real :: a
real :: b
real :: c
real :: disc
real :: x1
real :: x2
complex :: z1
complex :: z2
disc = b * b - 4.0* a * c
if ( disc < 0.0) then
z1 = cmplx ( -b , sqrt ( - disc ))
z1 = z1 /(2.0* a )
z2 = cmplx ( -b , - sqrt ( - disc ))
z2 = z2 /(2.0* a )
write (* ,*) ’ Las soluciones de la ecuacion son ’, z1 , z2
else if ( disc > 0.0) then
x1 = ( - b + sqrt ( disc ))/(2.0* a )
x2 = ( - b - sqrt ( disc ))/(2.0* a )
write (* ,*) ’ Las soluciones de la ecuacion son ’, x1 , x2
else
x1 = -b /(2.0* a )
x2 = x1
write (* ,*) ’ Las soluciones de la ecuacion son ’, x1 , x2
end if
?
@
expr.@
@
#1 ? #2 ? @ ?
donde
• expr. case es una expresión escalar de tipo integer, character o logical. Por
ejemplo, el nombre de un dato simple de uno de estos tipos, i, o una expresión
aritmética, i*j+2
• rango de valores puede tomar un único valor, varios valores o un rango de valores,
según se escriba de la forma
program ejemplo_case
integer :: num
write (* ,*) ’ Introducir un numero entero ’
read (* ,*) num
select case ( num )
case (: -1)
write (* ,*) ’ numero <= -1 ’
case (1 , 3 , 5 , 7 , 9)
write (* ,*) ’ 1 <= numero <= 9 e impar ’
case (2 , 4 , 6 , 8)
write (* ,*) ’ 2 <= numero <= 8 y par ’
case (0 , 10:200)
write (* ,*) ’ 10 <= numero <= 200 o 0 ’
case (205:)
write (* ,*) ’ numero >= 205 ’
case default
write (* ,*) ’ 201 <= numero <= 204 ’
end select
end program ejemplo_case
donde,
• vi,vf,p son constantes o variables de tipo integer, tales que vi es el valor inicial
del contador, vf es el valor final del contador y p es el incremento.
• Cuando se produce una salida normal del rango, el contador vale i=vi+p*(1+(vf-vi)/p)
• Dentro del rango del bucle se puede redefinir el contador, y este cambio queda
reflejado en el siguiente paso, por lo que en esta asignatura no estará permitido
hacerlo.
• Dentro del rango se pueden cambiar los valores de las variables vi, vf o p, y aunque
estos cambios no afectan al proceso de variación del contador establecido en el inicio
del bucle, en esta asignatura no estará permitido hacerlo.
• El número de iteraciones realizadas tras una salida normal del bucle do viene dado
por la expresión n o
máx (vf − vi + p)/p, 0
Ejemplos tı́picos del uso de estructuras iterativas lo constituyen el cálculo del suma-
torio y el productorio. En las figuras 5.11 y 5.12 se utiliza la construcción do con contador
para calcular la suma de los n primeros números naturales y el factorial de un número
entero no negativo, respectivamente. Nótese que estamos haciendo uso de una estructura
iterativa dentro de una condicional.
program Sumatorio
integer :: n
integer :: suma
integer :: i
program Factorial
integer :: n
integer :: Fact
integer :: i
1. Para definir un array cuyos elementos siguen una regla iterativa sencilla.
( lista_de_variables , i = vi , vf [ , p ])
siendo i el contador del bucle y lista variables el rango del mismo, es decir, la variación
de los datos deseada en cada iteración.
En el ejemplo de la figura 5.13 se muestran los dos usos del bucle implı́cito: para
definir un vector U, de modo que el valor de cada elemento U(i) está relacionado con el
ı́ndice del mismo, y para imprimir una matriz A tal y como lo hacemos matemáticamente,
es decir, por filas.
program main
integer , parameter :: n = 5
integer , parameter :: m = n +1
real :: U ( n )
real :: A (n , m )
integer :: i
integer :: j
program Sumatorio
integer :: cota , n
integer :: i , suma
! lectura de la cota
do
write (* ,*) ’ Introducir un numero entero positivo ’
read (* ,*) cota
if ( cota > 0) exit
end do
Índice
6.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
6.2. Funciones intrı́nsecas con datos numéricos . . . . . . . . . . . 66
6.2.1. Funciones de conversión . . . . . . . . . . . . . . . . . . . . . . 67
6.2.2. Funciones de truncamiento y redondeo . . . . . . . . . . . . . . 68
6.2.3. Funciones matemáticas . . . . . . . . . . . . . . . . . . . . . . 69
6.3. Funciones intrı́nsecas especı́ficas de caracteres . . . . . . . . . 70
6.3.1. Funciones de conversión . . . . . . . . . . . . . . . . . . . . . . 70
6.3.2. Funciones de manipulación . . . . . . . . . . . . . . . . . . . . 71
6.4. Funciones intrı́nsecas especı́ficas de arrays . . . . . . . . . . . 74
6.4.1. Funciones de cálculo . . . . . . . . . . . . . . . . . . . . . . . . 74
6.4.2. Funciones de búsqueda . . . . . . . . . . . . . . . . . . . . . . . 76
6.4.3. Funciones de dimensiones . . . . . . . . . . . . . . . . . . . . . 79
65
66 6.1 Introducción
6.1. Introducción
Dada la orientación de Fortran hacia la resolución de problemas cientı́ficos, es lógico
que las funciones matemáticas más básicas formen parte del propio lenguaje y no tengan
que ser programadas por el usuario. Además estas funciones han sido programadas del
modo más eficiente, aprovechando al máximo los recursos del compilador, por lo que
resulta muy difı́cil competir con ellas.
En este capı́tulo estudiaremos las funciones intrı́nsecas siguiendo una clasificación
basada en el tipo de sus argumentos:
cmplx(x) = x + i0.0
cmplx(x, y) = x + iy
Para todas aquellas funciones matemáticas que por definición son multivaluadas, el
valor retornado es el valor principal. Además de las funciones listadas, suficientemente
auto-explicativas, a continuación se detallan otras funciones de uso común.
abs(x)
sign(x,y)
Transfiere el signo del argumento y al argumento x. Los argumentos deben ser ambos
de tipo integer o real.
(
|x| Si y ≥ 0
sign(x, y) =
−|x| Si y < 0
mod(x,y)
Calcula el resto de la división x/y. Los argumentos deben ser ambos de tipo integer
o real. (
x − int(x/y) × y Si y 6= 0
mod(x, y) =
depende del compilador Si y = 0
len(string)
Devuelve la longitud de string
len(’ Fortran & magic ’) = 20
len trim(string)
Devuelve la longitud de string sin contar los espacios en blanco de la derecha.
len_trim(’ Fortran & magic ’) = 17
trim(string)
Devuelve el mismo string pero quitando los espacios en blanco de la derecha.
trim(’ Fortran & magic ’) = ’ Fortran & magic’
adjustl(string)
Ajusta string a la izquierda, manteniendo su longitud
adjustl(’ Fortran & magic ’) = ’Fortran & magic ’
adjustr(string)
Ajusta string a la derecha, manteniendo su longitud
adjustr(’ Fortran & magic ’) = ’ Fortran & magic’
index(’aderezado’, ’a’) = 1
index(’aderezado’, ’a’, back=.true.) = 7
index(’aderezado’, ’A’) = 0
index(’aderezado’, ’A’, back=.true.) = 0
index(’aderezado’, ’ad’) = 1
index(’aderezado’, ’ad’, back=.true.) = 7
index(’aderezado’, ’ae’) = 0
index(’aderezado’, ’ae’, back=.true.) = 0
index(’aderezado’, ’’) = 1
index(’aderezado’, ’’, back=.true.) = 10
scan(’aderezado’, ’ae’) = 1
scan(’aderezado’, ’ae’, back=.true.) = 7
scan(’aderezado’, ’ea’) = 1
scan(’aderezado’, ’ea’, back=.true.) = 7
scan(’aderezado’, ’Ae’) = 3
scan(’aderezado’, ’Ae’, back=.true.) = 5
scan(’aderezado’, ’Af’) = 0
scan(’aderezado’, ’Af’, back=.true.) = 0
scan(’aderezado’, ’’) = 0
scan(’aderezado’, ’’, back=.true.) = 0
B = exp ( A )
sum(array)
Devuelve un escalar que es la suma todos los elementos de array. El tipo y el
kind del escalar coincide con el de array.
sum(array, mask=expr. lógica)
Devuelve un escalar que es la suma de todos los elementos de array que cum-
plen la condición dada por expr. lógica. Si ningún elemento cumple la con-
dición lógica, devuelve un cero.
sum(matriz, dim=num)
Si num = 1, devuelve un vector cuyos elementos son la suma de las columnas
de la matriz. Si num = 2, devuelve un vector cuyos elementos son la suma de
las filas de la matriz.
sum(matriz, dim=num, mask=expr. lógica)
Si num = 1, devuelve un vector cuyos elementos son la suma de las columnas
de la matriz que cumplen la condición dada por expr. lógica. Si num = 2,
devuelve un vector cuyos elementos son la suma de las filas de la matriz que
cumplen la condición dada por expr. lógica.
sum ( A ) ! devuelve 9
sum (A , mask =( A >0)) ! devuelve 15
sum (A , mask =( A >20)) ! devuelve 0
sum (A , dim =1) ! devuelve (/7 , 1 , 1/)
sum (A , dim =2) ! devuelve (/4 , 5/)
sum (A , dim =2 , mask =( A >0)) ! devuelve (/6 , 9/)
sum (A , dim =2 , mask =( A >5)) ! devuelve (/0 , 6/)
product
product(array)
Devuelve un escalar que es el producto de todos los elementos de array. El
tipo y el kind del escalar coincide con el de array.
product(array, mask=expr. lógica)
Devuelve un escalar que es el producto de todos los elementos de array que
cumplen la condición dada por expr. lógica. Si ningún elemento cumple la
condición lógica, devuelve un uno.
product(matriz, dim=num)
Si num = 1, devuelve un vector cuyos elementos son el producto de las columnas
de la matriz. Si num = 2, devuelve un vector cuyos elementos son el producto
de las filas de la matriz.
product(matriz, dim=num, mask=expr. lógica)
Si num = 1, devuelve un vector cuyos elementos son el producto de las columnas
de la matriz que cumplen la condición dada por expr. lógica. Si num = 2,
devuelve un vector cuyos elementos son el producto de las filas de la matriz
que cumplen la condición dada por expr. lógica.
matmul(array 1,array 2)
Esta función devuelve el producto de dos arrays con formas compatibles con las
reglas algebraicas. Al menos uno de los dos argumentos debe ser una matriz. El tipo
de array 1 y array 2 no es necesario que sea coincidente. El resultado sigue las
reglas usuales de conversión aritmética.
transpose(matriz)
Esta función devuelve la matriz transpuesta de matriz, con el mismo tipo y kind.
La matriz no es necesario que sea una matriz cuadrada.
maxval(array)
Devuelve un escalar que es el máximo de los elementos de array. El tipo y
el kind del escalar coincide con el de array, teniendo en cuenta que array no
puede ser de tipo complex.
maxval ( U ) ! devuelve 4
maxval (U , mask =( U <0)) ! devuelve -5
maxval ( A ) ! devuelve 6
maxval (A , mask =( A <5)) ! devuelve 3
maxval (A , dim =1) ! devuelve (/6 , 5 , 3/)
maxval (A , dim =2) ! devuelve (/5 , 6/)
maxval (A , dim =1 , mask =( A <0)) ! devuelve (/ -1200 , -4 , -2/)
maxloc — minloc
maxloc(vector)
Devuelve un vector de un elemento que es la posición (no el ı́ndice) que ocupa el
mayor elemento del vector. En caso de que haya varios máximos, solo devuelve
la posición del primero de ellos.
maxloc(vector, mask=expr. lógica)
Devuelve un vector de un elemento que es la posición (no el ı́ndice) que ocupa
el mayor elemento del vector que cumple la condición dada en expr. lógica.
En caso de que haya varios máximos, solo devuelve la posición del primero de
ellos. Si ningún elemento cumple la condición lógica devuelve el vector cero.
maxloc(matriz)
Devuelve un vector de dos elementos que es la posición (no los ı́ndices) que
ocupa el mayor elemento de la matriz. En caso de que haya varios máximos,
solo devuelve la posición del primero de ellos, considerando que la matriz se
recorre por columnas.
maxloc(matriz, mask=expr. lógica)
Devuelve un vector de dos elementos que es la posición (no los ı́ndices) que
ocupa el mayor elemento de la matriz que cumple la condición dada en expr.
lógica. En caso de que haya varios máximos, solo devuelve la posición del
primero de ellos, considerando que la matriz se recorre por columnas. Si ningun
elemento cumple la condición lógica devuelve el vector cero.
all(expr. lógica)
Devuelve la constante literal .true. si todos los elementos del array verifican la
condición expr. lógica, y la constante .false. si alguno los elementos del array
no la verifica.
Si el array es una matriz, se puede utilizar el argumento opcional dim para especificar
si se evalúan las columnas (dim=1) o las filas (dim=2). En ese caso el resultado es
un vector.
any(expr. lógica)
Devuelve la constante literal .true. si algún elemento del array verifica la condición
expr. lógica, y la constante .false. si ninguno de los elementos del array la
verifica.
Si el array es una matriz, se puede utilizar el argumento opcional dim para especificar
si se evalúan las columnas (dim=1) o las filas (dim=2). En ese caso el resultado es
un vector.
count(expr. lógica)
Devuelve un dato de tipo integer que cuenta el número de elementos del array que
verifican la condición expr. lógica.
Si el array es una matriz, se puede utilizar el argumento opcional dim para especificar
si se evalúan las columnas (dim=1) o las filas (dim=2). En ese caso el resultado es
un vector.
Dada la matriz B de tipo integer,
!
1 5 −2
B=
6 −4 −3
size(array)
Devuelve un escalar de tipo integer igual al número total de elementos de
array.
size(matriz, dim=num)
Si num = 1, devuelve un escalar igual al número de filas de la matriz. Si num
= 2, devuelve un escalar igual al número de columnas de la matriz.
shape(array)
Devuelve un vector de tipo integer con tantos elementos como dimensiones tiene
array, que contiene el número de elementos que hay en cada dimensión de array.
lbound
lbound(array)
Devuelve un vector de tipo integer, con tantos elementos como dimensiones
tiene array, que contiene el lı́mite inferior de cada una de las dimensiones de
array.
lbound(matriz, dim=num)
Si num = 1, devuelve un escalar igual al lı́mite inferior de las filas de la matriz.
Si num = 2, devuelve un escalar igual al lı́mite inferior de las columnas de la
matriz.
ubound
ubound(array)
Devuelve un vector de tipo integer, con tantos elementos como dimensiones
tiene array, que contiene el lı́mite superior de cada una de las dimensiones de
array.
ubound(matriz, dim=num)
Si num = 1, devuelve un escalar igual al lı́mite superior de las filas de la matriz.
Si num = 2, devuelve un escalar igual al lı́mite superior de las columnas de la
matriz.
reshape(vector 1,vector 2)
Esta función construye un array con la forma dada por el vector vector 2 y los
datos contenidos en vector 1.
program main
integer :: n
integer :: U (2)
integer :: V (1)
real :: T (10:12)
integer :: A (2 ,3)
integer :: B (0:10 ,4:8)
real :: Zt (0:2 ,3)
integer :: Vu (2)
integer :: C (6)
real :: Cr (9)
! Funcion size
n = size ( T ) ! n = 3
n = size ( A ) ! n = 6
n = size (A , dim =1) ! n = 2
n = size (A , dim =2) ! n = 3
n = size ( B ) ! n = 55
n = size (B , dim =1) ! n = 11
n = size (B , dim =2) ! n = 5
n = size ( Zt ) ! n = 9
n = size ( Zt , dim =1) ! n = 3
n = size ( Zt , dim =2) ! n = 3
! Funcion shape
V = shape ( T ) ! V = (/3/)
U = shape ( A ) ! U = (/2 , 3/)
U = shape ( B ) ! U = (/11 , 5/)
U = shape ( Zt ) ! U = (/3 , 3/)
! Funcion lbound
V = lbound ( T ) ! V = (/10/)
U = lbound ( A ) ! U = (/1 , 1/)
n = lbound (A , dim =1) ! n = 1
n = lbound (A , dim =2) ! n = 1
U = lbound ( B ) ! U = (/0 , 4/)
n = lbound (B , dim =1) ! n = 0
! Funcion ubound
V = ubound ( T ) ! V = (/12/)
U = ubound ( A ) ! U = (/2 , 3/)
n = ubound (A , dim =1) ! n = 2
n = ubound (A , dim =2) ! n = 3
U = ubound ( B ) ! U = (/10 , 8/)
n = ubound (B , dim =1) ! n = 10
n = ubound (B , dim =2) ! n = 8
U = ubound ( Zt ) ! U = (/2 , 3/)
n = ubound ( Zt , dim =1) ! n = 2
n = ubound ( Zt , dim =2) ! n = 3
! Funcion reshape
Vu = (/2 , 3/)
C = (/1 , 6 , 5 , -4 , -2 , 3/)
A = reshape (C , Vu )
Vu = (/3 , 3/)
Cr = 4.0
Zt = reshape ( Cr , Vu )
Índice
7.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
7.2. Datos array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
7.2.1. Secciones de un array . . . . . . . . . . . . . . . . . . . . . . . 84
7.2.2. Asignación dinámica de memoria . . . . . . . . . . . . . . . . . 87
7.2.3. Arrays de tamaño cero . . . . . . . . . . . . . . . . . . . . . . . 90
7.3. Datos de tipo derivado . . . . . . . . . . . . . . . . . . . . . . . 91
7.3.1. Componente de tipo array . . . . . . . . . . . . . . . . . . . . . 92
7.3.2. Componente de tipo estructura . . . . . . . . . . . . . . . . . . 94
83
84 7.1 Introducción
7.1. Introducción
Hoy en dı́a el uso de objetos compuestos en Fortran se considera una práctica ha-
bitual tanto por la sencillez de su manejo como por la compacidad de su notación. Para
los arrays en particular, se ha visto que Fortran posee un conjunto de funciones intrı́nse-
cas que los dotan de una potencia de cálculo superior a la de cualquier otro lenguaje de
programación. En el caso de las estructuras, el poder representar de forma compacta un
objeto (una figura geométrica, una agenda personal, etc) ha permitido en los últimos años
un estilo de programación mucho más claro y estructurado.
Aunque los objetos compuestos ya han sido definidos y parcialmente estudiados, en
este capı́tulo vamos a desarrollar algunos aspectos tı́picos de su manejo que, por cuestiones
de claridad en la exposición, no se han desarrollado anteriormente.
En particular, en el caso de los arrays vamos a estudiar dos puntos de gran interés,
2. La asignación dinámica de memoria. ¿Es posible declarar un array del cual se sabe
cuántas dimensiones tiene, pero no cuáles son sus lı́mites?
De los datos de tipo derivado nos vamos a ocupar de dos cuestiones que, aunque son
sencillas, generalmente dan lugar a confusión,
nombre ([ ini_1 ]:[ fin_1 ][: inc_1 ] ,[ ini_2 ]:[ fin_2 ][: inc_2 ] ,...)
Ası́ a partir de los arrays V y A siguientes
V = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
11 12 13 14 15 16 17 18
21 22 23 24 25 26 27 28
31 32 33 34 35 36 37 38
A=
41 42 43 44 45 46 47 48
51 52 53 54 55 56 57 58
61 62 63 64 65 66 67 68
declarados como
integer :: V (0:10)
integer :: A (6 ,8)
V = ( 0 , 1, 2 , 3, 4 , 5, 6 , 7, 8 , 9, 10 )
V = (0, 1, 2, 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 )
A(2:5,7:7) (matriz de 4 × 1)
11 12 13 14 15 16 17 18
21 22 23 24 25 26 27 28
31 32 33 34 35 36 37 38
A=
41 42 43 44 45 46 47 48
51 52 53 54 55 56 57 58
61 62 63 64 65 66 67 68
program main
integer :: V (0:10)
integer :: A (6 ,8)
integer :: Uf (4)
integer :: Uc (5)
integer :: B (4 ,5)
integer :: U (4)
integer :: vW (4)
integer :: mW (1 ,4)
.
.
Uf = (/2 , 1 , 5 , 1/)
Uc = (/3 , 6 , 2 , 4 , 3/)
U = V ( Uf )
B = A ( Uf , Uc )
vW = A (2 , Uf )
mW = A (2:2 , Uf )
.
.
end program main
23 26 22 24 23 22
U = (1, 0, 4, 0)
13 16 12 14 13
21
B=
53 56 52 54 53
mW =
25
vW = (22, 21, 25, 21)
13 16 12 14 13 21
1.- Si el tamaño prefijado excede el número de valores que se van a almacenar, esta-
mos reservando memoria para elementos que luego no se van a utilizar.
2.- Si, por el contrario, el tamaño prefijado es menor que el número de valores que
se van a utilizar, el programa dará un error de ejecución.
Para evitar estos inconvenientes, Fortran permite asignar memoria a ciertos arrays,
llamados dinámicos, en tiempo de ejecución. Es decir, durante la ejecución, por medio de
una sentencia, se especifican las dimensiones que va a tener el array y se reserva la cantidad
de memoria necesaria para el mismo, siempre que en ese momento haya espacio suficiente
en la memoria de cálculo del procesador. Si por razones del algoritmo es necesario variar
las dimensiones del array, primero se tiene que liberar el espacio de memoria que ocupa
actualmente, a través de otra sentencia especı́fica, y luego volver a reservar una nueva
cantidad de memoria. Una vez que se ha terminado de utilizar el array en el programa es
necesario liberar el espacio de memoria ocupado.
Todo array dinámico debe ser declarado con el atributo allocatable especificando
su rango pero dejando los lı́mites sin definir, para ello se puede utilizar o no el atributo
dimension.
Para reservar la cantidad de memoria necesaria para almacenar los valores de un
array dinámico se utiliza la sentencia allocate con la que se definen los lı́mites del array.
A partir de este momento podemos utilizar el array como un objeto compuesto más del
programa, recordando que en este punto todavı́a no está definido.
Para liberar la memoria reservada, se utiliza la sentencia deallocate.
Las sentencias allocate y deallocate tienen un especificador opcional denominado
stat cuyo valor debe cargarse en una variable de tipo integer. Si la reserva/liberación
de memoria se ha producido de modo correcto, el valor de stat es 0, en caso contrario es
positivo. En ausencia de este especificador, si el procesador no es capaz de ejecutar alguna
de las dos sentencias, el programa se interrumpe de forma brusca.
En la figura 7.2 se muestra un ejemplo de cómo se reserva (allocate) y se libera
(deallocate) memoria a lo largo de un programa.
program main
real , allocatable :: U (:)
real , allocatable :: A (: ,:)
integer :: n
integer :: m
integer :: Ierr
.
.
write (* ,*) ’ Introducir la dimension del vector ’
read (* ,*) n
program main
real , allocatable :: U (:)
integer :: n
integer :: NumCasos
integer :: i
integer :: Ierr
.
do i =1 , NumCasos
.
n =
allocate ( U ( n ) , stat = Ierr )
if ( Ierr > 0) stop "*** No se puede alocatar U ***"
.
deallocate (U , stat = Ierr )
if ( Ierr > 0) stop "*** U no estaba alocatado ***"
.
end do
end program main
Si en alguno de los casos resulta que n toma un valor no positivo, el programa sigue
funcionando con normalidad sin tener que haber añadido lı́neas de código extra.
Si se definen secciones de un array y en algún momento el lı́mite inferior especificado
para una dimensión supera al superior, el subarray resultante es de tamaño cero. Esto ocu-
rre en el siguiente ejemplo donde el lı́mite inferior de la sección está dado en función del
contador del bucle, i, de modo que cuando éste adquiere el valor n-1 la sección definida
es un array de tamaño cero.
program main
integer , parameter :: n = 20
real :: U ( n )
real :: a
integer :: i
.
do i =1 , n
.
U ( i +2: n ) = a *0.5
.
end do
end program main
No hay que confundir la situación anterior con el error que se comete cuando en una
sección se establece un lı́mite inferior o superior fuera del rango de los lı́mites establecidos
en la declaración del array.
program main
integer , parameter :: n = 20
real :: U ( n )
real :: a
integer :: i
.
do i =1 , n
.
U ( i : i +2) = a *0.5 ! cuando i =n -1 hay un error
.
end do
end program main
Se debe resaltar el hecho de que dos arrays de tamaño cero pueden tener el mismo
rango pero distinta forma, por ejemplo uno puede ser (0,2) y el otro (2,0), con lo que
no son conformes y, por tanto, no pueden ser operandos de la misma expresión. Al igual
que todo array, un array de tamaño cero es conforme con cualquier escalar.
dato_1 = dato_2
ambos datos deben ser del mismo tipo. En Fortran, de forma general, existe la posibilidad
de definir funciones y operadores. Esta posibilidad se puede extender al caso de operandos
de tipo derivado lo que amplı́a el conjunto de operaciones que se pueden realizar con ellos.
Sin embargo, este tipo de operaciones se sale del propósito del presente curso.
nombre_array ( i) % componente
mientras que para acceder al elemento j−ésimo de una componente del elemento i−ésimo
del array de estructuras, se utiliza la expresión
nombre_array ( i) % componente ( j )
program main
integer , parameter :: numnotas = 3
type alumno
character ( len =15) :: nombre
character ( len =30) :: apellidos
real :: nota ( numnotas )
real :: media
end type alumno
type ( alumno ) , allocatable :: clase (:)
integer :: n
integer :: i
integer :: Ierr
do i =1 , n
write (* ,*) ’ Nombre y apellidos del alumno ’, i
read (* ,*) clase ( i) %nombre , clase ( i) % apellidos
program main
type punto
real :: x
real :: y
real :: z
end type punto
type circulo
type ( punto ) :: centro
real :: radio
end type circulo
type ( punto ) :: P
type ( punto ) :: centro
type ( circulo ) :: c1
type ( circulo ) :: c2
type ( circulo ) :: c3
P %x = 1.0
P %y = 1.0
P %z = 1.0
c1 %centro %x = 1.0
c1 %centro %y = 2.0
c1 %centro %z = 3.0
c1 %radio = 25.0
Índice
8.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
8.2. Sentencias read y print básicas . . . . . . . . . . . . . . . . . . 99
8.3. Manejo de ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . 99
8.3.1. Sentencia open . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
8.3.2. Sentencias read y write . . . . . . . . . . . . . . . . . . . . . . 101
8.3.3. Sentencia close . . . . . . . . . . . . . . . . . . . . . . . . . . 103
8.4. Sentencias rewind y backspace . . . . . . . . . . . . . . . . . . . 103
8.5. Especificaciones de formato . . . . . . . . . . . . . . . . . . . . 104
8.5.1. Datos tipo integer . . . . . . . . . . . . . . . . . . . . . . . . 105
8.5.2. Datos tipo real en coma flotante . . . . . . . . . . . . . . . . . 105
8.5.3. Datos tipo real en forma exponencial . . . . . . . . . . . . . . 106
8.5.3.1. Formato estándar . . . . . . . . . . . . . . . . . . . . 106
8.5.3.2. Formato estándar ampliado . . . . . . . . . . . . . . . 107
8.5.3.3. Formato cientı́fico . . . . . . . . . . . . . . . . . . . . 108
8.5.4. Datos tipo character . . . . . . . . . . . . . . . . . . . . . . . 108
8.5.5. Datos tipo logical . . . . . . . . . . . . . . . . . . . . . . . . 109
8.6. Especificación de un formato . . . . . . . . . . . . . . . . . . . 110
8.7. Sentencia namelist . . . . . . . . . . . . . . . . . . . . . . . . . . 112
97
98 8.1 Introducción
8.1. Introducción
El objeto de las operaciones de entrada y salida es transferir o recibir datos desde un
medio externo (cinta, disco magnético u óptico, pantalla, teclado). La lectura de datos es
una operación de entrada y la escritura de datos es una operación de salida. Un registro es
un conjunto de datos compuesto por campos que constituyen las unidades de información
más pequeñas e indivisibles. Se denomina fichero a un conjunto de registros contenidos
en la misma unidad.
print * , lista_de_variables
read * , lista_de_variables
Si se desea dejar una lı́nea en blanco en la salida por pantalla, basta con poner
print *
unit=u
u es un dato simple o una constante entera positiva. A cada fichero se le asigna una
unidad que viene determinada por este número de forma que, a partir de este punto,
nos podemos referir al fichero en cuestión solo a través de su unidad sin tener que
especificar su nombre. Hay que tener en cuenta que,
file=nombre
nombre es el nombre del fichero que se va a abrir. El nombre se puede dar en forma
de constante literal o de dato de tipo character
status=estado
estado es una constante literal o un dato de tipo character que puede tomar
cualquiera de los siguientes valores:
action=accion
accion es una constante literal o un dato de tipo character que puede tomar
cualquiera de los siguientes valores:
read el fichero que vamos a abrir se va a utilizar exclusivamente para leer, por lo
que si se intenta utilizar para escribir, dará un error de compilación.
write el fichero que vamos a abrir se va a utilizar exclusivamente para escribir, por
lo que si se intenta utilizar para leer, dará un error de compilación.
readwrite el fichero que vamos a abrir se puede utilizar tanto para leer como para
escribir.
unit=u
u es un dato o una constante entera positiva que especifica el fichero del que se va
a leer o escribir
fmt=’(form1,form2,...)’
’(form1,form2,...)’ es la lista de formatos con los que se va a leer o escribir los
datos. En la mayorı́a de los casos, si no se conoce el formato o los datos no poseen
un formato fijo, se pone un asterisco (*). En la sección 8.5 se desarrolla con más
detalle el uso de los formatos. Aunque en esta descripción estamos dando la lista de
formatos como una constante literal de tipo character, también se puede utilizar
una variable del mismo tipo.
iostat=v
Es posible que mientras leemos o escribimos un fichero se produzca un error. Por
ejemplo, nos encontramos con un dato que no tiene el formato especificado, o el
fichero no tiene tantas filas como creı́amos, etc. También puede ocurrir que queramos
leer un fichero de datos del que ignoramos el número total de registros que contiene.
El argumento iostat sirve para controlar este tipo de incidencias. v es una variable
entera que puede tomar los siguientes valores: v>0 si detecta un error de lectura o
escritura, v<0 si se alcanza el final del fichero durante la lectura y v=0 si la ejecución
es correcta. Este argumento es opcional.
lista vbles
Es la lista de variables, separadas por comas, en las que se van a cargar los datos
que se van a leer, o cuyos valores se van a escribir.
• Si se desea leer un registro, vacı́o o no, sin asignar ninguno de sus campos a
variables del programa, basta con poner
read (u ,*)
write (u ,*)
unit=u
u es un dato o una constante entera positiva que especifica el fichero que se va a
cerrar
status=estado
estado es una constante literal o un dato de tipo character que puede tomar
cualquiera de los siguientes valores:
rewind ( unit = u )
rewind ( u )
backspace ( unit = u )
unit=u
u es un dato o una constante entera positiva que especifica la unidad del fichero
actual.
x = 3.0 x = 3.000
x = 3. x = 0.3 e +1
x = 3 e0 x = 3.0 e +0
x = 30 e -1 x = 30.0 e -1
Figura 8.1 Visualización del mismo fichero (a) sin formato y (b) con formato
(a) (b)
3.0 -0.145 2.34 3.000 -0.145 2.340
5.29 0. -7.893 5.290 0.000 -7.893
-1.333 8.54 9.32 -1.333 8.540 9.320
In [. m ]
• n es una constante entera positiva que indica el número total de espacios que ocupa
la representación del valor de la variable (incluyendo el signo “−”, si lo hubiera).
• m es una constante entera positiva (menor o igual que n) que indica el número total
de dı́gitos que aparecen en la representación del valor de la variable (sin incluir el
signo “−”, si lo hubiera). Para completar el número de dı́gitos especificado rellena
con ceros a la izquierda. Este descriptor es opcional.
Fn . d
• n es una constante entera positiva que indica el número total de espacios que ocupa
la representación del valor de la variable (incluyendo el signo “−”, si lo hubiera, y
el punto “.”).
• d es una constante entera no negativa que indica el número total de decimales que
van a aparecer, tras redondear.
Especificación
En . d
• n es una constante entera positiva que indica el número total de espacios que ocupa
la representación del valor de la variable, incluyendo
• d es una constante entera no negativa que indica el número total de decimales que
van a aparecer, tras redondear.
Este formato no es válido para exponentes con valor absoluto mayor que 999.
Especificación
En . dEm
• n es una constante entera positiva que indica el número total de espacios que ocupa
la representación del valor de la variable, incluyendo
• d es una constante entera no negativa que indica el número total de decimales que
van a aparecer, tras redondear.
• m es una constante entera no negativa que indica el número total de dı́gitos que van
a aparecer en la exponencial.
Especificación
ESn . d [ Em ]
Su uso es idéntico al del formato estándar o estándar ampliado, excepto que
1 ≤ |mantisa| < 10
A[n]
• n es una constante entera positiva que indica el número total de espacios que ocupa
la representación del valor de la variable.
L[n]
• n es un entero positivo que indica el número total de espacios que ocupa la repre-
sentación del valor de la variable. En cualquier caso, la salida será o bien una T si
el valor de la variable es .true. o bien una F si el valor de la variable es .false.
siendo form1,form2,... los formatos de representación de las variables junto con posibles
formatos especiales, separados por comas.
Entre los formatos especiales destacamos los siguientes
Es muy importante tener en cuenta que n debe ser una constante literal entera
positiva, nunca el identificador de un dato. Sin embargo n puede ser mayor que el número
de datos que va a leer o escribir.
Otra forma de especificar el formato utiliza una variable de tipo character que
almacena la lista de formatos.
Vamos a ver un ejemplo. Tenemos un fichero de texto (d in.dat) con los siguientes
datos,
3 4
1.5 0.023 -1.2 24.5
1E-3 4.33 15. 0.
32. .24 -100. 10.0
Queremos leer este fichero y copiarlo en otro (d out.dat) de forma que todas las
variables reales tengan el mismo formato.
program fichero
implicit none
integer :: n , m
integer :: i
integer :: unitID
real , allocatable :: A (: ,:)
unitID = 15
open ( unit = unitID , file = ’ d_in . dat ’ , status = ’ old ’ , action = ’ read ’)
allocate ( A (n , m ))
do i =1 , n
read ( unitID ,*) A (i ,:)
end do
close ( unitID )
open ( unit = unitID , file = ’ d_out . dat ’ , status = ’ unknown ’ , action = ’ write ’)
deallocate ( A )
end program fichero
3 4
1.500 0.023 -1.200 24.500
0.001 4.330 15.000 0.000
32.000 0.240 -100.000 10.000
& nombre_del_namelist
nombre_variable1 = valor_variable1
nombre_variable2 = valor_variable2
.
nombre_variableN = valor_variableN /
◦ La declaración, tanto de las variables del namelist como del propio namelist,
se realiza dentro del cuerpo de declaraciones de la unidad de programa que lo
utiliza.
• Para leer los valores de las variables del namelist dentro de la unidad de programa
que lo utiliza, la secuencia es la siguiente
• A lo largo de la ejecución del programa es posible que alguna de las variables defi-
nidas en el namelist cambie su valor. Para actualizar los valores de las variables en
el propio fichero namelist la secuencia es la siguiente
&Tiempo
horas = 12
minutos = 30
segundos = 15
am pm = ’PM’ /
program main
integer :: horas
integer :: minutos
integer :: segundos
character ( len =2) :: am_pm
namelist / Tiempo / horas , minutos , segundos , am_pm
.
open (15 , file = ’ datos . dat ’)
read (15 , Tiempo )
.
write (15 , Tiempo )
.
close (15)
Índice
9.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
9.2. Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
9.3. Subrutinas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
9.4. Tratamiento de argumentos . . . . . . . . . . . . . . . . . . . . 126
9.4.1. El atributo intent . . . . . . . . . . . . . . . . . . . . . . . . . 127
9.4.2. Asociación de argumentos . . . . . . . . . . . . . . . . . . . . . 128
9.4.3. Argumentos tipo character . . . . . . . . . . . . . . . . . . . . 131
9.4.4. Argumentos tipo array . . . . . . . . . . . . . . . . . . . . . . . 131
9.4.5. Argumentos tipo subprograma . . . . . . . . . . . . . . . . . . 136
9.5. Array como resultado de una función . . . . . . . . . . . . . . 139
9.6. Variables locales . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
9.7. Tipos de subprogramas . . . . . . . . . . . . . . . . . . . . . . . 143
9.8. Subprograma interno . . . . . . . . . . . . . . . . . . . . . . . . 147
9.9. Subprograma module . . . . . . . . . . . . . . . . . . . . . . . . 149
115
116 9.1 Introducción
9.1. Introducción
La programación modular es una técnica de programación que consiste en dividir un
programa en partes bien diferenciadas, llamadas unidades de programa, que pueden ser
analizadas y programadas por separado. Se distinguen tres tipos de unidades de programa:
programa principal, función y subrutina. A estos dos últimos también se les llama de forma
genérica subprogramas.
Una unidad de programa se puede definir como un conjunto de instrucciones lógi-
camente enlazadas. A cada unidad de programa se le asigna un nombre, elegido por el
programador, para poder identificarlo. Cuando en un punto de una unidad de programa
se llama a ejecutar un subprograma, dicha unidad le cede el control para que se ejecuten
todas sus instrucciones. Finalizado el mismo, el control se devuelve al punto de la unidad
de programa llamadora, y se continúa con la ejecución de la instrucción siguiente a la que
realizó la llamada. El orden de ejecución se muestra en las figuras 9.1 y 9.2.
• Solo puede existir una unidad de programa principal, llamado programa principal,
que es el encargado de controlar y relacionar a todos los demás. Esta unidad de
programa debe indicar la solución completa del problema.
• Cada unidad de programa solo puede tener un punto de entrada y otro de salida.
• Una unidad de programa debe representar por sı́ misma una estructura lógica cohe-
rente y resolver una parte bien definida del problema.
' $
program nombre
& %
? ' $ ' $
q q q
? ? ?
q q q
? ' ? $' ? $
q
?
q
' ? $
• Los programas son más sencillos de escribir y depurar, pues se pueden hacer pruebas
parciales con cada una de sus unidades de programa.
• Un programa se puede ampliar fácilmente con solo diseñar las nuevas unidades de
programa necesarias.
• Un subprograma puede ser llamado varias veces desde la misma unidad de programa,
evitando la repetición de instrucciones ya escritas.
• Subprogramas externos
Son aquellos cuya definición se encuentra fuera del cuerpo de cualquier otra unidad
de programa, tal y como se muestra en la figura 9.2
• Subprogramas internos
Son aquellos cuya definición se encuentra dentro de una unidad de programa
• Subprogramas module
Son aquellos cuya definición se encuentra dentro de un unidad module
9.2. Funciones
Una función es un subprograma que, indicándole desde la unidad de programa lla-
madora los datos de entrada (argumentos) con los que se desea que realice los cálculos,
devuelve un único resultado.
Para entender este concepto pensemos en el caso más sencillo: las funciones intrı́nse-
cas con un único argumento. Por ejemplo, en el programa
program main
real :: x
real :: y
if ( y >= 0) then
x = abs ( x )
else
x = - abs ( x )
end if
write (* ,*) x
end program main
estamos llamando a la función abs con la variable x del programa principal de la que
queremos conocer su valor absoluto. Una vez ejecutada la función, ésta devuelve un único
resultado al programa, el valor absoluto del dato de entrada, que en este ejemplo se utiliza
para asignarlo a la variable x.
Imaginemos ahora que no existe la función intrı́nseca abs y, dada la utilidad de la
misma, queremos crearla nosotros. Para ello programamos una función, que trataremos
como subprograma externo, y escribimos el siguiente código (definición de la función)
Como el programa principal, única unidad de programa conocida hasta este capı́tulo,
la estructura general de un subprograma función consta de (Fig. 9.4)
1 function valor_abs ( x )
2 real , intent ( in ) :: x
3 real :: valor_abs
4
5 valor_abs = x
6 if ( valor_abs < 0.0) valor_abs = - valor_abs
7
• Las sentencias de ejecución, entre las que siempre tiene que aparecer la sentencia
que define el resultado de la función.
program main
interface
function valor_abs ( x )
real , intent ( in ) :: x
real :: valor_abs
end function valor_abs
end interface
real :: x
real :: y
interface
cuerpo_de_interface
end interface
2. Declaración de los argumentos y del tipo de resultado por tratarse de una función.
function transf_signo (a , b )
real , intent ( in ) :: a
real , intent ( in ) :: b
real :: transf_signo
if ( b >= 0) then
transf_signo = abs ( a )
else
transf_signo = - abs ( a )
end if
end function transf_signo
program main
interface
function transf_signo (a , b )
real , intent ( in ) :: a
real , intent ( in ) :: b
real :: transf_signo
end function transf_signo
end interface
real :: x
real :: y
x = transf_signo (x , y )
write (* ,*) x
end program main
9.3. Subrutinas
Una subrutina es un subprograma que, indicándole desde la unidad de programa
llamadora los datos de entrada con los que se desea que realice los cálculos, proporciona
un conjunto de datos de salida a dicha unidad de programa. Tanto los datos de entrada
como los de salida constituyen los argumentos ficticios de una subrutina.
En la figura 9.8 se muestra la definición de una subrutina que, dado un ángulo en
radianes (argumento de entrada: theta), calcula los correspondientes grados, minutos y
segundos (argumentos de salida: deg, min, sec).
7 real :: pi
8 real :: resto
9
10 pi = acos ( -1.0)
11
2. Los argumentos deg, min y sec están declarados con el atributo intent(out)
que indica que son datos de salida del subprograma y, por tanto, no pueden
ser utilizados en el subprograma hasta que no se les asigne un valor dentro del
mismo.
En las lı́neas 7 y 8 se declaran las variables locales del subprograma. Como su nombre
indica se trata de datos que solo conoce este subprograma subroutine y que son
necesarios para la realización de los cálculos que en él se definen. Su funcionamiento
dentro del subprograma es el propio del de cualquier dato de su tipo que hemos
estudiado.
• Las sentencias de ejecución, entre las que siempre tienen que aparecer la sen-
tencias que definen los argumentos ficticios de salida declarados con el atributo
intent(out).
program main
interface
subroutine conversion ( theta , deg , min , sec )
real , intent ( in ) :: theta
real , intent ( out ) :: deg
real , intent ( out ) :: min
real , intent ( out ) :: sec
end subroutine conversion
end interface
real :: angle
real :: deg
real :: min
real :: sec
llamadora. Mención especial merecen los argumentos de tipo array, los de tipo derivado
y el uso de subprogramas como argumentos. En esta sección nos dedicaremos a abordar
en detalle estas cuestiones.
• intent(in)
Los argumentos declarados con este atributo no pueden modificar su valor dentro
del subprograma. Si en algún momento apareciera una sentencia de asignación que
intentara modificar su valor, se producirı́a un error en tiempo de compilación.
• intent(out)
Los argumentos declarados con este atributo no pueden ser utilizados dentro del
subprograma hasta que no se les asigne un valor dentro del mismo, aunque sus
correspondientes argumentos verdaderos estuviesen definidos en la unidad de pro-
grama llamadora. Si esto ocurriese, darı́a un error en tiempo de compilación.
• intent(inout)
Los argumentos declarados con este atributo tienen un valor a la entrada al subpro-
grama que puede ser modificado a lo largo del mismo, cambio que se refleja en sus
correspondientes argumentos verdaderos.
sido declarado como argumento solo de entrada. El segundo error se produce al intervenir
el dato c en una operación sin que esté previamente definido, lo que se debı́a haber hecho
por estar declarado con el atributo intent(out). El argumento b es de entrada y salida
luego su correspondiente argumento verdadero modifica el valor que tenı́a antes de la
llamada, por el valor resultante de los cálculos realizados en el subprograma.
subroutine ejemplo (a , b , c )
real , intent ( in ) :: a
real , intent ( inout ) :: b
real , intent ( out ) :: c
program main
interface
subroutine suma (a , b , total )
real , intent ( in ) , optional :: a
real , intent ( in ) , optional :: b
real , intent ( out ) :: total
end subroutine suma
end interface
real :: a = 2.0
real :: b = 5.0
real :: total
subroutine explicita ( Ma , U )
real , intent ( in ) :: Ma (2 ,2)
real , intent ( in ) :: U (5)
.
end subroutine explicita
1 program main
2 real :: A (2 ,2)
3 real :: B (2 ,3)
4 real :: z (5)
5 real :: t (6)
6 .
7 A = reshape ((/11 , 12 , 13 , 14/) , (/2 ,2/))
8 B = reshape ((/21 , 22 , 23 , 24 , 25 , 26/) , (/2 ,3/))
9 z = (/41 , 42 , 43 , 44 , 45/)
10 t = (/51 , 52 , 53 , 54 , 55 , 56/)
11
12 call explicita ( Ma =A , U = z )
13 call explicita ( Ma =B , U = t )
14 call explicita ( Ma = B (2 ,1) , U = t (2))
15 call explicita ( Ma =t , U = B )
16 call explicita ( Ma = B (2 ,2) , U = t (4))
17
En el ejemplo representado por las figuras 9.13 y 9.14, el programa principal define
los vectores y matrices
z = 41, 42, 43, 44, 45 ! !
11 13 21 23 25
A= B=
12 14 22 24 26
t= 51, 52, 53, 54, 55, 56
mientras que la subrutina siempre recoge una matriz Ma(2,2) y un vector U(5).
• En la llamada de la lı́nea 12
!
11 13
Ma = U= 41, 42, 43, 44, 45
12 14
• En la llamada de la lı́nea 13
!
21 23
Ma = U= 51, 52, 53, 54, 55
22 24
• En la llamada de la lı́nea 14
!
22 24
Ma = U= 52, 53, 54, 55, 56
23 25
• En la llamada de la lı́nea 15
!
51 53
Ma = U= 21, 22, 23, 24, 25
52 54
• En la llamada de la lı́nea 16
!
24 26
Ma = U= 54, 55, 56, 79, 85
25 −500
Un método más flexible de trabajar con argumentos con forma explı́cita consiste en
introducir las dimensiones como argumentos de entrada al subprograma, de esta forma el
argumento ficticio se adapta fácilmente a la forma del argumento verdadero (Figs. 9.15 y
9.16)
program main
integer , parameter :: n = 2
integer , parameter :: m = 3
real :: A (n , n )
real :: B (n , m )
real :: z (5)
real :: t (6)
.
A = reshape ((/11 , 12 , 13 , 14/) , (/2 ,2/))
B = reshape ((/21 , 22 , 23 , 24 , 25 , 26/) , (/2 ,3/))
z = (/41 , 42 , 43 , 44 , 45/)
t = (/51 , 52 , 53 , 54 , 55 , 56/)
subroutine asumida (M , U )
real , intent ( in ) :: M (: ,:)
real , intent ( in ) :: U (:)
.
end subroutine asumida
1 program main
2 real :: A (2 ,2)
3 real :: B (2 ,3)
4 real :: z (5)
5 real :: t (6)
6 .
7 A = reshape ((/11 , 12 , 13 , 14/) , (/2 ,2/))
8 B = reshape ((/21 , 22 , 23 , 24 , 25 , 26/) , (/2 ,3/))
9 z = (/41 , 42 , 43 , 44 , 45/)
10 t = (/51 , 52 , 53 , 54 , 55 , 56/)
11
12 call asumida ( M =A , U = z )
13 call asumida ( M =B , U = t )
14 call asumida ( M = B (1:2 ,2:3) , U = t (2:4))
15 call asumida ( M = B (1:2 ,2:2) , U = t ((/1 ,3/)))
16
En el ejemplo representado por las figuras 9.17 y 9.18, el programa principal define
los vectores y matrices
z = 41, 42, 43, 44, 45 ! !
11 13 21 23 25
A= B=
12 14 22 24 26
t= 51, 52, 53, 54, 55, 56
function F ( x )
real , intent ( in ) :: x
real :: F
F = x * x + 3.0
end function F
function G ( x )
real , intent ( in ) :: x
real :: G
G = x * x - cos ( x )
end function G
1 program main
2 interface
3 function F ( x )
4 real , intent ( in ) :: x
5 real :: F
6 end function F
7 end interface
8 interface
9 function G ( x )
10 real , intent ( in ) :: x
11 real :: G
12 end function G
13 end interface
14 interface
15 subroutine trapecio (F , a , b , integral )
16 interface
17 function F ( x )
18 real , intent ( in ) :: x
19 real :: F
20 end function F
21 end interface
22 real , intent ( in ) :: a
23 real , intent ( in ) :: b
24 real , intent ( out ) :: integral
25 end subroutine trapecio
26 end interface
27
28 real :: IntegralF
29 real :: IntegralG
30 real :: a
31 real :: b
32 .
33 a = 0.0
34 b = 5.0
35 call trapecio (F , a , b , IntegralF )
36 .
37 b = pi
38 call trapecio (G , a , b , IntegralG )
39 end program main
function F (n , x )
integer , intent ( in ) :: n
real , intent ( in ) :: x
real , dimension ( n ) :: F
integer :: i
do i =1 , n
F ( i ) = x ** i
end do
end function F
function Forz ( x )
real , intent ( in ) :: x (:)
real , dimension ( size ( x )) :: Forz
integer :: i
do i =1 , size ( x )
Forz ( i ) = x ( i )* x ( i )
end do
function Normaliza ( A )
real , intent ( in ) :: A (: ,:)
real , dimension ( size (A ,1) , size (A ,2)) :: Normaliza
real :: maximo
maximo = maxval ( A )
Normaliza = 0.0
if ( maximo /= 0.0) Normaliza = A / maximo
program main
interface
function F (n , x )
integer , intent ( in ) :: n
real , intent ( in ) :: x
real , dimension ( n ) :: F
end function F
end interface
interface
function Forz ( x )
real , intent ( in ) :: x (:)
real , dimension ( size ( x )) :: Forz
end function Forz
end interface
interface
function Normaliza ( A )
real , intent ( in ) :: A (: ,:)
real , dimension ( size (A ,1) , size (A ,2)) :: Normaliza
end function Normaliza
end interface
integer , parameter :: n =2
real :: x
real :: U ( n + n )
real :: A (n , n )
real :: AN (n , n )
x = 5.0
U = F (n , x )
U = Forz ( U )
A = reshape (U , (/2 ,2/))
AN = Normaliza ( A )
end program main
subroutine llamadas
integer , save :: NLLamadas = 0
integer :: Nl
NumeroLLamadas = NumeroLLamadas + 1
Nl = 0
Nl = Nl + 1
write (* , ’(2( a , I2 ,2 x )) ’) ’ NLLamadas = ’, NLLamadas , ’ Nl = ’, Nl
end subroutine llamadas
program main
interface
subroutine llamadas
end subroutine llamadas
end interface
integer :: i
do i =1 ,5
call llamadas
end do
end program main
NLLamadas = 1 Nl = 1
NLLamadas = 2 Nl = 1
NLLamadas = 3 Nl = 1
Subprograma externo
Un subprograma, function o subroutine, externo se caracteriza por las dos pro-
piedades:
Las figura 9.25 muestra un esquema de los puntos descritos anteriormente. Varios
subprogramas externos y un programa principal que los utiliza.
El uso habitual de este tipo de esquemas está limitado al caso sencillo en el que un
programa principal necesita a lo largo de su ejecución tan solo uno o dos subprogramas
que, bien porque son muy largos o bien porque se han extraı́do de alguna librerı́a, se
mantienen en ficheros independientes. Esto obliga a declarados explı́citamente con una
interface. Evidentemente, tener un programa con, exagerando un poco, 200 lı́neas de
interface, no es precisamente lo que se entiende por un programa claro y compacto.
Tampoco es muy habitual ver programas con varias interfaces anidadas. De nuevo,
la razón es la claridad en el estilo de programación.
function/subroutine nombre#1
..
.
end function/subroutine nombre#1
..
.
function/subroutine nombre#r
..
.
end function/subroutine nombre#r
program nombre
interface
function/subroutine
.. nombre#1
.
end function/subroutine nombre#1
end interface ..
.
interface
function/subroutine nombre#r
..
.
end function/subroutine nombre#r
end interface ..
.
end program nombre
Subprograma interno
Un subprograma, function o subroutine, interno se caracteriza por las tres pro-
piedades:
1. Se encuentra dentro del esquema program — end program
2. Se encuentra justo antes de la sentencia end program
3. Se encuentra justo después de la sentencia contains
Las figura 9.26 muestra un esquema de los puntos descritos anteriormente. Varios
subprogramas internos contenidos en un programa principal.
El uso habitual de este tipo de esquemas está limitado al caso, también sencillo en el
que un programa principal necesita a lo largo de su ejecución unos pocos subprogramas,
todos ellos cortos en extensión y que probablemente estén relacionados entre sı́, en el
sentido de que algunos de ellos contengan llamadas a otros subprogramas del mismo
contains.
program nombre
..
.
contains
function/subroutine nombre#1
..
.
end function/subroutine nombre#1
..
.
function/subroutine nombre#r
..
.
end function/subroutine nombre#r
end program nombre
Subprograma module
Un subprograma module, function o subroutine, se caracteriza por las cuatro
propiedades:
Las figura 9.27 muestra un esquema de los puntos descritos anteriormente. Varios
subprogramas contenidos en un module y un programa principal que los utiliza.
El uso habitual de este tipo de esquemas se observa en los grandes programas que,
para resolver un problema importante deben resolver antes varios problemas intermedios.
La idea de este paradigma de programación consiste en manejar varios modules, cada uno
de ellos asociado a un problema completo en cuestión.
Un primer vistazo a los esquemas presentados revela las diferencias entre un sub-
programa externo y otro de tipo interno o module.
module nombre_module
..
.
contains
function/subroutine nombre#1
..
.
end function/subroutine nombre#1
..
.
function/subroutine nombre#r
..
.
end function/subroutine nombre#r
end module nombre_module
program nombre_program
use nombre_module
..
.
end program nombre_program
integer :: nombre_variable
para declarar una function externa de tipo real de una variable real utilizamos el es-
quema
interface
function nombre_funcion ( arg )
real , intent ( in ) :: arg
real :: nombre_funcion
end function nombre_funcion
end interface
Sin embargo, si el subprograma es interno, el hecho de estar fı́sicamente en el mismo
fichero que el programa llamador y dentro de un contains, basta para que el llama-
Variables locales
Son todas aquellas declaradas en los subprogramas internos que no son argumentos
ficticios. Una variable local solo es accesible para el propio subprograma interno que
lo contiene. Las variables locales de la figura 9.28 son:
• Para la función f, las variables i (lı́nea 18), z (lı́nea 19) y t (lı́nea 20)
• Para la función g, las variables i (lı́nea 29) y r (lı́nea 30)
Variables globales
Son todas aquellas declaradas en el programa principal. Una variable global es ac-
cesible, además de para el propio programa principal, para cualquier subprograma
interno a él siempre que no contenga una variable local con el mismo nombre. Las
variables globales de la figura 9.28 son: a, b, i, z, zf, zg (lı́neas 2 – 7)
1 program main
2 real :: a
3 real :: b
4 integer :: i
5 real :: z
6 real :: zf
7 real :: zg
8 .
9 zf = f ( a )
10 .
11 zg = g (a , b )
12 .
13 contains
14 function f ( x )
15 real , intent ( in ) :: x
16 real :: f
17
18 integer :: i
19 real :: z
20 real :: t
21 .
22 end function f
23
24 function g (x , y )
25 real , intent ( in ) :: x
26 real , intent ( in ) :: y
27 real :: g
28
29 integer :: i
30 real :: r
31 .
32 end function g
33 end program main
Variables locales
Son todas aquellas variables declaradas en los subprogramas que no son argumentos
ficticios. Una variable local solo es accesible para el propio subprograma que lo
contiene.
Variables globales
Son todas aquellas variables declaradas antes de la sentencia contains, considerada
como zona de declaración del module. Una variable global es accesible para cualquier
subprograma contenido en el module siempre que él mismo no contenga una variable
local con el mismo nombre.
use nombre_del_module
module CalculoMatrices
type sistema
real :: A (10 ,10)
real :: b (10)
real :: x (10)
end type sistema
contains
subroutine inversa (A , Ai )
real , intent ( in ) :: A (: ,:)
real , intent ( out ) :: Ai (: ,:)
real :: determ
.
call determinante ( A =A , det = determ )
.
end subroutine inversa
subroutine resuelve (A , b , x )
real , intent ( in ) :: A (: ,:)
real , intent ( in ) :: b (:)
real , intent ( out ) :: x (:)
type ( sistema ) :: Sistem10
.
end subroutine resuelve
end module CalculoMatrices
Figura 9.30
program main
use CalculoMatrices
integer , parameter :: n = 2
real :: A (n , n )
real :: InvA (n , n )
real :: detA
real , allocatable :: mA (: ,:)
type ( sistema ) :: Sist20
.
call inversa ( A =A , Ai = InvA )
.
call determinante ( A =A , det = detA )
.
allocate ( mA ( dimA , dimA ))
.
end program main
Figura 9.31
program main
use CalculoMatrices , only : inversa , dimA
real :: A ( dimA , dimA )
real :: InvA ( dimA , dimA )
.
call inversa ( A =A , Ai = InvA )
.
end program main
module metodos
implicit none
contains
module funciones
implicit none
contains
function F ( x )
real , intent ( in ) :: x
real :: F
F = x * x + 3.0
end function F
function G ( x )
real , intent ( in ) :: x
real :: G
G = x * x - cos ( x )
end function G
program main
use funciones
use metodos
implict none
155
156
Bibliografı́a
B
[ 1 ] Adams J.C., Brainerd W.S., Martin J.T., Smith B.T., Wagener J.N. Fortran 90
Handbook. Complete ANSI/ISO Reference. McGraw-Hill, 1992
[ 2 ] Ellis T.M.R., Philips I.R., Lahey T.M. Fortran 90 programing. Addison-Wesley, 1994
[ 4 ] Metcalf M., Reid J., Cohen M. Fortran 95/2003 explained. Oxford University Press,
2004
[ 5 ] Nyhoff L.R., Leestma S.F. Fortran 90 for engineers & scientists. Prentice Hall, 1997
157