Departamento de Ingeniería Mecánica y Mecatrónica
Modelación matemática
Sem I - 2014
GUIA RAPIDA PARA EL USO DE FORTRAN
1. Introducción
El objetivo del presente documento es proporcionar una guía rapida para el uso de Fortran 90/95, para los estudiantes de Modelación Matemática de la Universidad Nacional de Colombia. El documento está basado en un curso virtual de la Universidad de Warwick (UK) 1
. No pretende ser una referencia completa, y por lo tanto cuando se requiera mayor claridad sobre cualquier tópico particular se debe consultar la respectiva bibliografía especializada.
Fortran es un lenguaje de propósito general, pero principalmente orientado a la computación científica. Su principal fortaleza se centra en la realización eficiente de cálculos matemáticos y numéricos para uso y aplicación en diferentes áreas de la ciencia y la ingeniería. Fortran es un acrónimo de FORmula TRANslator, originalmente escrito simplemente como FORTRAN. Fortran fué uno de los primeros lenguajes de programación de alto nivel. El desarrollo de Fortran empieza en la década de 1950 en IBM y han habido varias versiones desde entonces. Por convención, y como medio de identificación, las versiones de Fortran se distinguen por los dos últimos dígitos del año en que se propuso la estandarización respectiva. De esta forma se tienen:
Fortran 66 Fortran 77 Fortran 90 (95) Fortran 2000
Fortran es un lenguaje de programación dominante usado en muchas aplicaciones de ingeniería y mate-máticas, por lo que es importante que se tengan bases para poder leer y modificar cualquier código de Fortran. Algunas opiniones de expertos han dicho que Fortran será un lenguaje que pronto decaerá en popularidad y se extinguirá, lo que no ha sucedido todavía. Una de las razones para esta supervivencia es la inercia del software, ya que una vez que una compañía ha gastado muchos millones de dólares y de años en el desarrollo de software, no le es conveniente traducir el software a un lenguaje diferente, por el costo que implica y por ser una tarea difícil y laboriosa.
1
2. Formato de Código
La estructura básica de un programa en Fortran 90 (F90) con módulos y funciones2
definidas como unidades internas y dentro del mismo archivo fuente, se indica en la siguiente esquema:
Código ejemplo
module1 module2
program nameOfProgram use module1
use module2
implicit none
constant/variable declarations parameter declarations
data declarations
body of program
contains function1 function2
end program nameOfProgram
La estructura general de un módulo (llamado en el siguiente ejemplo moduloA) corresponde al código presentado a continuación:
Código ejemplo
module moduloA (parametros)
local variable declarations
contains
body of function code
end module moduloA
La estructura de una función es muy similar, pero no incluirá declaraciones del tipo contains. En tal caso sólo se reemplaza la palabra reservada module por function.
2
2.1. Nuestro primer código.
Hello World
A continuación encontrará el primer código trivial a realizar usando Fortran. Este código incluye una salida a la terminal. Usando un editor de texto cree un archivo nuevo llamadohello.f90, y a continuación escriba el siguiente texto,
program hello
implicit none
! Este es un comentario
! Este programa escribe "hello world" en la terminal
print*, "hello world!"
end program hello
Una vez escrito el anterior texto, guarde el archivo y cierre el editor.
El archivo anterior es simplemente el código fuente. Ahora se debe compilar este código usando otro programa denominado compilador. En el prompt de su terminal de trabajo escriba:
user@prompt:$ ifort hello.f90 -o hello
Si no existe ningún error, se creará un archivo ejecutable llamadohello. Este archivo binario, o ejecutable, está listo para ser ejecutado desde la terminal. Para ejecutarlo escriba en el prompt de su terminal:
user@prompt:$ ./hello
Notas sobre nuestro primer código:
La primer línea determina el inicio del programa, y define el nombre del mismo. En éste caso el nombre del programa es hello
La segunda línea indica que usted quiere declarar explícitamente el tipo de todas y cada una de las variables o constantes. De lo contrario, usted está dejando al compilador decidir por usted el tipo de variable o constante.
La inclusión de comentarios es importante entodocódigo. En Fortran (F90) los comentarios van precedidos por un signo de exclamación (!). Adquiera el hábito de escribir comentarios útiles en su código.
Cada declaración de una línea en F90 esta limitada a 132 caracteres en total. Para continuar una línea, use un ampersand (&) al final de la linea, y con la nueva línea apareciendo directamente debajo de la que se está continuando. La excepción es cuando se está dividiendo una cadena de caracteres, en cuyo caso se debe comenzar la siguiente línea con un ampersand también.
3. Variables y constantes
3.1. Tipos de datos
Para declarar constantes o variables en F90, se debe declarar eltipode variable. En F90 solo hay cuatro tipos básicos de variables, as saber:
Tipo dato Ejemplo
En F90 las variables deben ser declaradas en el código antes de ser usadas. La sintaxis de declaración empieza con el tipo, seguido del símbolo ::, y a continuación por una lista de una o más variables, cada una separada por una coma. Ejemplo:
Código ejemplo
integer :: big,small,medium
Esta sentencia declara tres variables del tipo entero, llamadas "big", "small", y "medium".
Existen restricciones en los nombres que se pueden usar para declarar variables en F90: Nombres de variables deberán siempre empezar con una letra del alfabeto.
Sólo en el caso de nombres de archivo o links en linux, puede haber un espacio en el nombre de las variables. En F90 los nombres de variables NO pueden tener espacios, pero se puede usar el guion bajo (underscore).
Evite el uso de caracteres especiales.
F90 no distingue entre mayúsculas y minúsculas, así que los nombres de variables ELEMENT, Element y element harán referencia a la misma variable.
Las variables tambieén pueden tener asignados valores por defecto al tiempo de su declaración, sólo use un signo igual en este caso, ejemplo:
real :: element = 1.3E2
character(len=12) :: string = ’skywalker’
Si se requiere, espacios en blanco pueden será preservados dentro de una cadena limitada por comillas.
Definiciones tipo parametersiguen un patron similar, ejemplo:
real, parameter :: pi = 3.14159
Las variables tipoparameteralmacenan el valor definido en la inicialización, y este valor NUNCA podrá ser cambiado dentro del programa. Piense en estas variables como parámetros constantes de su programa.
Si se declara una variable sin asignar de inmediato un valor a la misma, siempre se puede asignar su valor más adelante en el código. La instrucción de asignación es un signo de igual (=), de forma que el valor de la derecha del signo de igualdad se almacenará en la variable presentada a la izquierda del signo igual.
Ejemplo de práctica
En el siguiente ejemplo, edite el código existente para incluir algunas declaraciones. Siga como ejemplo el siguiente código:
program hello
implicit none
integer :: special
character(len=12) :: name = ’organa’
special = 5
! print out your variables/constants
print*,special
print*
print*,name
end program hello
Asegurese que su código está compilando correctamente, e imprimiendo el valor adecuado en la pantalla de la terminal.
Palabras reservadas:
Usted debe asegurarse de que ninguno de sus nombres de variables o constantes sean textos como integer, real, character, etc. Claramente estos son palabras reservadas en F90 y tienen un pro-pósito especial.
4. Entrada y salida
4.1. Salida de datos
Usted ya habrá visto cómo podemos hacer que F90 obtenga una salida de información en formato libre, usando print. La sintaxis de la sentencia print es la siguiente:
Código ejemplo
print*, your_data
Usted ya ha visto en uno de los ejemplos anteriores que para imprimir un texto más el valor de una variable entera, había que incluir una línea como: print*,special.
Ejemplo de práctica
Suponga que usted desea imprimir cuatro variables reales en una línea, pero presentando cada número con 4 posiciones decimales. Si se tratara de imprimir tales n´humeros usando la instrucción de formato de impresión libre (por ejemplo, véase el fragmento de código más adelante) Qué pasa?
Código ejemplo
a1 = 5.67893454 a2 = 4.65124454 a3 = 10.2342454 a4 = 539.40405324 print*,a1,a2,a3,a4
Aunque la salida se ve ordenada, vale la pena notar que cada entrada ocupa 8 espacios, con diferente número de decimales.
Puede cambiar esta presentación utilizando una instrucción de formato. Para ilustrar esto, pruebe el siguiente fragmento de código:
Código ejemplo
Note que cuando se le dá formato a la salida, la sentenciawrite se utiliza en lugar deprint. Debería también notar que print/write enviara una salida de forma estándar, es decir a la términal X, o a un archivo si ha redireccionado la salida.
Si quiere enviar los datos de salida a un archivo específico, tiene que hacer pocos cambios en su código (esto se indicará más adelante).
La instrucción format en el ejercicio anterior contiene entradas llamadas descriptores de edición (edit descriptors). Los descriptores de edición en este ejemplo imprimirán cada número usando un total de 10 espacios, pero con 4 decimales c/u. Los descriptores de edición en esta declaración de formato contienen repetición. En este caso se podría escribir la instrucción format de manera más compacta como:
Código ejemplo
3 format(4f10.5)
4.2. Ingreso/entrada de datos
En F90 existen comandos que son la contraparte a los previamente discutidos print/write. Uno de ellos es read, el cual puede ser usado para leer o adquirir datos, bien sea desde la terminal o desde un archivo.
En los siguientes ejemplos consideraremos la lectura de datos desde la entrada estándar (es decir, mediante teclado en la terminal o desde algún archivo de datos usando re-direccionamiento). Este comando puede operar usando formato libre o formato definido (como en los casos anteriores). La sintaxis general del formato libre de lectura read es el siguiente:
Código ejemplo
! Esta código de ejemplo permite la lectura desde terminal ! sin ningún formato definido, es decir en formato libre read*, your_data
Ejemplo de práctica
program getname
implicit none
character(len=100) :: name
! Solicite ingreso del nombre desde la terminal
print*,"please enter your name at the prompt"
! Adquiera el texto ingresado
read*,name
! Imprima el texto ingresado en la terminal
print*,"your name is ",name
end program getname
Compile y corra este código como se indicó anteriormente (use ifort o gfort, según el compilador disponible en su sistema). Qué pasa si se escribe un nombre con un espacio? Qué pasa si escribe este nombre entre comillas?
Al igual que con la instrucción write, la instrucción read puede ser modificada para leer datos con formato. Los descriptores de formato para el comandoreadson muy similares a los del comandowrite, y pueden ser consultados en cualquier guía o libro de F90.
La forma en la que se puedenobtener datos de entrada desde óenviar datos de salida hacia un archivo específico (en lugar de la interacción con teclado a través de la terminal) son un poco diferentes. Primero debe abrir el archivo con la instrucción open. La declaración open especifica el número de unidad del archivo (un identificador interno para fortran), el nombre del archivo y el estado del archivo (nuevo/existente/desconocido3
.
Cuando usted necesite enviar datos al archivo definido con la instrucciónfor, se debe indicar el número de la unidad al comando write. Finalmente, el archivo debe cerrarse con una declaraciónclose. Para mayor ilustración pruebe el siguiente ejemplo,
3
Ejemplo de práctica
En este ejemplo usted creará un código que va a leer un nombre e imprimirá la salida a un archivo llamadomyname.txt. Cambie alguno de sus archivo existentes.f90de manera que sea igual al siguiente ejemplo.
program getname
implicit none
! Declaracion de variables
character(len=100) :: name
! Presente instrucciones en la terminal
print*,’please enter your name at the prompt’
! Lea el texto ingresado por el usuario
read*,name
! Abra un archivo para escribir el nombre ingresado
open(unit=6,file=’myname.txt’,status=’new’)
! Escriba el texto ingresado al archivo myname.txt,
! y asigne la unidad 6 para este archivo
write(6,*)
"your name is",name
! Cierre el archivo myname.txt
close(6)
! Detengamos TODO antes de salir
stop
! Finalice programa
end program getname
5. Operadores
Los operadores en Fortran son utilizados para manipular y comparar variables y constantes.
5.1. Operadores Aritméticos
Estos pueden ser aplicados a numéros reales y enteros. Los operandos pueden ser enteros, numéros reales o una mezcla de los dos. Los operadores se resumen a continuación:
Adición +
Substracción
-Multiplicación *
División /
Potenciación **
Sí los operandos, para cualquiera de los operadores indicados son dos enteros, el resultado será también un entero; si al menos uno de los operandos es un numero real, el resultado será un numero real.
Ejemplo de práctica En éste ejemplo usted escribiráun código para realizar diferentes operaciones aritméticas con diferentes valores. Siga el ejemplo ilustrado en el siguiente código.
program getname
implicit none
print*,"the result of 22/4 is",22/4
print*,"the result of 22.0/4.0 is",22.0/4.0
print*,"the result of 15/4*4.0 is",15/4*4.0
end program getname
Compile y corra éste código. La salida debería ser:
user@prompt:$
the result of 22/4 is 5
5.2. Operadores Comparativos
Para comparar dos variables o constantes enF90 se utilizan operadores comparativos. Estos operadores retornan un valor de 0 o1, con0 significando que la declaración o afirmación es falsa, y 1 significando que es verdadera. Los operadores se resumen a continuación4
:
Los operadores comparativos son muy útiles a la hora de tomar decisiones o en el momento de hacer declaraciones de control (lo que se verá más adelante).
Algo para tener en cuenta: No utilice estos operadores para comparar directamente dos numéros reales, buscando igualdad. Debido la forma en que los computadores tratan a los numéros reales es mejor definir una tolerancia y entonces verificar si la diferencia absoluta es menor que la tolerancia definida, por ejemplo
Código ejemplo
real :: a,b
real, parameter :: tol = 1.0e-06 logical :: same
! compare the value of a and b same = (abs(a-b).lt.tol)
5.3. Operadores Lógicos
Estos operadores trabajan con valores reales y retornan otro valor real. Los operadores se resumen a continuación:
5.4. Operadores de Caracter
Aquí son mostradas dos operadores de caracteres: El operador concatenación (//) y operaciones con subcadenas substring. Mire los ejemplos a continuación para su uso:
EJEMPLO:Abajo se encuentran algunos ejemplo de operación con cadenas:
Expresión Value
string1 .a
bcdef"
string2 "xyz"
string1 (2:4) "bcd"
string1 (1:1) .a
"
string1 (1) No válido
string1 // string 2 .a
bcdefxyz" string2 (2:3) // string1 (1:2) 2 zab"
5.5. Prioridad de Operadores
Al aplicar muchos operadores juntos en una sola declaración, la evaluación de algunos operadores ocurrirá primero. La lista mostrada a continuación otorga el orden en el cual estas operaciones son efectuadas en Fortran 90, en orden de prioridad descendente:
Potenciación
Multiplicación y división
6. Condicionales y Bucles
6.1.
if / else / endif
Estas estructuras condicionales le permiten controlar el flujo de su código. La declaraciónifle permite controlar sí un programa entra a una sección del código o no, basado en sí una condición es falsa o verdadera. Hay tres variaciones básicas en la declaración if, con una sintaxis general como:
if ( condición verdadera ) Ejecute está declaración
O usted podría utilizar una declaración en bloque como:
if ( condición verdadera ) then
. Ejecute está declaración
. Ejecute está declaración tambien
. etc... endif
Ambas estructuras ejecutarán únicamente la(s) declaración(es) que se encuentran dentro del if sí la declaración inicial es verdadera.
Si usted quiere ejecutar otro código para el caso en el cual la declaración sea falsa, usted puede usar la construcción if/else if/ else:
if ( condición 1 es verdadera ) then
. Ejecute está declaración si la condición 1 es verdadera else if ( condición 2 es verdadera ) then
. Ejecute está declaración si la condición 2 es verdadera else
. Ejecute está declaración si ninguna de las dos condiciones es vedadera endif
Ejemplo de práctica
program ageist
implicit none
integer :: age
print*,"Por favor introduzca su edad"
read*,age
if (age.lt.50) then
print*,"Usted es bastante joven!"
else if (age==50) then
print*,"Usted es viejo!"
else
print*,"Usted es en verdad viejo!"
endif
end program ageist
Compile y corra éste código. Intente escribir alguna variación sobre el código.
6.2. Declaración
case
La declaracióncasees otra forma de usar construcciones de decisión enFortran 90. Observe el siguiente ejemplo.
program numbers
implicit none
integer :: i
print*,"Por favor ingrese un numero"
read*,i
select case (i)
case (:-1) ! i is negative
print*,"El numero es negativo"
case(0) ! only zero
print*,"El numero es cero"
case(1:9) ! i is positive
print*,"El numero es positivo y menor a 10"
case default
print*,"El numero es positivo y mayor a 9"
end select
end program numbers
Con la instrucción case usted no está restringido a utilizar valores enteros (integer). Usted podría usar también caracteres. La opción por defecto (default) es completamente opcional.
6.3. Ciclos
DO
/ Bucles
Código ejemplo
Observe que usted puede introducir una declaración de salida condicional en cualquier parte del cuerpo del bucle, y de esta forma controlar el número de ejecuciones del bucle antes de que ocurra la salida (instrucciónexit). Al poner el condicional al final del bucle se asegura que la declaración se ejecuta al menos una vez.
Una variación en está construcción es usar una declaración de ciclo en vez de una declaración de salida. Está construcción de bucle asegura que cuando la evaluación de condición retornatrue, el bucle pasará sobre el valor del contador del bucle. Ejemplo:
Código ejemplo
Intente códificar lo anterior por usted mismo y ejecutelo. La salida será una impresión de todos los numeros del 1 al 100, a excepción del numero 80, en la terminal.
Código ejemplo
do <variable> = inicio, final, avance
El avance (o "stride" ) es el intervalo de incremento entre cada iteración, y es opcional. El caso por defecto es un incremento positivo de 1. Note que el"stride" puede ser de igual forma un número positivo o negativo.
Ejemplo de práctica
Ejemplo de un bucle indexado:
program loopy
implicit none
integer :: i
i = 0
print*,"Hacia Adelante"
do i=1, 5
print*,i
end do
print*,"Hacia Atras"
do i = 5, 1, -1
print*,i
end do
end program loopy
Usted no está restringido a un bucle simple o sencillo. Usted podrá necesitará también bucles anidados.
7. Arreglos /
Arrays
7.1. Introducción
Un arreglo en Fortran 90 es una estructura de datos que es usada para almacenar una colección de objetos del mismo tipo. La sintaxis general de la declaración de un arreglo es la siguiente:
Código ejemplo
El tipo de variable del arreglo es simplemente el tipo de variable de los valores que serán almacenados en el arreglo (por ejemplo reales, enteros etc). El comandoDIMENSION determina el rango del arreglo y es por lo tanto obligatorio. El valor extent es el rango de las entradas del arreglo, lo que determina los subíndices de sus elementos. La sintaxis general para la definición de este rango es
Código ejemplo
entero_inicio : entero_final
Los enteros de definición del rango del arreglo pueden ser positivos, negativos o cero. No es necesario definir el valor de inicio del rango, ya que Fortan 90 asumirá que el primer valor es 1. Un elemento de un arreglo puede ser accedido en el código mediante la siguiente sintaxis:
Código ejemplo
array_name1( expresión de entero )
donde la expresión del entero puede ser tan simple como un solo número entero, o puede ser una expresión para evaluar, por ejemplo i + 1, dondeiserá un contador, es decir una variable tipo entero.
Ejemplo de práctica
Este ejemplo muestra un caso concreto de declaración de un arreglo:
program createArray
implicit none
integer
::
i
integer, DIMENSION( -2 : 2 ) :: arrayA
do i = -2, 2
arrayA(i) = i
enddo
print*, arrayA
stop
end program createArray
PRECAUCION!
Usted siempre deberá tener cuidado de no referenciar elementos que se encuentren por fuera del rango del arreglo declarado - en el ejemplo de arriba esto sería equivalente a intentar acceder a arrayA(-3) o
arrayA(3). Si usted intenta escribir algo enarrayA(-3)en éste ejemplo, esto sería escrito en una posición aleatoria de memoria, lo que podría ocasionar que sucedieran sucesos impredecibles! Seguramente el programa colapsará, o incluso el compilador se rehusará a compilar tal código. Note que si usted realiza un error de este tipo en su código, y no se toman las opciones adecuadas, el compilador no será capaz de reconocer el error en el momento de la compilación. Así que tenga mucho cuidado!
7.2. Arreglos Multidimensionales
Es posible crear arreglos multidimensionales en Fortran 90. Por ejemplo, para almacenar una matriz en F90, usted puede declarar un arreglo bidimensional. El ejemplo a continuación es la declaración de una matriz 3 x 3.
Código ejemplo
real, DIMENSION( extent_1, extent_2 ) :: matrix_3by3
Así, por ejemplo, si usted ha intentado imprimir su arreglo de matriz 3x3 al teclear simplemente:
print*,matrix_3by3
Los elementos aparecerán en la terminal en el orden indicado anteriormente. Pruebe por usted mismo!
Ejemplo de práctica
Codifique las declaraciones abajo mostradas para ver un ejemplo de como asignar valores a los elementos de una matriz de enteros, e imprimir estos elementos en el ordenamiento por columna. Observe el uso de bucles anidados.
program myarray
implicit none
integer :: i,j
integer, DIMENSION (1:3, 1:3) :: matrix_3by3
do i = 1, 3
do j = 1, 3
matrix_3by3(i,j) = (2*i)*(j*j)
enddo
enddo
print*,matrix_3by3
end program myarray
Compile y ejecute este código. Intente escribir algunas variaciones del código.
Como usted ha visto en el ejemplo anterior, usted puede referirse a elementos individuales del arreglo de la misma manera en que se referencian las posiciones de una matriz. Por ejemplo, la instrucción matrix_3by3(1,2) claramente se refiere al elemento en la fila 1 y la columna 2 del arreglo o matriz que este representa
Como en otros lenguajes, enFortran 90 usted también puede referirse a una subsección del arreglo, al suministrar rangos de subsecciones. Mire los ejemplos a continuación.
Para acceder a toda la primera fila de la matrizmatrix_3by3 use cualquiera de las siguientes lineas:
matrix_3by3(1,1:3)
matrix_3by3(1,:)
La siguiente instrucción hace referencia a toda la segunda columna de la matriz:
matrix_3by3(1:3,2)
o
matrix_3by3(:,2)
Usted también puede referirse a elementos en un arreglo al específicar el "stride". A menos que se especifique, el "stride" siempre será 1. Digamos que usted quiere tomar cada segundo elemento de la matriz matrix_3by3 , empezando por el elemento 1. Esto podría ser hecho especificando:
matrix_3by3(1::2)
o de forma alternativa como
matrix_3by3(::2)
7.3. Operaciones con arreglos
En Fortan 90, usted puede aplicar operaciones globales sobre arreglos. Sin embargo, si más de un arreglo va a ser usado en expresiones o calculos, todos los arreglos usados (o subsecciones de los mismos) deben tener la misma forma, es decir deben referirse al mismo número de filas y columnas. El operador (aritmético, lógico, etc) actuará elemento por elemento. A continuación algunos ejemplos cortos y específicos darán mayor claridad.
Multiplicar todos los elementos de la matriz matrix_3by3 por un numero, por ejemplo 2.5:
matrix_3by3 = matrix_3by3 * 2.5
Inicializar cada uno de los elementos de la matriz matrix_3by3 con el valor de 1.0:
matrix_3by3 = 1.0
Ejemplo de una expresión algebraica que involucra otra matriz (del mismo tamaño) llamadamatrix_2:
matrix_3by3 = 3.0 * matrix_3by3 + (matrix_2)**2
Ejemplo de la multiplicación de 2 matrices.
Nota: El ejemplo anterior NO corresponde con la "multiplicación de matrices"; esta es una simple multiplicación elemento por elemento. Este último ejemplo podría expresarse como:
matrix_3by3(i,j) = matrix_3by3(i,j) * matrix_2(i,j)
Usted también puede aplicar funciones matemáticas intrínsecas (tales como funciones trigonométricas) a arreglos. En este caso, como en todos los anteriores, la función operará con base en operación elemento por elemento.
7.4. Arreglo - Funciones Especificas
Hay mucho más para descubrir en la manipulación de arreglos en Fortran 90 - en particular existen muchas "funciones de arreglos". Dos de las cuales usted podría encontrar muy útiles sondot_product (efectúa el producto interno de dos arreglos) y matmul (toma el producto de dos matrices - la propia multiplicación matricial). Estas dos funciones, entonces, operan en el sentido estricto de algebra lineal.
Ejemplo de práctica
Codifique el siguiente programa para ver un ejemplo de como usar estos operados específicos sobre arreglos.
program armanip
implicit none
integer :: i,j,c
integer, DIMENSION(1:3, 1:3) :: matrix_3by3,matrix_2,d
integer, DIMENSION(3) :: a,b
do i = 1, 3
do j = 1, 3
matrix_3by3(i,j) = 2*i*j*j
matrix_2(i,j) = 1.5 * j * (i+1)
enddo
enddo
! create vector a from the first row of matrix_3by3
a = matrix_3by3(1,:)
! create vector b from the second row of matrix_2
b = matrix_2(2,:)
! take dot product of these two vectors
c = dot_product(a,b)
print*,c
! take the real matrix inner product
! of the two matrices
d = matmul(matrix_3by3,matrix_2)
print*,d
end program armanip
compile y corra éste código. Intente escribir algunas variaciones en está código.
Ejemplo de práctica
Escriba el siguiente programa para ver como funciona el cambio de forma de arreglos (también deno-minado re-shape").
program reshape
implicit none
integer :: i
integer, DIMENSION(1:3, 1:3) :: matrix_3by3
integer, DIMENSION(9) :: a
! assign elements of a to be 1 -> 9
a = (/ (i,i=1,9) /)
! reshape this array, a, into a 3by3 matrix
matrix_3by3 = reshape ( a, (/ 3,3 /) )
print*,matrix_3by3
end program shape
Compile y ejecute este código. Intente escribir algunas variaciones obre este código.
7.5. Arreglos de tamaño dinámico / Allocatable arrays
La ultima área que usted puede encontrar útil con respecto a arreglos son los .Allocatable Arrays". A
veces no es conveniente haber decidido el tamaño del arreglo en una línea de compilación. Usted puede obtener flexibilidad al usar un arreglo asignable - en éste caso usted declara un arreglo al especificar el rango (número de dimensiones) unicamente. Su declaración debe incluir la palabra allocatable.
En el cuerpo del código, usted debe asignar la memoria de su arreglo, y una vez usted finalice esta tarea, liberar la memoria mediante la deasignación de la memoria. Esto será más claro con el siguiente ejemplo.
Ejemplo de práctica
program dynamic
implicit none
integer :: i,j
integer, DIMENSION (:,:), allocatable :: matrix
print*,&
&"Please enter the desired dimensions of your matrix"
read*,i,j
allocate ( matrix(0:i-1,0:j-1) )
matrix = 1.0
print*,matrix
deallocate ( matrix )
end program dynamic
Compile y ejecute este código. Intente escribir algunas variaciones obre este código.
8. Unidades de programa y procedimientos
8.1. Definición de módulo
En F90 una unidad de programa puede ser el cuerpo principal de un programa (iniciado por la sentencia program, como se ha visto en la parte inicial de cada código que se ha presentado hasta ahora), así como también lo puede ser un módulo.
Unmóduloes un elemento usado en proyectos de códigos grandes que involucran varias personas. Los módulos realizan muchas funciones:
Los módulos proporcionan una ubicación central de constantes y variables, de manera que las declaraciones de estos objetos no tengan que repetirse en muchos lugares dentro del código. Esto es equivalente a proporcionar declaraciones globales.
Los módulos pueden ser usados por todo un grupo de subprogramas agrupados.
Un módulo se puede compilar por separado o en conjunto con el programa principal. En todo caso se debe compilar antes de compilar el código principal. Si un módulo se escribe en el mismo archivo fuente que el cuerpo principal del código, entonces el módulo debe estar antes de la declaración del programa. Un módulo es invocado en el código principal mediante la sentenciause. Módulos y programas pueden contener procedimientos del programa (ver más adelante).
Ejemplo de práctica
Escriba las siguientes sentencias en un archivo nuevo. Este es un ejemplo trivial del uso de un módulo en un programa (llamado area ) En donde el módulo myconstants define algunas constantes:
! declare your module
module myconstants
implicit none
real, parameter :: pi=3.1415927, ee=2.7182818
end module myconstants
! start the main body of code
program area
! include your module with the *use* statement
use
myconstants
implicit none
real :: radius, result
print*,"Please enter the radius of a circle"
read*,radius
result = pi * radius**2
print*,"the area of the circle is ",result," units"
end program area
Compile y ejecute este código. Intente escribir algunas variaciones obre este código.
8.2. Definición de Subrutinas y Funciones
Una subrutina es una sección de código, identificada con un nombre particular, y que realiza una tarea determinada. Las subrutinas pueden ser invocadas desde una unidad de programa. Estas unidades de programación pueden afectar diferentes variables o porciones de memoria. Una función es similar, pero se utiliza para generar una única respuesta, y es invocada por referencia al nombre de la función. La función puede tener cualquier tipo de dato (por ejemplo, entero, real, etc).
A menudo es el caso de que no hay necesidad de escribir un procedimiento por usted mismo, F90 ya tiene muchas funciones intrínsecas, bastante útiles. Además existen muchas librerias numéricas (por ejemplo, NAG, BLAS, LAPACK, ATLAS, etc) que están disponibles. Estas librerias adicionalmente han sido optimizadas para el funcionamiento en plataformas específicas, por lo que serán bastante rápidas - probablemente mucho más rápidas que cualquier cosa que usted pueda escribir por si mismo.
Un procedimiento de programa puede ser declarado y especificado dentro del cuerpo principal del código, o puede ser externo al cuerpo principal de código. Un procedimiento debe tener argumentos (variables o constantes) que deben ser suministrados por otras insrucciones en el programa. Igualmente un proce-dimiento puede contener variables/constantes locales. Estos objetos locales se crean cuando se invoca el procedimiento y se destruyen cuando el programa sale de este procedimiento. Estos objetos locales no conservan los valores entre invocaciones (llamadas). La declaración del procedimiento debe conte-ner marcadores de posición para los argumentos a ser procesados. Estos son usualmente denominados
argumentos temporales. Este proceso se conoce como asociación de argumentos.
Ejemplo de función
Supongamos que en el cuerpo principal de un código vamos a llamar una funcion llamadawork, pasando por ella una variable real llamada a, así:
print*,work(a)
La definición correspondiente, o declaración, de esta función en este código es:
real function work(x)
Entonces, en este ejemplo, la variable temporal o ficticia esx. Cuando el programa ingresa a la función, reemplazará el valor de x por el actual valor dea.
8.3. Argumentos con atributos de intención
Para hacer su código más claro, puede usar algo llamado atributos de intenciónpara los argumentos de su procedimiento (sea este una función o una subrutina). Estos atributos facilitarán el proceso de compilación al indicar explícitamente al compilador cuál es su intención para el argumento temporal. Por ejemplo, si usted quiere que el argumento temporal:
Sea cambiado y se le asigne un valor diferente al usado anteriormente. En tal caso use la sentencia intent(out).
Debe ser referenciado y ademas cambiado. Para este caso use la sentencia intent(inout). Cuando un procedimiento es definido internamente, la definición del procedimiento debera venir solo despues del final del programa principal. La declaración deberia ser precedida por la sentencia contains.
Ejemplo de función
Escriba el siguiente código - Este le brindará claridad sobre algunos conceptos que se han cubierto en esta sección.
program example
implicit none
real :: x,y, result
print*,"Please enter the lengths of the rectangle"
read*,x,y
!***********************************************
! make a call to the subroutine called area
!---! the "real" attribute makes sure the input numbers
! are real, even if the user puts in integers
!***********************************************
call area(real(x),real(y),result)
print*,"the area of the rectangle is ",result," units"
! here is a list of one (or more) procedure defintions
! this is for internal procedures
contains
! subroutine declaration contains dummy arguments a,b,c
! these will be substituted for x,y,result
! (as taken from the call statement)
subroutine area(a,b,c)
real, intent(out) :: c
real, intent(in) :: a,b
! note the intent attributes of these variables
c = a * b
Compile y corra éste código. Intente escribir variaciones sobre él.