Funciones

En Fortran hay funciones preprogramadas (intrínsecas) que ya las hemos visto: raíz cuadrada, funciones trigonométricas, etc. Pero además de estas funciones se le permite al programador crear las suyas. Existen dos métodos para construir funciones en Fortran: a través de la Función Sentencia o de la Función Externa.

Es muy útil poder crear funciones, ahorra tiempo, hace los programas más compactos, enfocados y elegantes. Además permite que uno utilice funciones que ya se encuentran disponibles en libros o en páginas de internet. Sobre esto último, existen sitios web donde se discute cuál es el mejor algoritmo para una tarea determinada y cuales son sus mejores implementaciones en distintos lenguajes. Las funciones han tomado históricamente distintos nombres (procedimientos, subprogramas, etc) en distintos lenguajes de programación pero siempre existe una manera de definirlas.

Función Sentencia

Consiste en una sola sentencia aritmética definida en el programa. Esta estructura existe en otros lenguajes, por ejemplo, en Python se la llama función Lambda.
Se las define al comienzo del programa dándole un nombre a la función y se las construye usando variables ficticias, es decir que no son las variables del programa, sólo se las usa como referencia para construir la fórmula matemática de la función y sólo valen en la sentencia. Es decir, para indicar el orden y en que lugar se encuentran las distintas variables de la fórmula a calcular.
La forma sería la siguiente:
función(var1,var,2,var3...) = expresión matemática usando las variables var1, var2, var3,...
Donde función es el nombre que se le da a la función, las var1,var2, var3, etc son las variables que se usan en la expresión matemática. Estas variables indican el orden de los argumentos con los que defino la función. Por eso su orden es muy importante en el momento de llamarla.
Ejemplos:
Si se necesita una función discriminante (para ecuaciones cuadráticas), la puedo construir de esta manera al comienzo del programa (donde defino los tipos de variables del programa) escribiendo:
DISC(A,B,C) = B**2-4.*A*C
Entonces en el programa se puede escribir:
Program prueba_de_funcion_sentencia

DISC(A,B,C) = B**2-4.*A*C

\(\vdots\)

X= DISC(24.5, 34.5, 67.8) +25.4*C3+MAG

\(\vdots\)

MAGROJA = SQRT(DISC(z1+3, 45.5*8, (z2+z4+f6)+28)

\(\vdots\)
Detalles a tener en cuenta:

Ejemplo de aplicación de Funciones - Integral por trapecios

De los cursos de análisis matemático uno adquiere la idea de que la única manera de resolver los problemas pasa por obtener siempre su solución analítica. Pero en la vida real, esa situación es más bien rara, o imposible. Incluyendo el hecho que en el caso particular de una integral puede que esta no tenga primitiva o que sea muy complejo o laborioso encontrarla. Más aún si lo que se lo quiere resolver es una ecuación diferencial. Por esta razón, en problemas muy complejos se usan los sistemas de computación con el fin aproximar la solución, es decir obtener una solución numérica. Esta puede ser en algunos casos una solución exactas o a veces aproximada. Desarrollaremos un caso en particular como ejemplo.
Uno de los métodos más simples de aproximar numéricamente el resultado de una integral definida es el método de los trapecios. Vamos a ver con un ejemplo cómo funciona este método desde el punto de vista computacional. Un tratamiento más profundo de sus propiedades incluyendo ventajas y desventajas se estudia en cursos de análisis numérico.

Aproximación por trapecios

Con este método lo que se desea es integrar la función \(f(x)\) en el intervalo \([a,b]\), es decir queremos medir el área bajo la curva. Para ello dividiremos el intervalo en varios subintervalos más pequeños y veremos cómo se podría aproximar con un trapecio al área bajo la curva de la función \(f(x)\). Ya que la idea del método es dividir el área en \(n\) subintervalos de tamaño h, por lo que \(h = (b-a)/n\). Si llamo \(x_i\) a los puntos que separan cada uno de estos subintervalos tendríamos que:
\(a=x_0\), \(x_i=x_0+ih\) y \(b= x_n\)
En la figura 1.1 veamos cómo sería esta situación con un dibujo de la función \(f(x)\) entre los límites \(x_i\) y \(x_{i+1}\), (donde \(x_{i+1} = x_i + h\)).
:

Entonces, el área para el trapecio del la figura es:
\[A_i = h f(x_i) + \frac{h}{2} [f(x_{i+1}) - f(x_i)] = \frac{h}{2} [f(x_{i+1}) + f(x_i)]\]
y la aproximación a la integral será la suma de todos los trapecios \(A_i\)
\[Integral = \sum_{i=0}^{n}{ A_i}\]
si hago todos lo reemplazos, obtengo:1
\[Integral = \frac{h}{2}[ f(a)+f(b)] + h \sum_{i=1}^{n-1}f(x_i)\]
Veamos el programa que haría este cálculo y tomemos con función \(f(x)=x^2\)
y la integraremos en el intervalo [0,1]
En forma teórica:
\[\int_{0}^{1} x^2 dx = 1/3\]
Veamos como sería un programa y la precisión de los resultados.
\(\ \ \ \ \ \ \ \) program x2

\(\ \ \ \ \ \ \ \) real*8 integral

\(\ \ \ \ \ \ \ \) f(z)=z*z

\(\ \ \ \ \ \ \ \)

\(\ \ \ \ \ \ \ \) x0=0.

\(\ \ \ \ \ \ \ \) xn=1.

\(\ \ \ \ \ \ \ \) read(*,*)n

\(\ \ \ \ \ \ \ \) h=(xn-x0)/n

\(\ \ \ \ \ \ \ \) integral=0.

\(\ \ \ \ \ \ \ \)

\(\ \ \ \ \ \ \ \) do i=1,n-1

\(\ \ \ \ \ \ \ \ \ \ \ \) x=i*h

\(\ \ \ \ \ \ \ \ \ \ \ \) integral=integral+f(x)

\(\ \ \ \ \ \ \ \) enddo

\(\ \ \ \ \ \ \ \)

\(\ \ \ \ \ \ \ \) integral=integral*h+(f(xn)+f(x0))*h/2

\(\ \ \ \ \ \ \ \) write(*,*)’Para ’, n,’ intervalos, la integral es=’,integral

\(\ \ \ \ \ \ \ \) end
Si corro este programa para distintos valores de la cantidad de intervalos, obtengo los resultados del tabla 1.1. Como puede verse en la tabla no sirve pensar que se puede llegar al límite infinito sumando una cantidad gigantesca de trapecios debido a los errores de redondeo. Un buen resultado se obtiene cerca del 1,000,000 de trapecios, tomando intervalos más pequeños el resultado se deteriora. Pero por otro lado, la tabla nos muestra que según lo que se requiera de precisión en el resultado hay formas de evaluar este problema, y además de encontrar y determinar un resultado aproximado muy bueno incluyendo alguna idea de la precisión. En este caso hemos obtenido la integral con un error \(10^{-7}\).

En este programa usamos \(f(x)=x^2\) como función a integrar. Si quisiera integrar otra función en otro rango de valores, sólo tendría que cambiar la definición de la función por otra y modificar los límites del intervalo a integrar. El programa no requiere ninguna otra modificación. Sólo hay quecambiar la función y volver a compilarlo.

Resultados de sumar N cantidad de trapecios. Puede notarse que a partir de cierto límite en el tamaño de los intervalos la aproximación deja de funcionar.
Cantidad de intervalos Resultado de la aproximación
de la integral
10 0.33500001696869747
100 0.33334997741140865
1,000 0.33333354714617608
10,000 0.33333330969899705
100,000 0.33333330800677946
1,000,000 0.33333333080419814
10,000,000 0.33333334502431866
100,000,000 0.33333332725965703
1,000,000,000 0.33333330505514902

El método de trapecios, no es el método más usado pero si es un método que tiene interés académico porque sirve para entender la complejidad del cálculo y determinar cotas teóricas al problema de aproximar la integral. Existen métodos muchos mejores que el de trapecios y modificaciones para hacerlo mucho más eficiente.

Función Externa

La función sentencia que vimos en la sección anterior es muy útil pero tiene sus limitaciones. La mayor de ellas es que sólo permite una fórmula matemática que se escriba en un solo renglón. Por ejemplo, una función a trozos no se podría programar como función sentencia, ya que se necesitarían al menos más de un renglón para programarla con el comando IF().
En cambio, la función externa, trabaja como si fuera otro programa y este es llamado por el programa principal al igual que la función sentencia. Un esquema simple, sería:
\(\ \ \ \ \ \ \ \)program Principal

\(\ \ \ \ \ \ \ \)real*4 F

\(\ \ \ \ \ \ \ \vdots\)

\(\ \ \ \ \ \ \ \)A= F(x)+5.0

\(\ \ \ \ \ \ \ \vdots\)

\(\ \ \ \ \ \ \ \)END

\(\ \ \ \ \ \ \ \)Function F(x)

\(\ \ \ \ \ \ \ \vdots\)

\(\ \ \ \ \ \ \ \)F = \(\cdots\)

\(\ \ \ \ \ \ \ \)RETURN

\(\ \ \ \ \ \ \ \)END
Como se ve en el esquema, la función fue escrita en el mismo archivo del programa, después de la sentencia END2. Notar que en general la función tiene la misma estructura que un programa salvo por el inicio como FUNCTION nombre(variables que recibe) y la orden RETURN que devuelve la ejecución hacia el programa principal.
Detalles que definen a la función externa:

Por ejemplo, si programamos una función que nos calcule la serie \(\sum_{i=1}^n{1/i^k}\), donde básicamente le enviamos N, K y nos devuelve la suma de la serie, sería así:
\(\ \ \ \ \ \ \ \) Function Serie(n,k)
\(\ \ \ \ \ \ \ \) Serie=0.

\(\ \ \ \ \ \ \ \) DO i=1, n

\(\ \ \ \ \ \ \ \ \ \ \) x = i

\(\ \ \ \ \ \ \ \ \ \ \) Serie = Serie + 1/ x**k

\(\ \ \ \ \ \ \ \) ENDDO
\(\ \ \ \ \ \ \ \) RETURN

\(\ \ \ \ \ \ \ \) end


  1. Regla mnemotécnica: La suma extremos dividido dos más la suma de los puntos intermedios y todo esto multiplicado por el intervalo↩︎

  2. Puede escribirse en un archivo aparte, pero debe compilarse con el programa que la utiliza. Ejemplo: gfortran programa.f funcion1.f funcion2.f -o programa.↩︎