Sei sulla pagina 1di 9

Subrutinas en Fortran 95 para la resolucin

de ecuaciones no lineales de una variable


Pablo Santamara
v0.2.5 (Septiembre 2013)
1. Introduccin
En general, las races de una ecuacin no lineal f(x) = 0 no pueden ser obtenidas por frmulas explcitas
cerradas, con lo que no es posible obtenerlas en forma exacta. De este modo, para resolver la ecuacin nos
vemos obligados a obtener soluciones aproximadas a travs de algn mtodo numrico.
Estos mtodos son iterativos, esto es, a partir de una o ms aproximaciones iniciales para la raz, generan
una sucesin de aproximaciones x
0
, x
1
, x
2
, . . . que esperamos convergan al valor de la raz buscada. El
proceso iterativo se contina hasta que la aproximacin se encuentra prxima a la raz dentro de una
tolerancia > 0 preestablecida. Como la raz no es conocida, dicha proximidad, medida por el error absoluto
|x
n+1
|, no puede ser computada. Sin un conocimiento adicional de la funcin f(x) o su raz, el mejor
criterio para detener las iteraciones consiste en proceder hasta que la desigualdad
|x
n+1
x
n
|
|x
n+1
|
<
se satisfaga, dado que esta condicin estima en cada paso el error relativo. Ahora bien, puede ocurrir en ciertas
circunstancias que la desigualdad anterior nunca se satisfaga, ya sea por que la sucesin de aproximaciones
diverge o bien que la tolerancia escogida no es razonable. En tal caso el mtodo iterativo no se detiene
nunca. Para evitar este problema consideramos adems un nmero mximo de iteraciones a realizarse. Si
este nmero es excedido entonces el problema debe ser analizado con ms cuidado.
Cmo se escoge un valor correcto para las aproximaciones iniciales requeridas por los mtodos? No existe
una respuesta general para esta cuestin. Para el mtodo de biseccin es suciente conocer un intervalo que
contenga la raz, pero para el mtodo de Newton, por ejemplo, la aproximacin tiene que estar sucientemente
cercana a la raz para que funcione
1
. En cualquier caso primeras aproximaciones iniciales para las races
pueden ser obtenidas gracando la funcin f(x).
En las siguientes secciones presentamos implementaciones de los mtodos numricos usuales como
subrutinas Fortran. Con el n de proporcionar subrutinas de propsito general, las mismas tienen entre sus
argumentos a la funcin f involucrada, la cual pude ser entonces implementada por el usuario como un
subprograma FUNCTION externo con el nombre que quiera. Otros argumentos que requieren estas subrutinas
son los valores para las aproximaciones iniciales que necesite el mtodo, una tolerancia para la aproximacin
nal de la raz y un nmero mximo de iteraciones. La raz aproximada es devuelta en otro de los argumentos.
Dado que el mtodo puede fallar utilizamos tambin una variable entera como clave de error para advertir al
programa principal. Por convencin tomaremos que si dicha clave es igual a cero, entonces el mtodo funcion
correctamente y el valor devuelto es la raz aproximada dentro de la tolerancia preescrita. En cambio, si la
clave de error es distinta de cero, entonces ocurri un error. La naturaleza del error depender del mtodo,
pero un error comn a todos ellos es que el nmero mximo de iteraciones fue alcanzado.
Con el n de aprovechar la capacidad de Fortran 95 de detectar errores de tipo en los argumentos
al llamar a las subrutinas, debemos hacer explcita la interface de las mismas. La forma ms simple y
poderosa de efectuar sto consiste en agrupar las mismas en un mdulo, al que denominaremos roots. En
nuestra implementacin todas las cantidades reales sern de la clase de doble precisin, la cual, para mxima
exibilidad, est denida en forma paramtrica utilizando el modulo precision
2
, el cual, por completitud
en la exposicin, incluimos a continuacin junto con el esquema de nuestro mdulo roots.
1
De hecho, efectuando algunas iteraciones del mtodo de biseccin podemos obtener una buena aproximacin para iniciar el
mtodo de Newton.
2
La discusin sobre el uso de este mdulo se encuentra en el apunte Un mdulo para parametrizar las clases de tipos de
datos reales.
1
Cdigo 1. Implementacin del mdulo roots
MODULE precision
IMPLICIT NONE
INTEGER, PARAMETER :: SP = SELECTED_REAL_KIND(6,37)
INTEGER, PARAMETER :: DP = SELECTED_REAL_KIND(15,307)
END MODULE precision
MODULE roots
USE precision, ONLY: WP => DP
CONTAINS
SUBROUTINE biseccion(f,a,b,n,tol,raiz,clave)
....
END SUBROUTINE biseccion
SUBROUTINE newton(f,df,x0,n,tol,raiz,clave)
....
END SUBROUTINE newton
SUBROUTINE birge_vieta(a,m,x0,n,tol,raiz,clave)
....
END SUBROUTINE birge_vieta
SUBROUTINE secante(f,x0,x1,n,tol,raiz,clave)
....
END SUBROUTINE secante
SUBROUTINE punto_fijo(f,x0,n,tol,raiz,clave)
....
END SUBROUTINE punto_fijo
END MODULE roots
El cdigo correspondiente a cada subrutina, que debe insertarse donde se encuentran los puntos suspensivos,
ser discutido por separado en las siguientes secciones.
2. Mtodo de biseccin
El mtodo de biseccin comienza con un intervalo [a, b ] que contiene a la raz. Entonces se computa el
punto medio x
0
= (a + b)/2 del mismo y se determina en cual de los dos subintervalos [a, x
0
] o [x
0
, b ] se
encuentra la raz analizando el cambio de signo de f(x) en los extremos. El procedimiento se vuelve a repetir
con el nuevo intervalo as determinado. Es claro que la raz es acotada en cada paso por el intervalo as
generado y que una estimacin del error cometido en aproximar la raz por el punto medio de dicho intervalo
es igual a la mitad de la longitud del mismo. Esta estimacin es utilizada, en la siguiente implementacin del
mtodo, como criterio de paro para la sucesin de aproximaciones.
Cdigo 2. Implementacin del mtodo de biseccin
SUBROUTINE biseccion(f,a,b,n,tol,raiz,clave)
! ---------------------------------------------------
! METODO DE BISECCION para encontrar una solucin
! de f(x)=0 dada la funcin continua f en el intervalo
! [a,b] donde f(a) y f(b) tienen signos opuestos.
! ---------------------------------------------------
! Bloque de declaracin de argumentos
! ---------------------------------------------------
IMPLICIT NONE
INTERFACE
FUNCTION f(x) ! Funcin que define la ecuacin
IMPORT :: WP
2
IMPLICIT NONE
REAL(WP) :: f
REAL(WP), INTENT(IN) :: x
END FUNCTION f
END INTERFACE
REAL(WP), INTENT(IN) :: a ! Extremo izquierdo del intervalo inicial
REAL(WP), INTENT(IN) :: b ! Extremo derecho del intervalo inicial
INTEGER, INTENT(INOUT) :: n ! Lmite de iteraciones/iteraciones realizadas
REAL(WP), INTENT(IN) :: tol ! Tolerancia para el error absoluto
REAL(WP), INTENT(OUT) :: raiz ! Aproximacin a la raiz
INTEGER, INTENT(OUT) :: clave ! Clave de xito:
! 0 : xito
! >0 : iteraciones excedidas
! <0 : no se puede proceder (f de igual signo
en a y b)
! ---------------------------------------------------
! Bloque de declaracin de variables locales
! ---------------------------------------------------
INTEGER :: i
REAL(WP) :: xl, xr, error
! ---------------------------------------------------
! Bloque de procesamiento
! ---------------------------------------------------
clave = 1
xl = a
xr = b
IF (SIGN(1.0_WP,f(xl))
*
SIGN(1.0_WP,f(xr)) > 0.0_WP) THEN
clave = -1
RETURN
ENDIF
DO i=1,n
error = (xr-xl)
*
0.5_WP
raiz = xl + error
IF (error < tol) THEN
clave = 0
n = i
EXIT
ENDIF
IF ( SIGN(1.0_WP,f(xl))
*
SIGN(1.0_WP,f(raiz)) > 0.0_WP) THEN
xl = raiz
ELSE
xr = raiz
ENDIF
ENDDO
END SUBROUTINE biseccion
3. Mtodo de NewtonRaphson
El mtodo de Newton comienza con una aproximacin inicial x
0
dada, a partir de la cual se genera la
sucesin de aproximaciones x
1
, x
2
, . . ., siendo x
n+1
la abscisa del punto de interseccin del eje x con la recta
tangente a f(x) que pasa por el punto (x
n
, f(x
n
)). Esto conduce a la frmula de iteracin
x
n+1
= x
n

f(x
n
)
f

(x
n
)
, n = 1, 2, . . .
Nuestra implementacin de la subrutina correspondiente requiere que se pase tambin como argumento
no slo la funcion f(x), sino tambin su derivada f

(x), la cual debe ser implementada por el usuario, al


igual que f(x), como una FUNCTION.
3
Cdigo 3. Implementacin del mtodo de NewtonRaphson
SUBROUTINE newton(f,df,x0,n,tol,raiz,clave)
! ---------------------------------------------------
! Metodo DE NEWTON-RAPHSON para encontrar una
! solucin de f(x)=0 dada la funcin derivable
! f y una aproximacin inicial x0.
! ---------------------------------------------------
! Bloque de declaracin de argumentos
! ---------------------------------------------------
IMPLICIT NONE
INTERFACE
FUNCTION f(x) ! Funcin que define la ecuacin
IMPORT :: WP
IMPLICIT NONE
REAL(WP) :: f
REAL(WP), INTENT(IN) :: x
END FUNCTION f
FUNCTION df(x) ! Derivada de la funcin que define la ecuacin
IMPORT :: WP
IMPLICIT NONE
REAL(WP) :: df
REAL(WP), INTENT(IN) :: x
END FUNCTION df
END INTERFACE
REAL(WP), INTENT(IN) :: x0 ! Aproximacin inicial a la raz
INTEGER, INTENT(INOUT) :: n ! Lmite de iteraciones/iteraciones realizadas
REAL(WP), INTENT(IN) :: tol ! Tolerancia para el error relativo
REAL(WP), INTENT(OUT) :: raiz ! Aproximacin a la raz
INTEGER, INTENT(OUT) :: clave ! Clave de xito:
! 0 : xito
! >0 : iteraciones excedidas
! ---------------------------------------------------
! Declaracin de variables locales
! ---------------------------------------------------
INTEGER :: i
REAL(WP) :: xx0
! ---------------------------------------------------
! Bloque de procesamiento
! ---------------------------------------------------
clave = 1
xx0 = x0
DO i=1,n
raiz = xx0 - f(xx0)/df(xx0)
IF (ABS(raiz-xx0) < tol
*
ABS(raiz) ) THEN
clave = 0
n = i
EXIT
ENDIF
xx0 = raiz
END DO
END SUBROUTINE newton
4. Mtodo de Newton para ecuaciones algebraicas
En el caso particular en que f(x) es un polinomio, el mtodo de Newton puede ser ecientemente
implementado si la evaluacin de f(x
n
) (y su derivada) es realizada por el mtodo iterativo de Horner. En
efecto, supongamos que f(x) es un polinomio de grado m:
f(x) = a
0
+ a
1
x + a
2
x
2
+ + a
m
x
m
,
4
la evaluacin de f(x
n
) por la regla de Horner procede computando

b
m
= a
m
b
k
= a
k
+ b
k+1
x
n
k = m 1, . . . , 0
siendo, entonces
b
0
= f(x
n
),
en tanto que f

(x
n
) es computada haciendo

c
m
= b
m
c
k
= b
k
+ c
k+1
x
n
k = m 1, . . . , 1
siendo, entonces
c
1
= f

(x
n
).
El mtodo de Newton se reduce as a
x
n+1
= x
n

b
0
c
1
El procedimiento resultante se conoce a menudo como mtodo de BirgeVieta.
Nuestra implementacin en la siguiente subrutina pasa los coecientes del polinomio en un arreglo a de
(m+1) componentes, siendo m el grado del polinomio (valor que tambin es requerido como argumento). En
la subrutina, para simplicar el tratamiento de los subndices, el arreglo es declarado con el ndice inferior 0,
no 1, de manera que a(0) = a
0
, a(1) = a
1
, . . . , a(M) = a
m
.
Cdigo 4. Implementacin del mtodo de BirgeVieta
SUBROUTINE birge_vieta(a,m,x0,n,tol,raiz,clave)
! ---------------------------------------------------
! METODO DE BIRGE-VIETA para resolver ECUACIONES
! ALGEBRAICAS: P (x) = 0 donde P es un polinomio de
! grado m de coeficientes reales.
! El mtodo se basa en el mtodo de Newton-Raphson
! implementando el esquema de Horner para la evalua-
! cin del polinomio y su derivada.
! ---------------------------------------------------
! Bloque de declaracin de argumentos
! ---------------------------------------------------
IMPLICIT NONE
INTEGER, INTENT(IN) :: m ! Grado del polinomio
REAL(WP), INTENT(IN) :: a(0:m) ! Vector de m+1 elementos conteniendo
! los coeficientes del polinomio
REAL(WP), INTENT(IN) :: x0 ! Aproximacin inicial a la raz
REAL(WP), INTENT(IN) :: tol ! Tolerancia para el error relativo
INTEGER, INTENT(INOUT) :: n ! Limite de iteraciones/iteraciones realizadas
REAL(WP), INTENT(OUT) :: raiz ! Aproximacin a la raiz
INTEGER, INTENT(OUT) :: clave ! Clave de xito:
! 0 : xito
! >0 : iteraciones excedidas
! ---------------------------------------------------
! Bloque de declaracin de variables locales
! ---------------------------------------------------
INTEGER :: i, j
REAL(WP):: xx0,b,c
! ---------------------------------------------------
! Bloque de procedimiento
! ---------------------------------------------------
clave = 1
xx0 = x0
DO i=1,n
! -------------------------
! Esquema de Horner
! -------------------------
5
b = a(m)
c = a(m)
DO j=m-1,1,-1
b = b
*
xx0+a(j)
c = c
*
xx0+b
ENDDO
b = b
*
xx0+a(0)
! -------------------------
! Mtodo de Newton
! -------------------------
raiz = xx0 - b/c
IF (ABS(raiz-xx0) < tol
*
ABS(raiz)) THEN
clave = 0
n = i
EXIT
END IF
xx0 = raiz
END DO
END SUBROUTINE birge_vieta
5. Mtodo de la secante
El mtodo de la secante procede a partir de dos aproximaciones iniciales obteniendo la aproximacin
x
n+1
como la abscisa del punto de interseccin del eje x con la recta secante que pasa por los puntos
(x
n1
, f(x
n1
)) y (x
n
, f(x
n
)). La frmula de iteracin es entonces
x
n+1
= x
n
f(x
n
)
(x
n
x
n1
)
f(x
n
) f(x
n1
)
, n = 2, 3, . . .
El mtodo de la secante, si bien no converge tan rpido como Newton, tiene la gran ventaja de no requerir
la derivada de la funcin. Eso s, ahora se necesitan dos aproximaciones iniciales para arrancar el mtodo.
Cdigo 5. Implementacin del mtodo de la secante
SUBROUTINE secante(f,x0,x1,n,tol,raiz,clave)
! ---------------------------------------------------
! ALGORITMO DE LA SECANTE para encontrar una solucin
! de f(x)=0, siendo f una funcin continua, dada las
! aproximaciones iniciales x0 y x1.
! ---------------------------------------------------
! Bloque de declaracin de argumentos
! ---------------------------------------------------
IMPLICIT NONE
INTERFACE
FUNCTION f(x) ! Funcin que define la ecuacin
IMPORT :: WP
IMPLICIT NONE
REAL(WP) :: f
REAL(WP), INTENT(IN) :: x
END FUNCTION f
END INTERFACE
REAL(WP), INTENT(IN) :: x0,x1 ! Aproximaciones iniciales a la raz
INTEGER, INTENT(INOUT) :: n ! Lmite mximo de iteraciones/ iteraciones
realizadas
REAL(WP), INTENT(IN) :: tol ! Tolerancia para el error relativo
REAL(WP), INTENT(OUT) :: raiz ! Aproximacin a la raiz
INTEGER, INTENT(OUT) :: clave ! Clave de xito:
! 0 : xito
! >0 : iteraciones excedidas
! ---------------------------------------------------
! Bloque de declaracin de variables locales
! ---------------------------------------------------
6
INTEGER :: i
REAL(WP):: xx0, xx1, fx0, fx1
! ---------------------------------------------------
! Bloque de procesamiento
! ---------------------------------------------------
clave = 1
xx0 = x0
xx1 = x1
fx0 = f(x0)
fx1 = f(x1)
DO i= 2,n
raiz = xx1 - fx1
*
((xx1-xx0)/(fx1-fx0))
IF (ABS(raiz-xx1) < tol
*
ABS(raiz)) THEN
clave = 0
n = i
EXIT
ENDIF
xx0 = xx1
fx0 = fx1
xx1 = raiz
fx1 = f(raiz)
END DO
END SUBROUTINE secante
6. Iteracin de punto jo
El mtodo de punto jo requiere que se reescriba la ecuacin f(x) = 0 en la forma
x = (x)
y entonces, a partir de una aproximacin inicial x
0
, se obtiene la sucesin de aproximaciones x
1
, x
2
, ... segn
x
n+1
= (x
n
), n = 1, 2, . . .
En la siguiente implementacin, es importante recordar que la funcin que es pasada por argumento es
ahora (x) y no f(x), funcin que debe ser implementada por el usuario como una FUNCTION.
Cdigo 6. Implementacin del mtodo de punto jo
SUBROUTINE punto_fijo(f,x0,n,tol,raiz,clave)
! ---------------------------------------------------
! ALGORITMO DE PUNTO FIJO o DE APROXIMACIONES SUCESIVAS
! para encontrar una solucin de x=f(x) dada una
! aproximacin inicial x0.
! ---------------------------------------------------
! Bloque de declaracin de argumentos
! ---------------------------------------------------
IMPLICIT NONE
INTERFACE
FUNCTION f(x) ! Funcin que define la ecuacin
IMPORT :: WP
IMPLICIT NONE
REAL(WP) :: f
REAL(WP), INTENT(IN) :: x
END FUNCTION f
END INTERFACE
REAL(WP), INTENT(IN) :: x0 ! Aproximacin inicial a la raz
INTEGER, INTENT(INOUT) :: n ! Limite de iteraciones/ iteraciones
realizadas
REAL(WP), INTENT(IN) :: tol ! Tolerancia para el error relativo
REAL(WP), INTENT(OUT) :: raiz ! Aproximacin a la raiz
INTEGER, INTENT(OUT) :: clave ! Clave de xito:
! 0 : xito
7
! >0 : iteraciones excedidas
! ---------------------------------------------------
! Bloque de declaracin de variables locales
! ---------------------------------------------------
INTEGER :: i
REAL(WP) :: xx0
! ---------------------------------------------------
! Bloque de procesamiento
! ---------------------------------------------------
clave = 1
xx0 = x0
DO i=1,n
raiz = f(xx0)
IF (ABS(raiz-xx0) < tol
*
ABS(raiz)) THEN
clave = 0
n = i
EXIT
ENDIF
xx0 = raiz
END DO
END SUBROUTINE punto_fijo
7. Ejemplo
Como ejemplo del uso de nuestro mdulo roots consideremos el problema de determinar la raz de la
ecuacin
cos x x = 0.
Al gracar las curvas y = x e y = cos x, vemos en la g. 1, que la intereseccin de las mismas ocurre dentro
del intervalo [0.6, 0.8]. As pues, la raz buscada se encuentra en el interior de este intervalo y con l podemos
proceder a calcular la raz con el mtodo de biseccin asumiendo una tolerancia para el error absoluto de
1
2
10
6
y un nmero mximo de, digamos, 100 iteraciones. El siguiente programa implementa lo requerido.
Cdigo 7. Determinacin de la raz de la ec. cos x x = 0
PROGRAM ejemplo
USE precision, WP => DP
USE roots, ONLY: biseccion
IMPLICIT NONE
INTERFACE
FUNCTION f(x)
IMPORT :: WP
IMPLICIT NONE
REAL(WP) :: f
REAL(WP), INTENT(IN) :: x
END FUNCTION f
END INTERFACE
REAL(WP) :: a, b, tol, raiz
INTEGER :: n, clave
! Datos de iniciales
a = 0.6_WP
b = 0.8_WP
tol = 0.5E-6_WP
n = 100
! Determinar la raz
CALL biseccion(f,a,b,n,tol,raiz,clave)
IF (clave == 0) THEN
WRITE(
*
,
*
) 'Raz = ', raiz
WRITE(
*
,
*
) 'Nmero de iteraciones realizadas =', n
ELSE
WRITE(
*
,
*
) 'Error =', clave
ENDIF
END PROGRAM ejemplo
8
0
0.2
0.4
0.6
0.8
1
1.2
1.4
1.6
0 0.2 0.4 0.6 0.8 1 1.2 1.4
x
cos(x)
Figura 1. Determinacin de una aproximacin inicial de la raz de la funcin
cos x x.
FUNCTION f(x)
! Funcin que define la ecuacin
USE precision, WP => DP
IMPLICIT NONE
REAL(WP) :: f
REAL(WP), INTENT(IN) :: x
f = cos(x) - x
RETURN
END FUNCTION f
La compilacin del mismo procede en la lnea de comandos como sigue:
$ gfortran -Wall -o ejemplo roots.f90 ejemplo.f90
Su ejecucin arroja entonces:
$ ./ejemplo
Raz = 0.73908500671386723
Nmero de iteraciones realizadas = 19
As, pues, la raz buscada, con seis decimales correctos, es 0.739085.
9

Potrebbero piacerti anche