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 endAdemá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 casoLa 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 endSe 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 endObservar 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 endSe 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 endLa 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.