Práctica 3
Transcripción
Práctica 3
Métodos Numéricos EDOs práctica 3 EPSEM-UPC Abril 2008 • EDO lineal. Resolución manual • EDO lineal. Resolución exacta con dsolve. - Definir solución como función. - Representar solución. • EDO lineal. Resolución numérica con dsolve. • Método de Euler - Programa para método de Euler. - Método de Euler con dsolve. Opción method=classical. • Método de Euler modificado - Programa para método de Euler modificado. - Método de Euler modificado con dsolve. Opción method=classical[heunform]. • Programa para método de Taylor de segundo orden. Ejercicio 1. En este primer ejerccio nos ocupamos de aplicar los recursos vistos en el tema en la resolución del problema de valor inicial y'=1+y/x, y(1)=2, para valores de x en el intervalo [1,2]. Más concretamente, vamos a resolver los siguientes apartados. 1. Resolución manual de la EDO lineal. 2. Resolución manual del problema de valor inicial. 3. Resolución exacta con dsolve. - Represantación gráfica de la solución. - Cálculo de y(2). 4. Resolución numérica de la EDO. - Cálculo de y(2). - Cálculo del error. 5. Programa para aplicar el método de Euler. - Escribir programa con h=0.25. - Calcular y(2) con h=0.1, cálculo del error. - Cálcular y(2) con h=0.01, h=0.001, cálculo de los errores. - Usar dsolve para obtener un programa que permita aplicar el método de Euler. 6. Programa para aplicar el método de Euler modificado. - Escribir programa con h=0.25. - Calcular y(2) con h=0.1, cálculo del error. - Cálcular y(2) con h=0.01, h=0.001, cálculo de los errores. - Usar dsolve para obtener un programa que permita aplicar el método de Euler modificado. 7. Método de Taylor de segundo orden. - Escribir un programa con h=0.25. - Calcular y(2) con h=0.1, cálculo del error. Comparación con los métodos anteriores. Page 1 - Cálcular y(2) con h=0.01, h=0.001, cálculo de los errores, 1., 2. Puedes consultar la solución manual en Ejemplo 4.1 del resumen de clase. 3. Resolución exacta con dsolve. Empezamos entrando la EDO. > edo:=diff(y(x),x)=1+y(x)/x; edo := ∂ ∂x y( x ) = 1 + y( x ) x Solución general. > s:=dsolve(edo,y(x)); s := y( x ) = x ln( x ) + x _C1 Solución del problema de valor inicial. > s:=dsolve({edo,y(1)=2},y(x)); s := y( x ) = x ln( x ) + 2 x Construimos una función con la solución. > sf:=unapply(rhs(s),x); sf := x → x ln( x ) + 2 x Representación gráfica. > plot(sf(x),x=1..2); 5 4.5 4 3.5 3 2.5 2 1 1.2 1.4 x 1.6 1.8 2 1.6 1.8 2 Ajustamos el intervalo de y > plot(sf(x),x=1..2,y=0..6); 6 5 4 y 3 2 1 0 1 1.2 1.4 x Calculamos el valor de y(2) > v:=sf(2); v := 2 ln( 2 ) + 4 > vf:=sf(2.); vf := 5.386294361 4. Resolución numérica de la EDO. Usamos dsolve con la opción type=numeric. Maple nos proporciona un programa para aplicar el método de Runge-Kutta 4-5. > sn:=dsolve({edo,y(1)=2},y(x),type=numeric); sn := proc(rkf45_x) ... end Aproximación de y(2). > vap:=sn(2); Page 2 vap := [ x = 2, y( x ) = 5.386294319282972 ] Cálculo del error. Tenemos que extraer el valor de la aproximación. Para ello hemos de: 1. Acceder a la segunda componente de vap. Observa que es una ecuación. 2. Tomar la parte derecha de esa ecuación. > vap[2]; y( x ) = 5.386294319282972 > vn:=rhs(vap[2]); vn := 5.386294319282972 > er:=abs(vf-vn); er := .42 10-7 5. Método de Euler. Construimos el programa con paso h=0.25. > F:=(x,y)->1+y/x; a:=1.; b:=2.; yb0:=2.; n:=4; h:=(b-a)/n; x0:=a; for j from 0 to n-1 do `****************`; yb.(j+1):=yb.j+h*F(x.j,yb.j); x.(j+1):=x.j+h; od; `**** error ***`; lprint(`Valor exacto =`,vf); lprint(`Valor aproximado =`,yb.n); lprint(`Error =`, abs(vf-yb.n)); F := ( x, y ) → 1 + y x a := 1. b := 2. yb0 := 2. n := 4 h := .2500000000 x0 := 1. **************** yb1 := 2.750000000 x1 := 1.250000000 **************** yb2 := 3.550000000 x2 := 1.500000000 **************** yb3 := 4.391666667 x3 := 1.750000000 **************** yb4 := 5.269047620 x4 := 2.000000000 **** error *** Valor exacto = 5.386294361 Valor aproximado = 5.269047620 Error = .117246741 > Resolución con h=0.01, tomamos n=100. Acabamos el programa con dos puntos para evitar que se impriman los resultados intermedios. > F:=(x,y)->1+y/x; Page 3 a:=1.; b:=2.; yb0:=2.; n:=10; h:=(b-a)/n; x0:=a; for j from 0 to n-1 do `****************`; yb.(j+1):=yb.j+h*F(x.j,yb.j); x.(j+1):=x.j+h; od:# <---- acabamos con dos puntos `**** error ***`; lprint(`Valor exacto =`,vf); lprint(`Valor aproximado =`,yb.n); lprint(`Error =`, abs(vf-yb.n)); F := ( x, y ) → 1 + y x a := 1. b := 2. yb0 := 2. n := 10 h := .1000000000 x0 := 1. **** error *** Valor exacto = 5.386294361 Valor aproximado = 5.337542805 Error = .48751556e-1 Dado que no vamos a untilizar los resultados intermedios, podemos escribir una versión del programa que utiliza una sóla variable para los puntos de xj y una variable para todos los valores ybj. > F:=(x,y)->1+y/x; a:=1.; b:=2.; yy:=2.; n:=10; h:=(b-a)/n; xx:=a; for j from 0 to n-1 do `****************`; yy:=yy+h*F(xx,yy); xx:=xx+h; od; `**** error ***`; lprint(`Valor exacto =`,vf); lprint(`Valor aproximado =`,yy); lprint(`Error =`, abs(vf-yy)); F := ( x, y ) → 1 + y x a := 1. b := 2. yy := 2. n := 10 h := .1000000000 xx := 1. **************** yy := 2.300000000 xx := 1.100000000 **************** Page 4 yy := 2.609090909 xx := 1.200000000 **************** yy := 2.926515151 xx := 1.300000000 **************** yy := 3.251631701 xx := 1.400000000 **************** yy := 3.583891108 xx := 1.500000000 **************** yy := 3.922817182 xx := 1.600000000 **************** yy := 4.267993256 xx := 1.700000000 **************** yy := 4.619051683 xx := 1.800000000 **************** yy := 4.975665665 xx := 1.900000000 **************** yy := 5.337542805 xx := 2.000000000 **** error *** Valor exacto = 5.386294361 Valor aproximado = 5.337542805 Error = .48751556e-1 Aproximamos el valor de y(2) con paso h=0.01 > F:=(x,y)->1+y/x; a:=1.; b:=2.; yy:=2.; n:=100; h:=(b-a)/n; xx:=a; for j from 0 to n-1 do `****************`; yy:=yy+h*F(xx,yy); xx:=xx+h; od: `**** error ***`; lprint(`Valor exacto =`,vf); lprint(`Valor aproximado =`,yy); lprint(`Error =`, abs(vf-yy)); F := ( x, y ) → 1 + y x a := 1. b := 2. yy := 2. n := 100 h := .01000000000 xx := 1. Page 5 **** error *** Valor exacto = 5.386294361 Valor aproximado = 5.381306867 Error = .4987494e-2 Aproximación de y(2) con h=0.001. > F:=(x,y)->1+y/x; a:=1.; b:=2.; yy:=2.; n:=1000; h:=(b-a)/n; xx:=a; for j from 0 to n-1 do `****************`; yy:=yy+h*F(xx,yy); xx:=xx+h; od: `**** error ***`; lprint(`Valor exacto =`,vf); lprint(`Valor aproximado =`,yy); lprint(`Error =`, abs(vf-yy)); F := ( x, y ) → 1 + y x a := 1. b := 2. yy := 2. n := 1000 h := .001000000000 xx := 1. **** error *** Valor exacto = 5.386294361 Valor aproximado = 5.385794485 Error = .499876e-3 Obtención de un programa para el método de Euler con dsolve . > sne:=dsolve({edo,y(1)=2},y(x),type=numeric,method=classical,stepsize=0.001); sne := proc(x_classical) ... end > sne(2); [ x = 2, y( x ) = 5.385794486120386 ] Si nos limitamos a los 10 primeros dígitos, vemos que el programa construido por Maple proporciona el mismo resultado que nuestro programa. 6. Método de Euler modificado Construimos el programa con h=0.25. > F:=(x,y)->1+y/x; a:=1.; b:=2.; yb0:=2.; n:=4; h:=(b-a)/n; x0:=a; for j from 0 to n-1 do `******************`; k1:=F(x.j,yb.j); x.(j+1):=x.j+h; k2:=F(x.(j+1),yb.j+h*k1); yb.(j+1):=yb.j+h/2*(k1+k2); od; `**** error ***`; lprint(`Valor exacto =`,vf); lprint(`Valor aproximado =`,yb.n); lprint(`Error =`, abs(vf-yb.n)); Page 6 F := ( x, y ) → 1 + y x a := 1. b := 2. yb0 := 2. n := 4 h := .2500000000 x0 := 1. ****************** k1 := 3.000000000 x1 := 1.250000000 k2 := 3.200000000 yb1 := 2.775000000 ****************** k1 := 3.220000000 x2 := 1.500000000 k2 := 3.386666667 yb2 := 3.600833334 ****************** k1 := 3.400555556 x3 := 1.750000000 k2 := 3.543412699 yb3 := 4.468829366 ****************** k1 := 3.553616781 x4 := 2.000000000 k2 := 3.678616781 yb4 := 5.372858562 **** error *** Valor exacto = 5.386294361 Valor aproximado = 5.372858562 Error = .13435799e-1 Aproximación y error para h=0.01. > F:=(x,y)->1+y/x; a:=1.; b:=2.; yb0:=2.; n:=100; h:=(b-a)/n; x0:=a; for j from 0 to n-1 do `******************`; k1:=F(x.j,yb.j); x.(j+1):=x.j+h; k2:=F(x.(j+1),yb.j+h*k1); yb.(j+1):=yb.j+h/2*(k1+k2); od: `**** error ***`; lprint(`Valor exacto =`,vf); lprint(`Valor aproximado =`,yb.n); lprint(`Error =`, abs(vf-yb.n)); F := ( x, y ) → 1 + a := 1. Page 7 y x b := 2. yb0 := 2. n := 100 h := .01000000000 x0 := 1. **** error *** Valor exacto = 5.386294361 Valor aproximado = 5.386269511 Error = .24850e-4 Aproximación y error para h=0.001 > F:=(x,y)->1+y/x; a:=1.; b:=2.; yb0:=2.; n:=1000; h:=(b-a)/n; x0:=a; for j from 0 to n-1 do `******************`; k1:=F(x.j,yb.j); x.(j+1):=x.j+h; k2:=F(x.(j+1),yb.j+h*k1); yb.(j+1):=yb.j+h/2*(k1+k2); od: `**** error ***`; lprint(`Valor exacto =`,vf); lprint(`Valor aproximado =`,yb.n); lprint(`Error =`, abs(vf-yb.n)); F := ( x, y ) → 1 + y x a := 1. b := 2. yb0 := 2. n := 1000 h := .001000000000 x0 := 1. **** error *** Valor exacto = 5.386294361 Valor aproximado = 5.386294102 Error = .259e-6 Obtención de un programa para el método de Euler modificado con dsolve. Hemos de usar la opción method=classical[heunform]. > snem:=dsolve({edo,y(1)=2},y(x),type=numeric,method=classical[heunform],stepsize=0.001) ; snem := proc(x_classical) ... end > snem(2); [ x = 2, y( x ) = 5.386294111266229 ] Si nos limitamos a los primeros 10 dígitos, vemos que el valor proporcionado por dsolve coincide con el valor que hemos obtenido con nuestro programa. 7. Método de Taylor de segundo orden. Empezamos con un step h=0.25 > F:=(x,y)->1+y/x; F1:=unapply(diff(F(x,y),x),x,y); F2:=unapply(diff(F(x,y),y),x,y); a:=1.; b:=2.; yb0:=2.; n:=4; h:=(b-a)/n; Page 8 x0:=a; for j from 0 to n-1 do `*******************`; yb.(j+1):=yb.j+h*F(x.j,yb.j)+h^2/2*(F1(x.j,yb.j)+F2(x.j,yb.j)*F(x.j,yb.j)); x.(j+1):=x.j+h; od; `**** error ***`; lprint(`Valor exacto =`,vf); lprint(`Valor aproximado =`,yb.n); lprint(`Error =`, abs(vf-yb.n)); F := ( x, y ) → 1 + y F1 := ( x, y ) → − y F2 := x x2 1 ( x, y ) → x a := 1. b := 2. yb0 := 2. n := 4 h := .2500000000 x0 := 1. ******************* yb1 := 2.781250000 x1 := 1.250000000 ******************* yb2 := 3.612500000 x2 := 1.500000000 ******************* yb3 := 4.485416666 x3 := 1.750000000 ******************* yb4 := 5.394047619 x4 := 2.000000000 **** error *** Valor exacto = 5.386294361 Valor aproximado = 5.394047619 Error = .7753258e-2 Aproximación con h=0.001 > F:=(x,y)->1+y/x; F1:=unapply(diff(F(x,y),x),x,y); F2:=unapply(diff(F(x,y),y),x,y); a:=1.; b:=2.; yb0:=2.; n:=1000; h:=(b-a)/n; x0:=a; for j from 0 to n-1 do `*******************`; yb.(j+1):=yb.j+h*F(x.j,yb.j)+h^2/2*(F1(x.j,yb.j)+F2(x.j,yb.j)*F(x.j,yb.j)); x.(j+1):=x.j+h; od: `**** error ***`; lprint(`Valor exacto =`,vf); lprint(`Valor aproximado =`,yb.n); lprint(`Error =`, abs(vf-yb.n)); Page 9 F := ( x, y ) → 1 + y F1 := ( x, y ) → − y F2 := x x2 1 ( x, y ) → x a := 1. b := 2. yb0 := 2. n := 1000 h := .001000000000 x0 := 1. **** error *** Valor exacto = 5.386294361 Valor aproximado = 5.386294501 Error = .140e-6 > Page 10