Apuntes de Fortran 90
V. Dom´ Dom´ınguez ınguez y F.J. Sayas Junio de 2001
1.
Intr Introdu oducc cci´ i´ on on
Fortran 90 es una actualizaci´on on de Fortran 77 que moderniza este lenguaje, incorporando algunas de las caracter´ısticas ısticas comunes de d e los lenguajes lengua jes m´as modernos (C, C++, Pascal,etc.). Con el nuevo lenguaje se persiguen los siguientes objetivos: Modernizar la sintaxis. Incluir aspectos de programaci´on on modular, modular, recursividad recursividad,. ,. . . Mejorar la “habilidad” para trabajar con las matem´aticas. Incorporaci´ on de estructuras de datos y de punteros. on Dentro de los l os posible p osible se mantiene m antiene todav´ıa ıa v´alida alida las instrucciones instrucci ones y sintaxis s intaxis del Fortran 77. A Ass´ı peque˜ p eque˜nas modificaciones permiten pasar un c´odigo odigo en Fortran 77 a un c´odigo odigo en Fortran 90. Sin embargo con ello perdemos las principales ventajas que incorpora el nuevo lenguaje. Cap´ Cap´ıtulo ıtulo aparte aparte merece merece el caso del manejo manejo de tablas. tablas. En nuestro nuestro caso nos concentra concentraremos remos en tablas tablas unidimensi unidimensionale onaless y bidimensi bidimensionale onaless que se identific identifican an con vectores vectores y matrices. matrices. La nueva nueva filosof filosof´´ıa de Fortran 90 consiste en el manejo de estas estructuras globalmente en lugar de elemento a elemento. Por ultimo u ´ ltimo conviene se˜nalar nalar que existe una actualizaci´on on posterior que se conoce como Fortran 95. Sin embargo los cambios que incorpora son de una magnitud sensiblemente inferior a los desarrollados en la versi´on on anterior Primeras ideas sobre la sintaxis.
se emplea desde la columna inicial, a diferencia del Fortran 77 que dejaba las 6 primeras libres para etiquetas y control de bucles. No se distingue entre may´usculas usculas y min´usculas. usculas. Hay compiladores que distinguen para los nombres de variables. ! indica una l´ınea de comentario. comentario. Todo lo que sigue no se compila. & se emplea para cortar co rtar una l´ınea. Se escribe escrib e al final fin al de la l´ınea ınea cortada cor tada y al principio princ ipio de la siguiente. siguie nte.
Estructura del programa. program nombre programa declaraci´ on on de variables cuerpo del programa end program program nombre programa Ejemplo
! mi primer primer programa programa en FORTRA FORTRAN N 90 program primero implicit none real real :: x,y x,y
! arranque del programa ! declaraci´on variables variables
! programa programa print*,’ print*,’dame dame dos numeros numeros reales’ reales’ read*,x,y print*,’ print*,’su su suma es’,x+y es’,x+y print* print*,’E ,’Esta sta es una linea linea partid partida a en dos’,& dos’,& & (x+(2*y)*x-y*y)/3.5 (x+(2*y)*x-y*y)/3.5 end program primero
! final
2
2.
Declaraci´ on de variables y asignaci´on Tipos de constantes y variables: • enteras (integer) • de coma flotante (real) a simple y doble precisi´on • complejas ( complex) a simple y doble precisi´on • car´acter (character) • l´ogicas (logical): u ´ nicamente pueden adoptar los valores .TRUE.
.FALSE
La orden implicit none
cancela un convenio impl´ıcito de declaraci´on de variables y obliga a declarar todas las variables Por defecto real y complex son de precisi´on simple, pero depende del compilador. Ejemplo
program asignaciones implicit none integer :: i,j real (kind=4) :: x,y ! declara variables de precisi´on simple real (kind=8) :: z,t ! precisi´on doble complex :: u ! complex(kind=4) :: u character (len=4) :: palabra ! (len=4) indica que tiene 4 caracteres logical :: test x=3.23e-4 y=-2.312e2 x=3.4 y=4 z=3.23e-4 8 t=2. 8 z=(3.e-1,2.) palabra=’casa’ palabra="Juan" test=.TRUE.
! asignacion de 3,23 10
4
−
! esta asignaci´on incluye una conversi´on de entero a real ! 8 indica que es doble precisi´on ! = 0,3 + 2 ı ! las comillas identifican las constantes car´acter ! tambi´en se usan las dobles comillas
end program asignaciones
Inicializaci´ on 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 inicializaci´on no puede haber operaciones aritm´eticas. Es aconsejable que no haya conversiones autom´aticas (entero a real, etc).
3
programa asignaciones implicit none real :: x=4.,t,z=3.e-2 real (kind=8) :: u=6.e2 8 complex :: a=(2.,3.) character (4) :: palabra=’casa’ real, parameter :: pi=3.141592 ...
3.
! asigna valores de arranque a x y z
! (4) abrevia (len=4)
Lectura y escritura en pantalla
Para escribir en pantalla y leer de teclado, en formato libre, se usan respectivamente print*,
read*, Ejemplo
... x=3.5 print*,’x es ’,x print*,’da un valor a y’ read*,y print*,’valores de x e y’,x,y ...
4.
Operaciones num´ ericas
Binarias b´ asicas.
Suma, resta, producto, divisi´on y exponenciaci´on. +
-
*
/
**
real real real real
doble doble real doble
Tabla de tipos de datos y resultado.
entero real doble Funciones matem´ aticas b´ asicas.
entero entero real doble
El argumento siempre se escribe entre par´entesis.
abs (valor absoluto o m´odulo) sqrt (ra´ız 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 divisi´on 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 ,...,x n ) da el mayor de dos o varios argumentos min(x1 ,...,x n ) da el menor de dos o varios argumentos Ejemplo
program partesEnteras real :: x=2.3, y=-4.3, z=7.2 integer :: i=3, j=7, k=-5
! preasignadas
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 devolver´ıa en pantalla: 2 3 -5 -4 7.2 -5
5.
2 -4
Estructuras de decisi´ on
Operadores de comparaci´ on. ci´ on. El s´ımbolo /= indica =.
>
N´ otese la diferencia entre el igual de comparaci´on (==) y el de asigna<
<=
>=
5
==
/=
Operadores l´ ogicos.
Son cuatro: y, o, o exclusivo, negaci´on. .AND.
.OR.
.XOR.
.NOT.
Simple de sentencia ´unica on l´ ogica ) sentencia if (expresi´
Simple de sentencia m´ultiple on l´ ogica ) then if (expresi´ sentencia primera sentencia segunda ... end if
If-else if (...) then ... else ... end if
Decisi´ on m´ ultiple if (...) then ... else if (...) then ... else if (...) then ... else ! puede no estar ... end if
Puede haber estructuras anidadas. Ejemplo
program decisiones implicit none real :: x,y print*,’escribe x e y’ read*,x,y if (y<0) print*,’y es estrictamente negativo’ if (x==0) then print*,’x es nulo’ else if (x>0) then print*,’x es positivo’ else print*,’x es negativo’ end if if ((x>0 .AND. y>0).OR.(x<0 .AND. y<0)) then print*,’x*y es positivo’
6
else print*,’x*y es negativo o nulo’ end if end program decisiones
La orden select case.
select case ( criterio ) case(expr 1 ) ... case(expr 2 ) ... ... case default ... end select
La sintaxis es ! criterio devuelve un valor num´erico ! selecciona si se cumple el caso ! si se cumple este caso y no el precedente
! caso por defecto; puede no estar
Ejemplo
program casos implicit none integer :: op real :: x,y print*,’elija una opcion’ read*,op select case(op) case(1) print*,’op=1’ read*,x case(2) print*,’op=2’ read*,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 default print*,’op es cero’ end select end program casos
6.
Estructuras de repetici´ on Estructura general do ´ındice = inicio , final , incremento sentencias end do
7
Por defecto el incremento es 1. Puede haber bucles vac´ıos (p.ej. con inicio menor que final e incremento negativo): no se hace ninguna operaci´on. exit se puede emplear para forzar la salida del bucle. cycle se puede emplear para pasar directamente al comienzo de la siguiente repetici´on del bucle. Ejemplo
program repeticiones implicit none integer :: i,op real :: x do i=10,1,-1 print*, i**2 ! cuadrados de enteros del 10 al 1 end do do i=1,10 print*,i**2 ! lo mismo del rev´ es end do do i=1,10,-1 ! bucle vac´ıo print*,i end do nombre : do i=1,10 ! bucle etiquetado print*,’inserta x’ read*,x if (.NOT.x>=0) then print*,’x es negativo’ cycle ! se pasa de nuevo a la primera l´ınea, incrementando i end if print*,’¿Otra vez? (1->si)’ read*,op if (op/=1) exit ! si op =1 se sale del bucle end do nombre ! cierre de bucle etiquetado end program repeticiones
7.
Ficheros La instrucci´on b´asica de apertura de un fichero es open(unit=unidad , file=nombreFichero , status=tipo )
donde: • unidad es un n´ umero entero que identificar´a 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 borrar´a al cerrar Las instrucciones write( unidad ,*) read(unidad ,*)
sirven para escribir y leer en formato libre. La instrucci´on open dada abre ficheros de tipo texto. Se puede modificar para ficheros binarios (sin formato). El fichero se cierra con close( unidad ) Ejemplo
program ficheros implicit none real :: a,b integer :: i,n open(unit=1, file=’datos.dat’, status=’old’) open(unit=2, file=’salida.res’, status=’replace’) read(1,*) n do i=1,n read(1,*) a,b write(2,*) a+b end do close(1) close(2) end program ficheros
Si el fichero datos.dat tiene la forma 5 4. 6. -2. 1. 2.
2. 3. 4. 1.2e-3 1.1e2
el fichero salida.res tendr´a la forma 6. 9. 2. 1.0012 112.
9
8.
Funciones En principio una funci´on devuelve u ´ nicamente un valor. La sintaxis general es function nombre declaraci´ on de variables instrucciones return end function nombre nombre es la denominaci´on de la variable de salida y debe estar declarada con las dem´as.
Puede haber m´as de un return por funci´on. El final es innecesario. Ejemplo
program programaPrincipal implicit none integer :: i,n real :: x, f ! la funci´ on f se declara como otra variable print*,’inserta numero repeticiones’ read*,n do i=1,n print*,’escribe x’ read*,x print*,f(x) print*,x+f(x) end do end program programaPrincipal function f(y) implicit none real :: y,f,z if (y>=0) then z=y**3 f=z+z**2 else f=0 end if return end function f
9.
! z es una variable local
! f ser´a el valor de salida
Subrutinas La sintaxis de una subrutina es subroutine nombre (arg 1 ,..., arg n ) declaraci´ on de variables instrucciones end 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 ejecuci´on. La llamada a una subrutina se realiza mediante la orden call call nombre (var 1 ,..., var n )
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 programaPrincipal implicit none integer :: i,j real :: x,y,z print*,’introducir dos enteros y dos reales’ read*,i,j,x,y call intercambia(i,j) print*,i,j call potencias(x,y,z,i,j) end program programaPrincipal subroutine intercambiar(u,v) integer :: u,v,w w=u u=v v=w end subroutine intercambiar
! u,v son de entrada-salida; w es local
! no hace falta poner un return
subroutine potencias(x,y,z,i,j) integer, intent(in) :: i,j ! i,j son argumentos de entrada real :: x,y real, intent(out) :: z if ((i<0).OR.(j<0)) then z=x+y return ! regresa al programa principal end if x=x**i y=y**j z=x+y end subroutine potencias
11
10.
Vectores y matrices (1)
Declaraci´ on de matrices.
Se hace en la declaraci´on de variables, utilizando el especificador dimension . Ejemplo
... real, dimension(10) :: b,c ! vectores de 10 componentes real(kind=8), dimension(10,12) :: a ! matriz 10 × 12, doble precisi´ on real :: bb(10), cc(10,12) ! equivalente a poner dimension integer :: 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. Tambi´ en, 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 operaciones real :: a(10,10),b(10,10),c(10,10),v1(10),v2(10),t=3.,c1,c2 integer :: i,j do i=1,10 do j=1,10 a(i,j)=1./(i+j) end do v1(i)=i*6.5 end do b=t*a c=a+b c=-c b=c*a ! producto elemento a elemento v2=sin(v1) v1=t*v1+5*v2 ! combinaci´on lineal end program operaciones
Asignaciones y bucles impl´ıcitos.
La asignaci´ on 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,10 b(i)=2*(i-2)-1 end do
o en un bucle impl´ıcito 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 n´umero de funciones para manejar matrices y vectores. transpose(a) dot product(a,b) matmul(a,b) sum(a) product(a) maxval(a) minval(a) maxloc(a) minloc(a) shape(a)
devuelve la traspuesta de a calcula el producto escalar de dos vectores a y b calcula el producto de dos matrices a y b ; o el producto de una matriz a por un vector b devuelve la suma de todos los elementos de a devuelve el producto de todos los elementos de a devuelve el m´aximo valor de a devuelve el m´ınimo valor de a devuelve un vector con la posici´on relativa del m´aximo valor de a , esto es, la posici´on en el array si todos los ´ındices arrancan en 1. idem con el m´ınimo devuelve un vector con las dimensiones de a Ejemplo
program normasVector implicit none integer :: p(1),i real :: b(-1:5) b=(/ -1./9.,1.,((-3.)**(2*i),i=1,5) /) print*,sqrt(dot product(b,b)) ! norma 2 print*,sum(abs(b)) ! norma 1 print*,maxval(abs(b)) ! norma ∞ p=maxloc(abs(b)) ! posici´on relativa del m´aximo print*,p end program normasVector
13
Filas y columnas.
Si se tiene una matriz e i es un valor admisible del ´ındice
a(i,:)
es una referencia v´alida de la fila i –´esima, que se puede emplear como vector. De la misma forma a(:,i)
sirve para emplear la columna i –´esima. Las ´ordenes de escritura y lectura se pueden hacer por filas, etc Ejemplo
programa lectura implicit none integer :: i real :: a(10,5), b(6) print*,’Escribe un vector de seis componentes’ read*,b print*,’Escribe por filas una matriz 10 por 5’ do i=1,10 read*, a(i,:) end do print*,’Esta es su traspuesta’ do i=1,5 print*,a(:,i) end do end program lectura
Secciones de vectores y matrices.
La idea anterior se puede generalizar a la selecci´on de secciones
de matrices y vectores. Dada una matriz a de dimensi´on m× n, entonces a(i1:i2, j1:j2) es la matriz obtenida al seleccionar 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 el convenio limiteInferior:limiteSuperior:incremento
Ejemplo: Consideremos las matrices a1 y a2 1 5 9
2 6 10
3 7 11
4 8 12
-1 -3 -5
Entonces a(1:2,2:4) es la submatriz 2 6
La sentencia a1(2:3,1:2)=a2(2:3,:)
14
3 7
4 8
-2 -4 -6
transforma a1 en
1 -3 -5
2 -4 -6
3 7 11
4 8 12
1
-4
-6
-2
2
1
-4
-6
-2
-4
2
Ejemplo: dado el vector b 3
2
-2
se tiene que b(2:5) es mientras que b(6:2:-2) proporciona Ejemplo
... print*,maxval( (/ sum( abs(a(i,:)) ),i=1,n) /) ) ...
axj ! A = m´ ∞
|a i
ij
|
Ejemplo
subroutine gauss(n,a,b,x) implicit none integer :: n,i,j real :: a(n,n), b(n),x(n),c real :: aa(n,n+1) ! array local ajustado a tama~no exterior aa(1:n,1:n)=a aa(:,n+1)=b ! matriz ampliada do i=1,n ! eliminaci´on gaussiana do j=1,n c=aa(j,i)/aa(i,i) aa(j,i:n+1)=aa(j,i:n+1)-c*aa(i,i*n+1) end do end do do i=n,1,-1 ! sustituci´on regresiva x(i)=aa(i,n+1)-dot product(aa(i,i+1:n),x(i+1:n)) ! xi = b i − x(i)=x(i)/aa(i,i) end do end subroutine gauss
12.
n j =i+1 aij xj
Vectores y matrices (3) la orden reshape permite asignar tablas de diferentes dimensiones. La sintaxis elemental es reshape( tabla , perfil )
donde • tabla es la matriz–vector 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 2
3 4
5 6
Si seguidamente hacemos mm=reshape(m,(/3,2/))
obtenemos la matriz
13.
1 2 3
4 5 6
Matrices y vectores (4)
Secciones arbitrarias de matrices y vectores.
Si ind=(/ i 1 ,i 2 ,..., i r /)
entonces a(ind,:) selecciona las r filas de ´ındices correspondientes a(i 1 ,1) a(i 2 ,1)
a( i 1 ,2) a( i 2 ,2)
... ...
a(i r ,1)
a( i r ,2)
...
.. .
.. .
a( i 1 ,n) a( i 2 ,n)
.. .
a( i r ,n)
De manera an´aloga b(ind) es el vector de componentes b(i 1 )
b(i 2 )
...
b(i r )
Si en ind hay ´ındices repetidos, esto permite emplear a(ind,:) en operaciones, pero puede dar problemas en asignaciones. (ver comentarios sobre subrutinas) Igualmente, si indi=(/ indj=(/
i 1 ,i 2 ,..., j 1 , j 2 ,...,
i r /) j s /)
la submatriz a(indi,indj) hace referencia a a(i 1 , j 1 ) a(i 2 , j 1 )
a(i 1 , j 2 ) a(i 2 , j 2 )
... ...
a(i r , j 1 )
a(i r , j 2 )
...
.. .
.. .
16
a( i 1 , j s ) a( i 2 , j s )
.. .
a( i r , j s )
Ejemplo. Sean ind=(/1,4,2/) ; a y b las siguientes matriz y vector (respectivamente)
1 -2 2 1
2 2 1 3
3 1 3 1
-1 0 2 1
2
1
2
-3
2
Entonces a(ind,:) y a(2:3,ind) son respectivamente 1 1 -2
2 3 2
3 1 1
-1 1 0
-2 2
0 2
2 1
mientras que b(ind) es 2 Ejemplo.
-3
1
Con indi y indj los vectores de enteros dados respectivamente por 2 4 3
1 5 2
y a dada por 1 2 -2 2 2 1 1 3
3 -1 1 0 3 2 1 1
2 4 2 3
la secci´on a(indi,indj ) es -2 1 2
4 3 2
2 3 1
La instrucci´on a(indi,indj)=0
transformar´ıa a en
1 0 0 0
2 0 0 0
3 1 3 1
-1 0 2 1
2 0 0 0
En FORTRAN 90 es posible declarar matrices y vectores sin asignarles sus dimensiones, esperando a que se fijen durante el programa: Declaraci´ on din´ amica.
El especificador allocatable en la declaraci´on de un array, con los ´ındices de dimensiones mudos, deja la cuesti´on de la asignaci´on de memoria en suspenso. No obstante, hay que decidir a priori en la declaraci´on el n´umero de ´ındices del array. Con allocate se asignan dimensiones. Con deallocate se deasignan dimensiones. Ejemplo
program dinamica implicit none real, allocatable :: a(:,:), b(:) integer :: n,i,j,op do j=1,10
! una matriz y un vector
17
print*,’dar dimension’ read*,n allocate(a(n,2*n),b(2*n)) ! asignaci´on; ambas en la misma instrucci´on print*,’escribir matriz por filas’ do i=1,n read*,a(i,:) end do print*,’escribir vector’ read*,b print*,’su producto es:’, matmul(a,b) deallocate(a,b) ! desasignaci´on de memoria print*,’¿Otra vez? (1->Si)’ read*,op if(op/=1) exit end do end program dinamica
14.
Matrices y vectores en subrutinas La forma correcta de enviar una matriz a una subrutina es dando adem´as las dimensiones de dicha matriz 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 la subrutina se mantiene en el programa principal. Ejemplo
program pruebaSubrutina implicit none real, allocatable :: a(:,:), b(:) integer :: i,j,n,m print*,’Escribir dimensiones de la matriz’ read*,m,n allocate(a(m,n),b(m)) do i=1,m read*,a(i,:) end do call sumaColumnas(a,b,m,n) print*,b end program pruebaSubrutina subroutine sumaColumnas(a,b,k,l) implicit none integer :: k,l,i real :: a(k,l),b(k) b=(/ (sum(a(i,:)), i=1,l) /) end subroutine sumaColumnas
! suma de los elementos de cada fila
18
Lo anterior sigue siendo cierto si enviamos trozos ‘compactos’ de matrices como argumento. En el ejemplo anterior pod´ıamos haber puesto call sumaColumnas(a(1:m-2,1:n-1),b(1:m-2),m-2,n-1)
Esto no funciona si se env´ıan trozos de matrices con referencia mediante un conjunto de ´ındices. Si hacemos, por ejemplo, call sumaColumnas(a(ind,:),b(ind),mind,n)
donde ind es un vector de mind n´umeros enteros, se env´ıan copias de las secciones de a y b. Por tanto, 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 matriz o vector auxiliar, llamar a la subrutina y al final volcar el resultado sobre la matriz o vector original. Ejemplo
program pruebaSubrutina implicit none real, allocatable :: a(:,:), b(:), b2(:) integer :: i, j, n, m, mind integer, allocatable :: ind(:) print*,’Escribir dimensiones’ read*,m,n allocate(a(m,n),b(m)) print*,’Introducir la matriz por filas’ do i=1,m read*,a(i,:) end do print*,’¿Cuantas filas quieres tener en cuenta?’ read*, mind allocate(b2(mind),ind(mind)) print*,’Escribir numeros de filas’ read*,ind call sumaColumnas(a(ind,:),b2,mind,n) ! la parte de a pasa por valor b(ind)=b2 ! las filas que no se tienen en cuenta dan un cero print*,b end program pruebaSubrutina
Ejemplo
subroutine GaussSeidel(a,b,x,n,itmax,tol) implicit none integer, intent(in) :: n,itmax real :: a(n,n),x(n),xold(n),b(n) real, intent(in) :: tol real :: dif x=0. ! arrancamos del vector nulo do it=1,itmax xold=x do i=1,n x(i)=b(i)-dot product(a(i,1:i-1),x(1:i-1))&
19
! con i=1, nada
&-dot product(a(i,i+1:n),xold(i+1:n)) x(i)=x(i)/a(i,i) end do dif=maxval(abs(x-old)) ! norma infinito if (dif
15.
! sigue la l´ınea
Funciones como argumentos
Se emplea el especificador external en todas las apariciones de la misma. Ejemplo
function trapecio(f,a,b,n) integer :: n,i real :: trapecio,a,b,h real, external :: f ! f es un argumento funcional trapecio=0. h=(b-a)/n do i=1,n-1 trapecio=trapecio+h*f(a+i*h) end do trapecio=trapecio+h/2.*(f(a)+f(b)) end function trapecio function g1(x) real :: g1,x real, parameter :: pi=3.141592 g1=cos(2*pi*x) end function g1 function g2(x) real :: g2,x g2=(x-1.)**2 end function g2 program prueba ! programa principal integer :: num,op real :: a,b real :: trapecio real,external :: g1,g2 ! g1, g2 deben ser declaradas como externas print*,’Extremos del intervalo’ read*,a,b print*,’Numero de particiones’ read*,num print*,’Opcion:’ read*,op opciones : select case(op) case(1) print*,’Resultado:’,trapecio(g1,a,b,num) case(2) print*,’Resultado:’,trapecio(g2,a,b,num)
20
end select opciones end program prueba
16.
M´ odulos
M´ odulos simples: contienen informaci´on como declaraciones de variables y par´ametros muy repetitivas. Construcci´ on module nombreModulo informacion... end module nombreModulo
Utilizaci´ on program/function/subroutine nombreParte use nombreModulo declaraciones de variables sentencias del programa end program/function/subroutine nombreParte Ejemplo
module constantes real, parameter :: pi=3.141592, euler=0.57721566 end module constantes function g1(x) use constantes implicit none real :: g1,x g1=cos(2*pi*x) end function g1 function g2(x) implicit none real :: g2,x g2=(x-1.)**2 end function g2
M´ odulos librer´ıa: contienen funciones y subrutinas Construcci´ on module moduloSegundo contains function nombreFuncion ... end function nombreFuncion function otraFuncion ... end function otraFuncion end module moduloSegundo
21
Utilizaci´ on: igual que antes Ejemplo
module misfunciones contains function g1(x) use constantes implicit none real :: g1,x g1=cos(2*pi*x) end function g1 function g2(x) implicit none real :: g2,x g2=(x-1.)**2 end function g2 end module misfunciones program prueba use misfunciones implicit none integer :: num,op real :: a,b real :: trapecio
! programa principal ! no se declaran g1, g2
print*,’Extremos del intervalo’ read*,a,b print*,’Numero de particiones’ read*,num print*,’Opcion:’ read*,op opciones : 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 com´un. Forma: program/subroutine/function nombreParte type nombreTipo declaraciones de identificadores end type nombreTipo declaraciones de otras variables
22
type (nombreTipo) :: variablesConcretas ....
Ojo: hay que incluir la declaraci´on del tipo en todas las partes en que se use Ejemplo
program pruebatipos type fecha integer :: dia, mes, anho end type fecha type (fecha) :: mifecha type (fecha), external :: leefecha integer :: aux mifecha=leefecha() aux=mifecha %anho aux=aux-100*(aux/100) print*,’Mi fecha:’,mifecha %dia,mifecha %mes,aux end program pruebatipos function leefecha() type fecha integer :: dia, mes, anho end type fecha type (fecha) :: leefecha print*,’A~ no:’ read*,leefecha %anho print*,’Mes:’ read*,leefecha %mes print*,’Dia:’ read*,leefecha %dia return end function leefecha
! sin argumentos
Ejemplo
module misEstructuras type fecha integer :: dia, mes, anho end type fecha end module misEstructuras program pruebatipos use misEstructuras type (fecha) :: mifecha type (fecha), external :: leefecha integer :: aux ... ! sigue como antes end program pruebatipos
23
function leefecha() use misEstructuras type (fecha) :: leefecha ... ! sigue como antes end function leefecha
Ejemplo
module misEstructuras type fecha integer :: dia, mes, anho end type fecha type datos type(fecha) :: nacimiento ! un tipo puede utilizar otros tipos character(len=40) :: nombre, apellidos integer :: dni end type datos end module misEstructuras program pruebatiposdetipos use misEstructuras type (datos), allocatable :: lista(:) type (fecha), external :: leefecha integer :: i,num print*,’Cuantos datos?’ read*,num allocate(lista(num)) do i=1,num print*,’Nombre’ read ’(a40)’,lista(i) %nombre print*,’Apellidos’ read ’(a40)’,lista(i) %apellidos lista(i) %nacimiento=leefecha() end do print*,’Lista de a~nos de nacimiento’ do i=1,num print*,lista(i) %nacimiento %anho end do end program pruebatiposdetipos
18.
Funciones con valores vectoriales
FORTRAN 90 admite que una funci´on devuelva un array de datos. Precauci´ on: tienen que estar declaradas bajo una estructura interface
cada vez que se usen. La declaraci´on es un prototipo que aclara el tipo de variables y de resultado de la funci´ on. 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 prueba real :: phi,x(2) interface function rotacion(x,ang) real :: ang,x(2),rotacion(2) end function end interface print*,’angulo de rotacion’ read*,phi print*,’vector que se quiere rotar’ read*,x x=rotacion(x,phi) print*,’vector rotado=’,x end 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 puntero implicit none real,target ::aa,bb real, pointer:: c,d aa=4. bb=6. c=>aa ! c apunta a aa d=>bb ! d apunta a bb print*,’aa=’,aa,’bb=’,bb print*,’valor apuntado por c’,c,’valor apuntado por d’,d c=-6 print*,’aa=’,aa,’bb=’,bb print*,’valor apuntado por c’,c,’valor apuntado por d’,d c=>d ! c apunta a bb (a->d->bb) c=2 print*,’bb=’,bb
25
print*,’valor apuntado por c’,c,’valor apuntado por d’,d nullify(c) ! c no apunta a ninguna variable end program puntero
El programa anterior da como salida en pantalla a= 4.000000 b= valor apuntado por c a= -6.000000 b= valor apuntado por c b= 2.000000 valor apuntado por c
6.000000 4.000000 6.000000 -6.000000
valor apuntado por d
6.000000
valor apuntado por d
6.000000
2.000000
valor apuntado por d
2.000000
Las variables punteros pueden definirse para apuntar a estructuras m´as complicadas: arrays y estr´ucturas de datos.
20.
Ejemplo final
Problema.
Almacenamiento (y manipulaci´on) de matrices esencialmente vac´ıas.
Modelo sparse.
0 −2 0
real integer integer
1,5 2,5 0 0 0 0 ,5 0,25 0 0
1,5 2,5 −2 0,5 0,25 1 1 2 2 3 2 3 1 4 2
El formato debe guardar el tama˜no de la matriz original m´a s el n´umero de elementos no nulos (por comodidad) Problema pr´ actico. nada allocatable :
El tipo de datos debe admitir longitudes por determinar. Pero no puede haber
* en la definici´ on de un tipo de datos * como argumento de una subrutina o funci´on Sustituir allocatable por pointer y hacer lo mismo. Por dentro, el programa cambia mucho; por fuera, no. Plan.
M´ odulo con tipo sparse Subrutinas y funciones: • leer matriz sparse • pasar sparse a matriz • pasar matriz a sparse • multiplicar sparse por vector Crear un m´odulo con las interfaces de todo lo anterior Programa de prueba 26
module cosassparse type sparse integer :: nf,nc,nel real, pointer :: matriz(:) integer, pointer :: fil(:), col(:) end type sparse end module cosassparse module funcionessparse interface subroutine leersparse(u) use cosassparse type(sparse) :: u end subroutine leersparse function sparser(v,dim) use cosassparse type(sparse) :: sparser integer,dimension(2) :: dim real :: v(dim(1),dim(2)) end function sparser function matriz(a) use cosassparse type(sparse) :: a real :: matriz(a %nf,a %nc) end function matriz function sparseporvector(a,x,m) use cosassparse integer :: m type(sparse) :: a real :: x(m),sparseporvector(a %nf) end function sparseporvector end interface end module funcionessparse subroutine leersparse(a) use cosassparse type (sparse) :: a integer :: n,i print*,’Numero elementos, filas, columnas’ read*,n,a %nf,a %nc a %nel=n allocate(a %matriz(n),a %fil(n),a %col(n)) do i=1,n read*,a %matriz(i),a %fil(i),a %col(i) end do end subroutine leersparse Nota. a entra sin tama˜ no predefinido y sale con tama˜no asignado.
function matriz(a) use cosassparse type(sparse) :: a real :: matriz(a %nf,a %nc) integer :: i matriz=0.
27
do i=1,a %nel matriz(a %fil(i),a %col(i))=a %matriz(i) end do end function matriz function sparser(v,dim) use cosassparse type(sparse) :: sparser integer,dimension(2) :: dim real :: 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+1 sparser %matriz(cont)=v(i,j) sparser %fil(cont)=i sparser %col(cont)=j end if end do end do end function sparser function sparseporvector(a,x,m) use cosassparse integer :: m type(sparse) :: a real :: x(m),aux(a %nf),sparseporvector(a %nf) if (m /= a%nc) then print*,’error de dimensiones’ return end if aux=0 do i=1,a %nel aux(a %fil(i))=aux(a %fil(i))+& & a %matriz(i)*x(a %fil(i)) end do sparseporvector=aux end function sparseporvector program pruebas use cosassparse use funcionessparse type (sparse) :: a real,allocatable :: bb(:,:),cc(:,:),x(:),y(:) allocate(bb(3,5),x(5),y(3))
28
do i=1,3 bb(i,i+2)=3.*i bb(i,i)=-1.*i end do a=sparser(bb,shape(bb)) print*,a %matriz allocate(cc(a %nf,a %nc)) cc=matriz(a) do i=1,size(cc,dim=1) print*,cc(i,:) end do print* x=1. y=sparseporvector(a,x,5) print*,y end program pruebas
29