Un subprograma es una pequeña pieza de código que resuelve un subproblema bien definido. En un programa grande, se tiene con frecuencia que resolver el mismo subproblema con diferentes tipos de datos. En vez de replicar el código, estas tareas pueden resolverse con subprogramas. El mismo subprograma puede ser llamado varias veces con distintas entradas de datos.
En Fortran se tienen dos tipos diferentes de subprogramas, conocidas como funciones y subrutinas.
Un ejemplo simple muestra como usar una función:
x = cos(pi/3.0)En este caso la función coseno cos de 60º, asignará a la variable x el valor de 0.5 (si pi ha sido definido correctamente; Fortran 77 no tiene constantes incorporadas). Hay varias funciones incorporadas en Fortran 77. Algunas de las más comunes son:
abs valor absoluto
min valor mínimo
max valor máximo
sqrt raíz cuadrada
sin seno
cos coseno
tan tangente
atan arco tangente
exp exponencial (natural)
log logaritmo (natural)
En general, una función siempre tiene un tipo. Varias de las
funciones incorporadas mencionadas anteriormente son sin embargo
genéricas.
Por lo tanto en el ejemplo anterior pi y x podrían ser del tipo real o del tipo double precision. El compilador revisará los tipos y usará la versión correcto de la función cos
(real o double precision). Desafortunadamente, Fortran no es un lenguaje
polimórfico, por lo que en general, el programador debe hacer
coincidir los tipos de las variables y las funciones.
Se revisa a continuación como implementar las funciones escritas por el usuario. Supongamos el siguiente problema: un meteorólogo ha estudiado los niveles de precipitación en el área de una bahía y ha obtenido un modelo (función) ll(m,t) donde ll es la cantidad de lluvia, m es el mes, y t es un parámetro escalar que depende de la localidad. Dada la fórmula para ll y el valor de t, calcular la precipitación anual
La forma obvia de resolver el problema es escribir un ciclo que corra sobre todos los meses y sume los valores de ll. Como el cálculo del valor de ll es un subproblema independiente, es conveniente implementarlo como una función. El siguiente programa principal puede ser usado:
program lluvia
real r, t, suma
integer m
read (*,*) t
suma = 0.0
do m = 1, 12
suma = suma + ll(m, t)
end do
write (*,*) 'La precipitación Anual es ', suma, 'pulgadas'
stop
end
Además, la función
ll tiene que ser definida como una función de Fortran. La fórmula del
meteorólogo es:
ll(m,t) = t/10 * (m**2 + 14*m + 46) si la expresión es positiva
ll(m,t) = 0 otro caso
La correspondiente función en Fortran es
real function ll(m,t)
integer m
real t
ll = 0.1*t * (m**2 + 14*m + 46)
if (ll .LT. 0) ll = 0.0
return
end
Se puede observar que la estructura de una función es parecida a la del
programa principal. Las diferencias son:
Para resumir, la sintaxis general de una función en Fortran 77 es:
tipo function nombre (lista_de parámetros)
declaraciones
sentencias
return
end
La función es llamada simplemente usando el nombre de la función y haciendo una lista de argumentos entre paréntesis.
subroutine nombre (lista_de_parámetros)
declaraciones
sentencias
return
end
Observar que las subrutinas no tienen tipo y por consecuencia no pueden
hacerse asignación al momento de llamar al procedimiento.
Se da un ejemplo de una subrutina muy sencilla. El propósito de la subrutina es intercambiar dos valores enteros.
subroutine iswap (a, b)
integer a, b
c Variables Locales
integer tmp
tmp = a
a = b
b = tmp
return
end
Se debe observar que hay dos bloques de declaración de variables en el código.
Primero, se declaran los parámetros de entrada/salida, es decir, las variables
que son comunes al que llama y al que recibe la llamada. Después, se declaran
las variables locales, esto es, las variables que serán sólo
conocidas dentro del subprograma. Se pueden usar los mismos nombres de
variables en diferentes subprogramas.
program llamaint
integer m, n
c
m = 1
n = 2
call iswap(m, n)
write(*,*) m, n
stop
end
La salida de este programa es "2 1", justo como se habría esperado.
Sin embargo, si Fortran 77 hubiera hecho una llamada por valor entonces la
salida hubiera sido "1 2", es decir, las variables m y
n hubieran permanecido sin cambio. La razón de esto último, es que
solamente los valores de m y n habrían sido copiados a la
subrutina iswap, a pesar de que a y b hubieran sido
cambiados dentro de la subrutina, por lo que los nuevos valores no sería
regresados al programa que hizo la llamada.
En el ejemplo anterior, la llamada por referencia era lo que se quería hacer. Se debe tener cuidado al escribir código en Fortran, porque es fácil introducir efectos laterales no deseados. Por ejemplo, en ocasiones es tentador usar un parámetro de entrada en un subprograma como una variable local y cambiar su valor. No se deberá hacer nunca, ya que el nuevo valor se propagará con un valor no esperado.
Se revisará más conceptos cuando se vea la sección de Arreglos en subprogramas para pasar arreglos como argumentos.
program prbfac
c
c Ejercicio A, seccion 11.
c Programa Main para probar la función factorial.
c
integer n, fac
10 continue
write(*,*) 'Dame n: '
read (*,*) n
if (n.gt.0) then
write(*,*) ' El factorial de', n, ' es', fac(n)
goto 10
endif
c End of loop
stop
end
(Tip: Se tiene que usar un ciclo para implementar la función ya que Fortran 77
no soporta llamadas recursivas.)
write(*,*) 'Advertencia: Raices Complejas.'También se deberá escribir un programa main que pruebe la subrutina.