Buscando raíces Suponga que f : ℜ → ℜ es una función continua. Una raíz de f es una solución a la ecuación f ( x ) = 0 , Es decir, una raíz es un número a ∈ ℜ tal que f (a ) = 0 . Si se observa el gráfico de la función, digamos y = f ( x ) , una solución de f ( x ) = 0 es la coordenada horizontal del punto en el que el gráfico cruza el eje x . Iteración de punto fijo Sea g : ℜ → ℜ una función continua. Un punto fijo de g es un número a tal que g (a ) = a . Es decir, a es la solución de la ecuación g ( x ) = x . Gráficamente, un punto fijo es aquel en el la gráfica de la función y = g ( x ) cruza la línea y = x . El método de punto fijo es un método iterativo para resolver g ( x ) = x . Este método genera una secuencia de puntos x0 , x1 , x 2 , … que, se espera, converja a cierto punto a tal que g (a ) = a . Usando el valor inicial x0 se genera el siguiente usando x1 = g ( x0 ) y así sucesivamente. Esto nos lleva a la siguiente relación de recurrencia de primer orden: Método de punto fijo x n +1 = g ( x n ) puntofijo <- function(func, x0, tol = 1e-9, max.iter = 100) { tabla <- data.frame(matrix(0, max.iter, 2)) names(tabla) <- c("xn", "xn1") xn <- x0 xn1 <- func(xn) iter <- 1 tabla[1,] <- c(xn, xn1) while ((abs(xn1-xn) > tol) && (iter < max.iter)) { xn <- xn1; xn1 <- func(xn); iter <- iter + 1 tabla[iter,] <- c(xn, xn1) } print(tabla[-((iter + 1):max.iter),]) if (abs(xn1-xn) > tol) { cat("El algoritmo no converge\n") } else { cat("El algoritmo converge, la raíz es:", xn1, "\n") } } func <- function(x) return(exp(exp(-x))) Ejemplo 12: Hallar la raíz de f ( x ) = log( x ) − exp(− x ) . • Si x = exp(exp(− x )) = g1 ( x) > func <- function(x) return(exp(exp(-x))) > puntofijo(func, x0=2, tol = 1e-6, max.iter = 100) xn xn1 1 2.000000 1.144921 2 1.144921 1.374719 3 1.374719 1.287768 4 1.287768 1.317697 5 1.317697 1.307022 6 1.307022 1.310783 7 1.310783 1.309452 8 1.309452 1.309922 9 1.309922 1.309756 10 1.309756 1.309815 11 1.309815 1.309794 12 1.309794 1.309802 13 1.309802 1.309799 14 1.309799 1.309800 El algoritmo converge, la raíz es: 1.309800 • Si x = x + log( x ) − exp(− x ) = g 2 ( x) > func <- function(x) return(x+log(x)-exp(-x)) > puntofijo(func, x0=2, tol = 1e-6, max.iter = 20) xn xn1 1 2.000000 2.557812 2 2.557812 3.419490 3 3.419490 4.616252 4 4.616252 6.135946 5 6.135946 7.947946 6 7.947946 10.020506 7 10.020506 12.325096 8 12.325096 14.836729 9 14.836729 17.533834 10 17.533834 20.397966 11 20.397966 23.413402 12 23.413402 26.566710 13 26.566710 29.846369 14 29.846369 33.242432 15 33.242432 36.746259 16 36.746259 40.350296 17 40.350296 44.047895 18 44.047895 47.833172 19 47.833172 51.700891 El algoritmo no converge • Si x = x − log( x ) + exp(− x ) = g 3 ( x) > func <- function(x) return(x-log(x)+exp(-x)) > puntofijo(func, x0=2, tol = 1e-6, max.iter = 100) xn xn1 1 2.000000 1.442188 2 1.442188 1.312437 3 1.312437 1.309715 4 1.309715 1.309802 5 1.309802 1.309799 6 1.309799 1.309800 El algoritmo converge, la raíz es: 1.309800 El método de Newton – Raphson Suponga que la función f es diferenciable con derivada continua f / y una raíz a . Si x0 ∈ ℜ entonces la recta que pasa por el punto ( x0 , f ( x0 )) con pendiente f / ( x0 ) es la mejor aproximación lineal a la función f ( x ) en el punto x0 . La ecuación de esta recta esta dada por f / (x0 ) = f (x0 ) − y x0 − x Luego esta recta cruza el eje x en el punto x1 , el cual debería ser una mejor aproximación para a . Para encontrar x1 se observa que f / (x0 ) = f (x0 ) − 0 x 0 − x1 y entonces x1 = x0 − f (x0 ) f / (x0 ) Luego de obtener el valor de x1 , se usa el mismo procedimiento para obtener x 2 , x 2 = x1 − f ( x1 ) f / ( x1 ) y así sucesivamente. Método de Newton – Raphson x n +1 = x n − f (x n ) f / (xn ) newtonraphson <- function(func, x0, tol = 1e-9, max.iter = 100) { tabla <- data.frame(matrix(0, max.iter, 2)) names(tabla) <- c("xn", "xn1") xn <- x0 fx <- func1(xn) iter <- 0 while ((abs(fx[1]) > tol) && (iter < max.iter)) { xn1 <- xn - fx[1]/fx[2] tabla[iter+1,] <- c(xn, xn1) fx <- func1(xn1) xn <- xn1 iter <- iter + 1 } print(tabla[-((iter + 1):max.iter),]) if (abs(fx[1]) > tol) { cat("El algoritmo no converge\n") } else { cat("El algoritmo converge, la raíz es:", xn1, "\n") } } func1 <- function(x) { fx <- log(x) - exp(-x) dfx <- 1/x + exp(-x) return(c(fx, dfx)) } > newtonraphson(func1, x0=2, tol = 1e-6, max.iter = 100) xn xn1 1 2.000000 1.122020 2 1.122020 1.294997 3 1.294997 1.309709 4 1.309709 1.309800 El algoritmo converge, la raíz es: 1.309800 Integración numérica Frecuentemente es necesario calcular integrales definidas ∫ f (x ) dx de una función b a f. A partir del Teorema fundamental del cálculo se sabe que se puede encontrar una antiderivada tal que F / ( x ) = f (x ) , entonces ∫ f (x ) dx = F (a ) − F (b) b a Sin embargo para muchas funciones f es imposible escribir una antiderivada en forma cerrada, es decir, no existe una fórmula finita para F . En tales casos se debe usar la integral numérica para aproximar la integral definida. Por ejemplo, en estadística es frecuente usar integrales definidas para la densidad normal estándar Φ(z ) = z ∫ −∞ 1 − x2 2 e dx 2π En este capitulo se considera que se tiene una función integrable f ( x ) y un intervalo [a, b] tal que se desea aproximar ∫ f (x ) dx b a Se subdivide el intervalo [a, b] en n subintervalos de igual longitud h = (b − a ) n . Los límites de estos intervalos son a = x0 , x1 , x 2 , L , x n = b El objetivo es aproximar la integral en cada uno de los subintervalos y luego agregar todas estas aproximaciones para obtener la aproximación total del la integral original. Regla trapezoidal La aproximación trapezoidal es obtenida aproximando el área bajo y = f ( x ) sobre el subintervalos [ xi , xi +1 ] usando un trapecio. Es decir, la función f ( x ) se aproxima usando una recta sobre el intervalo [ xi , xi +1 ] . La altura del trapecio es h y las longitudes de las bases son f ( xi ) y f ( xi +1 ) . Finalmente el área del trapecio es h ( f (xi ) + f (xi +1 )) 2 Luego se suman las áreas para todos los subintervalos para obtener la aproximación T de la integral ∫ f (x ) dx : b a Regla trapezoidal T= h ( f (x0 ) + 2 f (x1 ) + 2 f (x2 ) + L + 2 f (xn−1 ) + f (xn )) 2 Ejemplo 13: Aproximar 1 ∫ 4 x dx = 1 3 0 trapecio <- function(func, a, b, n = 100) { h <- (b-a)/n x.vec <- seq(a, b, by = h) f.vec <- sapply(x.vec, func) T <- h*(f.vec[1]/2 + sum(f.vec[2:n]) + f.vec[n+1]/2) return(T) } func <- function(x) return(4 * x^3) > trapecio(a = 0, b = 1) [1] 1.0001 > trapecio(a = 0, b = 1, n = 1000) [1] 1.000001 > trapecio(a = 0, b = 1, n = 1000000) [1] 1 La regla de Simpson La regla de Simpson divide el intervalo [a, b] en n subintervalos, n es par, luego en cada par de intervalos consecutivos se aproxima f ( x ) usando una parábola, es decir un polinomio de grado 2. Sean u < v < w tres puntos con distancia h . Para x ∈ [u, w] se puede aproximar f ( x ) usando una parábola que pase por los puntos (u, f (u )) , (v, f (v )) y (w, f (w)) . Existe solo una parábola p( x ) que cumple esta condición cuya fórmula es p (x ) = f (u ) (x − v )(x − w) + f (v ) (x − u )(x − w) + f (v ) (x − u )(x − v ) (u − v )(u − w) (v − u )(v − w) (w − u )(w − v ) Como una aproximación al área bajo la curva y = f ( x ) se usa álgebra puede probarse que ∫ p(x ) dx . Con algo de w u h ∫ p(x ) dx = 3 ( f (u ) + 4 f (v ) + f (w)) w u Si n es par se pueden agregar las aproximaciones para obtener la aproximación de Simpson S a la integral ∫ f (x ) dx . b a Regla de Simpson h S = ( f (x 0 ) + 4 f ( x1 ) + 2 f ( x 2 ) + 4 f ( x3 ) + L + 4 f ( x n −1 ) + f ( x n )) 3 simpson <- function(func, a, b, n = 100) { h <- (b-a)/n x.vec1 <- seq(a+h, b-h, by = 2*h) x.vec2 <- seq(a+2*h, b-2*h, by = 2*h) f.vec1 <- sapply(x.vec1, func) f.vec2 <- sapply(x.vec2, func) S <- h/3*(func(a) + func(b) + 4*sum(f.vec1) + 2*sum(f.vec2)) return(S) } func <- function(x) return(4 * x^3) > simpson(func, a = 0, b = 1) [1] 1 Ejemplo 13: Aproximar Φ(0 ) = 1 ∫ −1 1 − x2 2 e dx . 2π func <- function(x) return(exp(-x^2/2)/sqrt(2*pi)) > simpson(func, a = -1, b = 1) [1] 0.6826895