fortran 90
TRANSCRIPT
-
Apuntes de Fortran 90
V. Domnguez y F.J. Sayas
Junio de 2001
-
1. Introduccion
Fortran 90 es una actualizacion de Fortran 77 que moderniza este lenguaje, incorporando algunas de lascaractersticas comunes de los lenguajes mas modernos (C, C++, Pascal,etc.). Con el nuevo lenguaje sepersiguen los siguientes objetivos:
Modernizar la sintaxis.
Incluir aspectos de programacion modular, recursividad,. . .
Mejorar la habilidad para trabajar con las matematicas.
Incorporacion de estructuras de datos y de punteros.
Dentro de los posible se mantiene todava valida las instrucciones y sintaxis del Fortran 77. As pequenasmodificaciones permiten pasar un codigo en Fortran 77 a un codigo en Fortran 90. Sin embargo con elloperdemos las principales ventajas que incorpora el nuevo lenguaje.Captulo aparte merece el caso del manejo de tablas. En nuestro caso nos concentraremos en tablasunidimensionales y bidimensionales que se identifican con vectores y matrices. La nueva filosofa deFortran 90 consiste en el manejo de estas estructuras globalmente en lugar de elemento a elemento.Por ultimo conviene senalar que existe una actualizacion posterior que se conoce como Fortran 95. Sinembargo los cambios que incorpora son de una magnitud sensiblemente inferior a los desarrollados en laversion anterior
Primeras ideas sobre la sintaxis.
se emplea desde la columna inicial, a diferencia del Fortran 77 que dejaba las 6 primeras libres paraetiquetas y control de bucles.
No se distingue entre mayusculas y minusculas. Hay compiladores que distinguen para los nombresde variables.
! indica una lnea de comentario. Todo lo que sigue no se compila.
& se emplea para cortar una lnea. Se escribe al final de la lnea cortada y al principio de la siguiente.
Estructura del programa.program nombre programadeclaracion de variablescuerpo del programaend program nombre programa
Ejemplo
! mi primer programa en FORTRAN 90
program primero ! arranque del programaimplicit none ! declaracion variablesreal :: x,y
! programaprint*,dame dos numeros realesread*,x,yprint*,su suma es,x+yprint*,Esta es una linea partida en dos,&
& (x+(2*y)*x-y*y)/3.5
end program primero ! final
2
-
2. Declaracion de variables y asignacion
Tipos de constantes y variables:
enteras (integer) de coma flotante (real) a simple y doble precision complejas (complex) a simple y doble precision caracter (character) logicas (logical): unicamente pueden adoptar los valores
.TRUE. .FALSE
La ordenimplicit none
cancela un convenio implcito de declaracion de variables y obliga a declarar todas las variables
Por defecto real y complex son de precision simple, pero depende del compilador.
Ejemplo
program asignacionesimplicit noneinteger :: i,jreal (kind=4) :: x,y ! declara variables de precision simplereal (kind=8) :: z,t ! precision doblecomplex :: u ! complex(kind=4) :: ucharacter (len=4) :: palabra ! (len=4) indica que tiene 4 caractereslogical :: test
x=3.23e-4 ! asignacion de 3,23 104
y=-2.312e2x=3.4y=4 ! esta asignacion incluye una conversion de entero a realz=3.23e-4 8 ! 8 indica que es doble precisiont=2. 8z=(3.e-1,2.) ! =0,3 + 2palabra=casa ! las comillas identifican las constantes caracterpalabra="Juan" ! tambien se usan las dobles comillastest=.TRUE.
end program asignaciones
Inicializacion de variables.
Se pueden dar valores de arranque a las variables al declararlas
parameter bloque la posibilidad de reasignar la variable en el transcurso del programa
En las asignaciones de inicializacion no puede haber operaciones aritmeticas. Es aconsejable que nohaya conversiones automaticas (entero a real, etc).
3
-
programa asignacionesimplicit nonereal :: x=4.,t,z=3.e-2 ! asigna valores de arranque a x y zreal (kind=8) :: u=6.e2 8complex :: a=(2.,3.)character (4) :: palabra=casa ! (4) abrevia (len=4)real, parameter :: pi=3.141592...
3. Lectura y escritura en pantalla
Para escribir en pantalla y leer de teclado, en formato libre, se usan respectivamente
print*, read*,
Ejemplo
...x=3.5print*,x es ,xprint*,da un valor a yread*,yprint*,valores de x e y,x,y...
4. Operaciones numericas
Binarias basicas. Suma, resta, producto, division y exponenciacion.
+ - * / **
Tabla de tipos de datos y resultado.
entero real dobleentero entero real doblereal real real realdoble doble real doble
Funciones matematicas basicas. El argumento siempre se escribe entre parentesis.
abs (valor absoluto o modulo)
sqrt (raz cuadrada)
exp (exponencial)
log (logaritmo neperiano)
log10
sin
cos
tan
4
-
asin
acos
atan
sinh
cosh
tanh
Otras.
mod(i,j) da el resto de la division entera
int(x) da la parte entera de x
floor(x) da el mayor entero menor o igual que x
ceiling(x) da el menor entero mayor o igual que x
max(x1,...,xn) da el mayor de dos o varios argumentos
min(x1,...,xn) da el menor de dos o varios argumentos
Ejemplo
program partesEnterasreal :: x=2.3, y=-4.3, z=7.2 ! preasignadasinteger :: i=3, j=7, k=-5
print*, floor(x), ceiling(x), int(x)print*, floor(y), ceiling(y), int(y)print*, max(x,y,z), min(i,j,k)
end program partesEnteras
El programa precedente devolvera en pantalla:
2 3 2-5 -4 -47.2 -5
5. Estructuras de decision
Operadores de comparacion. Notese la diferencia entre el igual de comparacion (==) y el de asigna-cion. El smbolo /= indica 6=.
> < = == /=
5
-
Operadores logicos. Son cuatro: y, o, o exclusivo, negacion.
.AND. .OR. .XOR. .NOT.
Simple de sentencia unica
if (expresion logica) sentencia
Simple de sentencia multiple
if (expresion logica) thensentencia primerasentencia segunda...
end if
If-else
if (...) then...
else...
end if
Decision multiple
if (...) then...
else if (...) then...
else if (...) then...
else ! puede no estar...
end if
Puede haber estructuras anidadas.
Ejemplo
program decisionesimplicit nonereal :: x,yprint*,escribe x e yread*,x,yif (y0) then
print*,x es positivoelse
print*,x es negativoend ifif ((x>0 .AND. y>0).OR.(x
-
elseprint*,x*y es negativo o nulo
end ifend program decisiones
La orden select case. La sintaxis es
select case (criterio) ! criterio devuelve un valor numericocase(expr1) ! selecciona si se cumple el caso
...case(expr2) ! si se cumple este caso y no el precedente
......case default ! caso por defecto; puede no estar
...end select
Ejemplo
program casosimplicit noneinteger :: opreal :: x,y
print*,elija una opcionread*,opselect case(op)
case(1)print*,op=1read*,x
case(2)print*,op=2read*,x,y
case(3:5)print*,Valor de op entre 3 y 5
case(6:)print*,Valor de op >=6
case(:-1)print*,Valor de op negativo
case defaultprint*,op es cero
end selectend program casos
6. Estructuras de repeticion
Estructura general
do ndice = inicio, final, incrementosentencias
end do
7
-
Por defecto el incremento es 1.
Puede haber bucles vacos (p.ej. con inicio menor que final e incremento negativo): no se haceninguna operacion.
exit se puede emplear para forzar la salida del bucle.
cycle se puede emplear para pasar directamente al comienzo de la siguiente repeticion del bucle.
Ejemplo
program repeticionesimplicit noneinteger :: i,opreal :: xdo i=10,1,-1
print*, i**2 ! cuadrados de enteros del 10 al 1end dodo i=1,10
print*,i**2 ! lo mismo del revesend dodo i=1,10,-1 ! bucle vaco
print*,iend donombre : do i=1,10 ! bucle etiquetado
print*,inserta xread*,xif (.NOT.x>=0) then
print*,x es negativocycle ! se pasa de nuevo a la primera lnea, incrementando i
end ifprint*,Otra vez? (1->si)read*,opif (op/=1) exit ! si op 6=1 se sale del bucle
end do nombre ! cierre de bucle etiquetadoend program repeticiones
7. Ficheros
La instruccion basica de apertura de un fichero es
open(unit=unidad, file=nombreFichero, status=tipo)
donde:
unidad es un numero entero que identificara al fichero mientras permanezca abierto nombreFichero es el nombre de fichero que se desea abrir; lleva comillas tipo es uno de los cuatro siguientes valores
old cuando el fichero ya existe; permite leer pero no escribir new cuando el fichero no existe y se va a crear; si ya existe, da un error replace cuando el fichero no existe o existe pero se va a reemplazar por uno nuevo;borra el anterior
8
-
scratch cuando se trate de un fichero temporal de trabajo que se borrara al cerrarLas instrucciones
write(unidad,*)read(unidad,*)
sirven para escribir y leer en formato libre.
La instruccion open dada abre ficheros de tipo texto. Se puede modificar para ficheros binarios (sinformato).
El fichero se cierra con
close(unidad)
Ejemplo
program ficherosimplicit nonereal :: a,binteger :: i,nopen(unit=1, file=datos.dat, status=old)open(unit=2, file=salida.res, status=replace)read(1,*) ndo i=1,n
read(1,*) a,bwrite(2,*) a+b
end doclose(1)close(2)end program ficheros
Si el fichero datos.dat tiene la forma
54. 2.6. 3.-2. 4.1. 1.2e-32. 1.1e2
el fichero salida.res tendra la forma
6.9.2.1.0012112.
9
-
8. Funciones
En principio una funcion devuelve unicamente un valor.
La sintaxis general es
function nombredeclaracion de variablesinstruccionesreturnend function nombre
nombre es la denominacion de la variable de salida y debe estar declarada con las demas.
Puede haber mas de un return por funcion. El final es innecesario.
Ejemplo
program programaPrincipalimplicit noneinteger :: i,nreal :: x, f ! la funcion f se declara como otra variableprint*,inserta numero repeticionesread*,ndo i=1,n
print*,escribe xread*,xprint*,f(x)print*,x+f(x)
end doend program programaPrincipal
function f(y)implicit nonereal :: y,f,z ! z es una variable localif (y>=0) then
z=y**3f=z+z**2 ! f sera el valor de salida
elsef=0
end ifreturnend function f
9. Subrutinas
La sintaxis de una subrutina es
subroutine nombre(arg1,..., argn)declaracion de variablesinstruccionesend subroutine nombre
10
-
Todos los argumentos son, salvo que se indique lo contrario mediante los especificadores intent,de entrada y salida, es decir, su valor puede ser modificado en el transcurso de la ejecucion.
La llamada a una subrutina se realiza mediante la orden call
call nombre(var1,..., varn)
El especificador intent sirve para bloquear un argumento como argumento de entrada o salida.Sus posibles valores son
in (entrada); no admite que sea modificada out (salida) inout (entrada y salida)
Se puede regresar al programa principal desde cualquier punto de la subrutina con return.
Ejemplo
program programaPrincipalimplicit noneinteger :: i,jreal :: x,y,zprint*,introducir dos enteros y dos realesread*,i,j,x,ycall intercambia(i,j)print*,i,jcall potencias(x,y,z,i,j)end program programaPrincipal
subroutine intercambiar(u,v)integer :: u,v,w ! u,v son de entrada-salida; w es localw=uu=vv=wend subroutine intercambiar ! no hace falta poner un return
subroutine potencias(x,y,z,i,j)integer, intent(in) :: i,j ! i,j son argumentos de entradareal :: x,yreal, intent(out) :: zif ((i
-
10. Vectores y matrices (1)
Declaracion de matrices. Se hace en la declaracion de variables, utilizando el especificador dimension.Ejemplo
...real, dimension(10) :: b,c ! vectores de 10 componentesreal(kind=8), dimension(10,12) :: a ! matriz 10 12, doble precisionreal :: bb(10), cc(10,12) ! equivalente a poner dimensioninteger :: ccc(-2:7) ! 10 componentes, numeradas a partir de -2...
Operaciones elementales.
+ : Suma elemento a elemento, de arrays de las mismas dimensiones.
- : Resta elemento a elemento. Tambien, cambio de signo de todos los elementos.
* : Producto de un escalar por un array.
* : Producto elemento a elemento de arrays de las mismas dimensiones.
Las funciones abs, log, sin, cos, exp, ... se aplican elemento a elemento.
Ejemplo
program operacionesreal :: a(10,10),b(10,10),c(10,10),v1(10),v2(10),t=3.,c1,c2integer :: i,jdo i=1,10
do j=1,10a(i,j)=1./(i+j)
end dov1(i)=i*6.5
end dob=t*ac=a+bc=-cb=c*a ! producto elemento a elementov2=sin(v1)v1=t*v1+5*v2 ! combinacion linealend program operaciones
Asignaciones y bucles implcitos. La asignacion siguiente
real :: b(10)...b=(/ -3.,-1.,1.,3.,5.,7.,9.,11.,13.,15. /)...
se puede hacer equivalentemente en un bucle desplegado
12
-
do i=1,10b(i)=2*(i-2)-1
end do
o en un bucle implcito
b=(/ (2*i-1, i=-1,8) /)
o incluso
b=(/ (i, i=-3,11,2) /)
Ejemplo
...integer :: b(8), c(9)b=(/ (i,i=-3,15,2) /) ! (/-3,-1,1,3,5,7,...,11 /)b=(/ 1,2,(i**2,i=2,4), (-i**2,i=4,2,-1) /) ! (/ 1,2,4,9,16,-16,-9,-4 /)c=(/ ( (10*j+i,i=1,3), j=1,3 /) ! anidados:(/11,12,13,21,22,23,31,32,33/)...
11. Matrices y vectores (2)
FORTRAN 90 dispone de un buen numero de funciones para manejar matrices y vectores.
transpose(a) devuelve la traspuesta de adot product(a,b) calcula el producto escalar de dos vectores a y bmatmul(a,b) calcula el producto de dos matrices a y b;
o el producto de una matriz a por un vector bsum(a) devuelve la suma de todos los elementos de aproduct(a) devuelve el producto de todos los elementos de amaxval(a) devuelve el maximo valor de aminval(a) devuelve el mnimo valor de amaxloc(a) devuelve un vector con la posicion relativa del maximo valor de a,
esto es, la posicion en el array si todos los ndices arrancan en 1.minloc(a) idem con el mnimoshape(a) devuelve un vector con las dimensiones de a
Ejemplo
program normasVectorimplicit noneinteger :: p(1),ireal :: b(-1:5)b=(/ -1./9.,1.,((-3.)**(2*i),i=1,5) /)print*,sqrt(dot product(b,b)) ! norma 2print*,sum(abs(b)) ! norma 1print*,maxval(abs(b)) ! norma p=maxloc(abs(b)) ! posicion relativa del maximoprint*,pend program normasVector
13
-
Filas y columnas. Si se tiene una matriz e i es un valor admisible del ndice
a(i,:)
es una referencia valida de la fila iesima, que se puede emplear como vector. De la misma forma
a(:,i)
sirve para emplear la columna iesima.Las ordenes de escritura y lectura se pueden hacer por filas, etc
Ejemplo
programa lecturaimplicit noneinteger :: ireal :: a(10,5), b(6)print*,Escribe un vector de seis componentesread*,bprint*,Escribe por filas una matriz 10 por 5do i=1,10
read*, a(i,:)end doprint*,Esta es su traspuestado i=1,5
print*,a(:,i)end doend program lectura
Secciones de vectores y matrices. La idea anterior se puede generalizar a la seleccion de seccionesde matrices y vectores.
Dada una matriz a de dimension m n, entonces a(i1:i2, j1:j2) es la matriz obtenida al selec-cionar las filas i1 a i2 y las columnas j1 a j2.
Si aparece algo del estilo a(:i2,j1:j2), las filas se toman desde el principio hasta la i2 (esto es,un ndice que no aparece toma el primer valor posible).
La sintaxis se puede complicar, tomando ndices que no se mueven consecutivamente, siguiendo elconvenio
limiteInferior:limiteSuperior:incremento
Ejemplo: Consideremos las matrices a1 y a2
1 2 3 45 6 7 89 10 11 12
-1 -2-3 -4-5 -6
Entonces a(1:2,2:4) es la submatriz2 3 46 7 8
La sentencia
a1(2:3,1:2)=a2(2:3,:)
14
-
transforma a1 en1 2 3 4-3 -4 7 8-5 -6 11 12
Ejemplo: dado el vector b3 2 1 -4 -6 -2 -2
se tiene que b(2:5) es2 1 -4 -6
mientras que b(6:2:-2) proporciona-2 -4 2
Ejemplo
...print*,maxval( (/ sum( abs(a(i,:)) ),i=1,n) /) ) ! A = maxj
i |aij |
...
Ejemplo
subroutine gauss(n,a,b,x)implicit noneinteger :: n,i,jreal :: a(n,n), b(n),x(n),creal :: aa(n,n+1) ! array local ajustado a tama~no exterioraa(1:n,1:n)=aaa(:,n+1)=b ! matriz ampliadado i=1,n ! eliminacion gaussiana
do j=1,nc=aa(j,i)/aa(i,i)aa(j,i:n+1)=aa(j,i:n+1)-c*aa(i,i*n+1)
end doend dodo i=n,1,-1 ! sustitucion regresiva
x(i)=aa(i,n+1)-dot product(aa(i,i+1:n),x(i+1:n)) ! xi = bi n
j=i+1 aijxjx(i)=x(i)/aa(i,i)
end doend subroutine gauss
12. Vectores y matrices (3)
la orden reshape permite asignar tablas de diferentes dimensiones. La sintaxis elemental es
reshape(tabla, perfil)
donde
tabla es la matrizvector que queremos reorganizar perfil es el vector de dimensiones de la tabla final
15
-
Por ejemplo,
...b=(/ 1,2,3,4,5,6 /)m=reshape(b,(/2,3/))...
devuelve la matriz (por defecto se rellena por columnas)
1 3 52 4 6
Si seguidamente hacemos
mm=reshape(m,(/3,2/))
obtenemos la matriz1 42 53 6
13. Matrices y vectores (4)
Secciones arbitrarias de matrices y vectores.
Si
ind=(/ i1,i2,..., ir/)
entonces a(ind,:) selecciona las r filas de ndices correspondientes
a(i1,1) a(i1,2) ... a(i1,n)a(i2,1) a(i2,2) ... a(i2,n)
......
...a(ir,1) a(ir,2) ... a(ir,n)
De manera analoga b(ind) es el vector de componentes
b(i1) b(i2) ... b(ir)
Si en ind hay ndices repetidos, esto permite emplear a(ind,:) en operaciones, pero puede darproblemas en asignaciones. (ver comentarios sobre subrutinas)
Igualmente, si
indi=(/ i1,i2,..., ir/)indj=(/ j1,j2,..., js/)
la submatriz a(indi,indj) hace referencia a
a(i1,j1) a(i1,j2) ... a(i1,js)a(i2,j1) a(i2,j2) ... a(i2,js)
......
...a(ir,j1) a(ir,j2) ... a(ir,js)
16
-
Ejemplo. Sean ind=(/1,4,2/); a y b las siguientes matriz y vector (respectivamente)
1 2 3 -1-2 2 1 02 1 3 21 3 1 1
2 1 2 -3 2
Entonces a(ind,:) y a(2:3,ind) son respectivamente
1 2 3 -11 3 1 1-2 2 1 0
-2 0 22 2 1
mientras que b(ind) es2 -3 1
Ejemplo. Con indi y indj los vectores de enteros dados respectivamente por
2 4 3 1 5 2
y a dada por1 2 3 -1 2-2 2 1 0 42 1 3 2 21 3 1 1 3
la seccion a(indi,indj) es-2 4 21 3 32 2 1
La instruccion
a(indi,indj)=0
transformara a en1 2 3 -1 20 0 1 0 00 0 3 2 00 0 1 1 0
Declaracion dinamica. En FORTRAN 90 es posible declarar matrices y vectores sin asignarles susdimensiones, esperando a que se fijen durante el programa:
El especificador allocatable en la declaracion de un array, con los ndices de dimensiones mudos,deja la cuestion de la asignacion de memoria en suspenso. No obstante, hay que decidir a priori enla declaracion el numero de ndices del array.
Con allocate se asignan dimensiones.
Con deallocate se deasignan dimensiones.
Ejemplo
program dinamicaimplicit nonereal, allocatable :: a(:,:), b(:) ! una matriz y un vectorinteger :: n,i,j,opdo j=1,10
17
-
print*,dar dimensionread*,nallocate(a(n,2*n),b(2*n)) ! asignacion; ambas en la misma instruccionprint*,escribir matriz por filasdo i=1,n
read*,a(i,:)end doprint*,escribir vectorread*,bprint*,su producto es:, matmul(a,b)deallocate(a,b) ! desasignacion de memoriaprint*,Otra vez? (1->Si)read*,opif(op/=1) exit
end doend program dinamica
14. Matrices y vectores en subrutinas
La forma correcta de enviar una matriz a una subrutina es dando ademas las dimensiones de dichamatriz como otro argumento.
En la subrutina se declara como una matriz de las dimensiones recibidas
Las matrices se reciben por referencia, es decir, cualquier cambio que hagamos en la matriz en lasubrutina se mantiene en el programa principal.
Ejemplo
program pruebaSubrutinaimplicit nonereal, allocatable :: a(:,:), b(:)integer :: i,j,n,mprint*,Escribir dimensiones de la matrizread*,m,nallocate(a(m,n),b(m))do i=1,m
read*,a(i,:)end docall sumaColumnas(a,b,m,n)print*,bend program pruebaSubrutina
subroutine sumaColumnas(a,b,k,l)implicit noneinteger :: k,l,ireal :: a(k,l),b(k)b=(/ (sum(a(i,:)), i=1,l) /) ! suma de los elementos de cada filaend subroutine sumaColumnas
18
-
Lo anterior sigue siendo cierto si enviamos trozos compactos de matrices como argumento. En elejemplo anterior podamos haber puesto
call sumaColumnas(a(1:m-2,1:n-1),b(1:m-2),m-2,n-1)
Esto no funciona si se envan trozos de matrices con referencia mediante un conjunto de ndices. Sihacemos, por ejemplo,
call sumaColumnas(a(ind,:),b(ind),mind,n)
donde ind es un vector de mind numeros enteros, se envan copias de las secciones de a y b. Portanto, cualquier cambio que se haga sobre a o b en la subrutina no repercute en el valor final.
La forma de solucionar este problema es realizar una copia de lo que se quiere enviar en una matrizo vector auxiliar, llamar a la subrutina y al final volcar el resultado sobre la matriz o vector original.
Ejemplo
program pruebaSubrutinaimplicit nonereal, allocatable :: a(:,:), b(:), b2(:)integer :: i, j, n, m, mindinteger, allocatable :: ind(:)print*,Escribir dimensionesread*,m,nallocate(a(m,n),b(m))print*,Introducir la matriz por filasdo i=1,m
read*,a(i,:)end doprint*,Cuantas filas quieres tener en cuenta?read*, mindallocate(b2(mind),ind(mind))print*,Escribir numeros de filasread*,indcall sumaColumnas(a(ind,:),b2,mind,n) ! la parte de a pasa por valorb(ind)=b2 ! las filas que no se tienen en cuenta dan un ceroprint*,bend program pruebaSubrutina
Ejemplo
subroutine GaussSeidel(a,b,x,n,itmax,tol)implicit noneinteger, intent(in) :: n,itmaxreal :: a(n,n),x(n),xold(n),b(n)real, intent(in) :: tolreal :: difx=0. ! arrancamos del vector nulodo it=1,itmax
xold=xdo i=1,n
x(i)=b(i)-dot product(a(i,1:i-1),x(1:i-1))& ! con i=1, nada
19
-
&-dot product(a(i,i+1:n),xold(i+1:n)) ! sigue la lneax(i)=x(i)/a(i,i)
end dodif=maxval(abs(x-old)) ! norma infinitoif (dif
-
end select opcionesend program prueba
16. Modulos
Modulos simples: contienen informacion como declaraciones de variables y parametros muy repetitivas.
Construccion
module nombreModuloinformacion...
end module nombreModulo
Utilizacion
program/function/subroutine nombreParteuse nombreModulodeclaraciones de variablessentencias del programaend program/function/subroutine nombreParte
Ejemplo
module constantesreal, parameter :: pi=3.141592, euler=0.57721566end module constantes
function g1(x)use constantesimplicit nonereal :: g1,xg1=cos(2*pi*x)end function g1
function g2(x)implicit nonereal :: g2,xg2=(x-1.)**2end function g2
Modulos librera: contienen funciones y subrutinas
Construccion
module moduloSegundocontains
function nombreFuncion...end function nombreFuncionfunction otraFuncion...end function otraFuncion
end module moduloSegundo
21
-
Utilizacion: igual que antes
Ejemplo
module misfuncionescontains
function g1(x)use constantesimplicit nonereal :: g1,xg1=cos(2*pi*x)end function g1
function g2(x)implicit nonereal :: g2,xg2=(x-1.)**2end function g2
end module misfunciones
program prueba ! programa principaluse misfunciones ! no se declaran g1, g2implicit noneinteger :: num,opreal :: a,breal :: trapecio
print*,Extremos del intervaloread*,a,bprint*,Numero de particionesread*,numprint*,Opcion:read*,opopciones : select case(op)
case(1)print*,Resultado:,trapecio(g1,a,b,num)
case(2)print*,Resultado:,trapecio(g2,a,b,num)
end select opciones
end program prueba
17. Tipos derivados de datos
Empaquetado de varias variables bajo un tipo comun.
Forma:
program/subroutine/function nombrePartetype nombreTipo
declaraciones de identificadoresend type nombreTipodeclaraciones de otras variables
22
-
type (nombreTipo) :: variablesConcretas....
Ojo: hay que incluir la declaracion del tipo en todas las partes en que se use
Ejemplo
program pruebatipostype fecha
integer :: dia, mes, anhoend type fechatype (fecha) :: mifechatype (fecha), external :: leefechainteger :: aux
mifecha=leefecha()aux=mifecha %anhoaux=aux-100*(aux/100)print*,Mi fecha:,mifecha %dia,mifecha %mes,auxend program pruebatipos
function leefecha() ! sin argumentostype fecha
integer :: dia, mes, anhoend type fechatype (fecha) :: leefechaprint*,A~no:read*,leefecha %anhoprint*,Mes:read*,leefecha %mesprint*,Dia:read*,leefecha %diareturnend function leefecha
Ejemplo
module misEstructurastype fecha
integer :: dia, mes, anhoend type fecha
end module misEstructuras
program pruebatiposuse misEstructurastype (fecha) :: mifechatype (fecha), external :: leefechainteger :: aux... ! sigue como antesend program pruebatipos
23
-
function leefecha()use misEstructurastype (fecha) :: leefecha... ! sigue como antesend function leefecha
Ejemplo
module misEstructurastype fecha
integer :: dia, mes, anhoend type fechatype datos
type(fecha) :: nacimiento ! un tipo puede utilizar otros tiposcharacter(len=40) :: nombre, apellidosinteger :: dni
end type datosend module misEstructuras
program pruebatiposdetiposuse misEstructurastype (datos), allocatable :: lista(:)type (fecha), external :: leefechainteger :: i,numprint*,Cuantos datos?read*,numallocate(lista(num))do i=1,num
print*,Nombreread (a40),lista(i) %nombreprint*,Apellidosread (a40),lista(i) %apellidoslista(i) %nacimiento=leefecha()
end doprint*,Lista de a~nos de nacimientodo i=1,num
print*,lista(i) %nacimiento %anhoend doend program pruebatiposdetipos
18. Funciones con valores vectoriales
FORTRAN 90 admite que una funcion devuelva un array de datos.Precaucion: tienen que estar declaradas bajo una estructura
interface
cada vez que se usen. La declaracion es un prototipo que aclara el tipo de variables y de resultado de lafuncion.
Ejemplo
24
-
function rotacion(x,theta)real :: theta,x(2),rotacion(2),matriz(2,2)matriz=reshape((/cos(theta),-sin(theta),&
& sin(theta),cos(theta)/),(/2,2/))rotacion=matmul(matriz,x)end function rotacion
program pruebareal :: phi,x(2)interface
function rotacion(x,ang)real :: ang,x(2),rotacion(2)end function
end interfaceprint*,angulo de rotacionread*,phiprint*,vector que se quiere rotarread*,xx=rotacion(x,phi)print*,vector rotado=,xend program prueba
19. Punteros
Variables que apuntan direcciones de memoria de otras variables
Se declaran con el atributo pointer
Las variable a las que se va a apuntar llevan el atributo target
La forma general es
puntero=>objetivo
Ejemplo
program punteroimplicit nonereal,target ::aa,bbreal, pointer:: c,daa=4.bb=6.c=>aa ! c apunta a aad=>bb ! d apunta a bb
print*,aa=,aa,bb=,bbprint*,valor apuntado por c,c,valor apuntado por d,dc=-6print*,aa=,aa,bb=,bbprint*,valor apuntado por c,c,valor apuntado por d,dc=>d ! c apunta a bb (a->d->bb)c=2print*,bb=,bb
25
-
print*,valor apuntado por c,c,valor apuntado por d,dnullify(c) ! c no apunta a ninguna variableend program puntero
El programa anterior da como salida en pantalla
a= 4.000000 b= 6.000000valor apuntado por c 4.000000 valor apuntado por d 6.000000a= -6.000000 b= 6.000000valor apuntado por c -6.000000 valor apuntado por d 6.000000b= 2.000000valor apuntado por c 2.000000 valor apuntado por d 2.000000
Las variables punteros pueden definirse para apuntar a estructuras mas complicadas: arrays y estructurasde datos.
20. Ejemplo final
Problema. Almacenamiento (y manipulacion) de matrices esencialmente vacas.
Modelo sparse. 0 1,5 2,5 02 0 0 0,50 0,25 0 0
real 1,5 2,5 2 0,5 0,25
integer 1 1 2 2 3integer 2 3 1 4 2
El formato debe guardar el tamano de la matriz original mas el numero de elementos no nulos (porcomodidad)
Problema practico. El tipo de datos debe admitir longitudes por determinar. Pero no puede habernada allocatable:
* en la definicion de un tipo de datos
* como argumento de una subrutina o funcion
Sustituir allocatable por pointer y hacer lo mismo. Por dentro, el programa cambia mucho; por fuera,no.
Plan.
Modulo con tipo sparse
Subrutinas y funciones:
leer matriz sparse pasar sparse a matriz pasar matriz a sparse multiplicar sparse por vector
Crear un modulo con las interfaces de todo lo anterior
Programa de prueba
26
-
module cosassparsetype sparse
integer :: nf,nc,nelreal, pointer :: matriz(:)integer, pointer :: fil(:), col(:)
end type sparseend module cosassparse
module funcionessparseinterface
subroutine leersparse(u)use cosassparsetype(sparse) :: u
end subroutine leersparsefunction sparser(v,dim)
use cosassparsetype(sparse) :: sparserinteger,dimension(2) :: dimreal :: v(dim(1),dim(2))
end function sparserfunction matriz(a)
use cosassparsetype(sparse) :: areal :: matriz(a %nf,a %nc)
end function matrizfunction sparseporvector(a,x,m)
use cosassparseinteger :: mtype(sparse) :: areal :: x(m),sparseporvector(a %nf)
end function sparseporvectorend interfaceend module funcionessparse
subroutine leersparse(a)use cosassparsetype (sparse) :: ainteger :: n,iprint*,Numero elementos, filas, columnasread*,n,a %nf,a %nca %nel=nallocate(a %matriz(n),a %fil(n),a %col(n))do i=1,n
read*,a %matriz(i),a %fil(i),a %col(i)end doend subroutine leersparse
Nota. a entra sin tamano predefinido y sale con tamano asignado.
function matriz(a)use cosassparsetype(sparse) :: areal :: matriz(a %nf,a %nc)integer :: imatriz=0.
27
-
do i=1,a %nelmatriz(a %fil(i),a %col(i))=a %matriz(i)
end doend function matriz
function sparser(v,dim)use cosassparsetype(sparse) :: sparserinteger,dimension(2) :: dimreal :: v(dim(1),dim(2))integer :: cont,i,j,aux(1)sparser %nf=dim(1)sparser %nc=dim(2)aux=count(v/=0)sparser %nel=aux(1)cont=aux(1)allocate(sparser %matriz(cont), &
& sparser %fil(cont),sparser %col(cont))cont=0.do i=1,dim(1)
do j=1,dim(2)if(v(i,j) /= 0) then
cont=cont+1sparser %matriz(cont)=v(i,j)sparser %fil(cont)=isparser %col(cont)=j
end ifend do
end doend function sparser
function sparseporvector(a,x,m)use cosassparseinteger :: mtype(sparse) :: areal :: x(m),aux(a %nf),sparseporvector(a %nf)if (m /= a %nc) then
print*,error de dimensionesreturn
end ifaux=0do i=1,a %nel
aux(a %fil(i))=aux(a %fil(i))+&& a %matriz(i)*x(a %fil(i))
end dosparseporvector=auxend function sparseporvector
program pruebasuse cosassparseuse funcionessparsetype (sparse) :: areal,allocatable :: bb(:,:),cc(:,:),x(:),y(:)
allocate(bb(3,5),x(5),y(3))
28
-
do i=1,3bb(i,i+2)=3.*ibb(i,i)=-1.*i
end doa=sparser(bb,shape(bb))print*,a %matrizallocate(cc(a %nf,a %nc))cc=matriz(a)do i=1,size(cc,dim=1)
print*,cc(i,:)end doprint* x=1.y=sparseporvector(a,x,5)print*,yend program pruebas
29