Professional Documents
Culture Documents
La ecuación cúbica
Expresamos una ecuación cúbica en la forma equivalente
x3+ax2+bx+c=0
dividiendo todos los coeficientes por el primero, de modo que el coeficiente del
término x3 es la unidad.
Las fórmulas que permiten calcular las raíces de una ecuación cúbica son las siguientes:
function x = raices_3(p)
Q=(p(2)*p(2)-3*p(3))/9;
R=(2*p(2)^3-9*p(2)*p(3)+27*p(4))/54;
x=zeros(3,1); %reserva memoria para un vector de tres elementos
if (R*R)<(Q^3)
tetha=acos(R/sqrt(Q^3));
x(1)=-2*sqrt(Q)*cos(tetha/3)-p(2)/3;
x(2)=-2*sqrt(Q)*cos((tetha+2*pi)/3)-p(2)/3;
x(3)=-2*sqrt(Q)*cos((tetha-2*pi)/3)-p(2)/3;
else
A=-sign(R)*nthroot(abs(R)+sqrt(R*R-Q^3),3);
if A==0
B=0;
else
B=Q/A;
end
x(1)=(A+B)-p(2)/3;
x(2)=-(A+B)/2-p(2)/3+(sqrt(3)*(A-B)/2)*sqrt(-1); %mejor que i
x(3)=-(A+B)/2-p(2)/3-(sqrt(3)*(A-B)/2)*sqrt(-1);
end
end
En la ventana de comandos llamamos a la función raices_3 para calcular las raíces de la
ecuación cúbica x3+0x2-7x-6
f(x)=0
donde f(x) es una función continua que se desea determinar sus raíces reales. Se
sustituye f(x) por la ecuación equivalente
x=g(x)
x1=g(x0)
xn=g(xn-1)
La condición de finalización
Primero, introducimos el valor inicial x, la primera aproximación, calculamos el valor del
coseno de x, el valor devuelto (segunda aproximación), lo guardamos de nuevo en la
variable x y repetimos el proceso indefinidamente. El código aunque correcto, necesita
terminarse en algún momento, cumpliendo una determinada condición.
Cuando el valor absoluto del cociente entre la diferencia de dos términos consecutivos
de la sucesión y uno de los términos, sea menor que cierta cantidad ε.
Modificamos el script para sustituir el bucle for por un bucle while indefinido que se
interrumpe cuando se cumpla la condición de terminación.
El criterio de convergencia
No todas las ecuaciones pueden resolverse por este método, solamente si el valor
absoluto de la derivada de la función g(x) en la vecindad de la raíz ξ es menor que la
unidad (la pendiente de la recta bisectriz del primer cuadrante es uno). En la figura,
podemos ver como es imposible encontrar la solución marcada por un puntito negro en
la intersección entre la curva y la recta bisectriz del primer cuadrante, ya que la
sucesión xi diverge.
x3-x-1=0
tiene una raíz en el intervalo (1, 2) ya que f(1)=-1<0 y f(2)=5>0. Esta ecuación puede
escribirse de la forma
x=x3-1
En este caso,
y por tanto,
>>raiz_trascedente (0.5,0.0001)
ans = 0.7391
Vamos a hacer que este código sea independiente de la función x=g(x) cuya raíz
queremos calcular. En el capítulo funciones, ya hemos visto que a una función se le
pueden pasar diversos tipos de datos.
function x=raiz_trascendente(f,x0,ERROR)
while(1)
x=f(x0);
if abs((x-x0)/x)<ERROR
break
end
x0=x;
end
end
Método de Newton-Raphson
El desarrollo en serie de la función f(x) en el punto x es
function x=newton_raphson(f,f_prima,x0,ERROR)
while(1)
x=x0-f(x0)/f_prima(x0);
if abs((x-x0)/x)<ERROR
break
end
x0=x;
end
end
A la función newton_raphson, le pasamos la función f y su derivada f_prima, la
aproximación inicial x0 y la tolerancia ERROR.
Dibujamos la función en color rojo. Probamos con x0=0.1, trazamos la recta tangente a
la curva que pasa por el punto(x0,y0), punto señalado en la gráfica con 0. Esta recta
corta al eje X en el punto de abscisa x1. Trazamos la tangente a la curva en el punto
(x1,y1), punto señalado en la gráfica con 1. Esta recta corta al eje X en el punto de
abscisa x2 y así, sucesivamente.
8
f=@(x) x.*sin(pi*x)-exp(-x);
fp=@(x) sin(pi*x)+x*pi*cos(pi*x)+exp(-x);
hold on
x=linspace(0,0.8,50);
plot(x,f(x),'r')
x0=0.1;
for i=1:5
x1=x0-f(x0)/fp(x0);
h=line([x0,x0],[0,f(x0)],'color','g');
set(h,'lineStyle', '--')
line([x1,x0],[0,f(x0)],'color','b')
x0=x1;
end
hold off
grid on
xlabel('x')
ylabel('y')
title('Método de Newton-Raphson')
Calculamos la raíz
function x=newton_raphson_1(f,x0,ERROR)
DELTA=1.0e-6;
while(1)
x=x0-DELTA*f(x0)/(f(x0+DELTA)-f(x0));
if abs((x-x0)/x)<ERROR
break
end
x0=x;
end
end
A la función newton_raphson_1, le pasamos la función f, la aproximación inicial x0 y la
tolerancia ERROR. Consideremos la función f(x)=x-cos(x), en la ventana de comandos
escribimos
Método de la secante
Este método comienza con dos puntos (x0, f(x0)) y (x1, f(x1)), tales que los signos
de f(x0) y f(x1) son opuestos, es decir, f(x0)·f(x1)<0
Se dibuja una línea recta entre los dos puntos cuya ecuación es
donde m=(an+bn)/2 es el punto medio del intervalo (an, bn) cada vez más pequeño.
O bien, cuando se han completado el bucle, sin que se haya encontrado la raíz
emitiendo un mensaje de error.
function x2=secante(f,x0,x1,MAXITER)
ERROR=0.0001;
for i=1:MAXITER
f0=f(x0);
f1=f(x1);
x2=x0-f0*(x1-x0)/(f1-f0);
if (abs(2*(x2-x1)/(x2+x1))<ERROR | abs(2*(x2-x0)/(x2+x0))<ERROR)
break;
end
if f(x2)*f0<0
x1=x2;
else
x0=x2;
end
end
if(i==MAXITER)
error('no se ha encontrado la raiz')
end
end
A la función secante, le pasamos la función f, el intervalo en el que se encuentra la raíz
(x0, x1) y el número de iteracciones MAXITER
f(x)=0
Para hallar la raíz de la función en el intervalo (a, b), se divide el intervalo en la mitad.
m=(a+b)/2
Como los puntos extremos de la izquierda a1, a2, ... an, ...forman una sucesión creciente
y acotada, y los de la derecha b1, b2, ... bn, ... una sucesión acotada decreciente, existe
un límite común que es la raíz ξ buscada.
Si queremos conocer el valor de la raíz con un error menor que ε, tenemos que realizar
un número n de iteracciones tal que
11
Para poder codificar este procedimiento hemos de seguir los pasos siguientes
>> punto_medio(func,0.7,0.8,10)
ans = 0.7393
13
Raíces múltiples
La representación gráfica de la función en una pantalla de alta resolución nos permitirá
estimar los intervalos en los que la función cambia de signo y aplicar en consecuencia,
el procedimiento mitad a cada intervalo. Si no es posible una representación gráfica o
esta no es de la suficiente resolución, será preciso explorar el eje X en busca de
intervalos en los que la función cambia de signo. Cuando los encontremos aplicaremos a
cada uno de ellos el procedimiento del punto medio.
Las situaciones en las que nos podemos encontrar cuando buscamos las raíces de una
función y=f(x) en un intervalo (a,b) se muestran en la figura
f(a) y f(b) tienen el mismo signo, no hay raíz de la función en dicho intervalo,
pero también puede ocurrir que haya un número par de raíces en dicho intervalo.
f(a) y f(b) tienen distinto signo, hay una raíz de la función en dicho intervalo,
pero también puede ocurrir que haya un número impar de raíces en dicho
intervalo.
Vamos a crear un procedimiento que nos permita buscar los intervalos en los que la
función cambia de signo y calcular la raíz en cada uno de ellos, definiendo una función
denominada buscar_intervalos.
function xb = buscar_intervalos(f,a,b,n)
x = linspace(a,b,n);
j = 0;
for i = 1:length(x)-1
if sign(f(x(i))) ~= sign(f(x(i+1)))
j = j + 1;
xb(j,1) = x(i);
xb(j,2) = x(i+1);
end
end
if isempty(xb)
disp('no se han encontrado cambios de signo')
else
disp(['número de intervalos:' int2str(j)])
end
end
Este código es correcto, pero se puede hacer más eficiente, un asunto de vital
importancia en el cálculo intensivo. Nos daremos cuenta, que se calcula dos veces la
función f para el mismo valor de x, en el final de un intervalo y en el comienzo del
siguiente, ahorraremos el tiempo que tarda al procesador en realizar estas operaciones
si guardamos el valor de f(x) calculado al final del intervalo previo en la variable local y2
y lo asignamos a la variable y1, que guarda el valor de la función f(x) en el principio del
intervalo siguiente.
14
function xb = buscar_intervalos(f,a,b,n)
x = linspace(a,b,n);
j = 0;
y1=f(x(1));
for i = 1:length(x)-1
y2=f(x(i+1));
if sign(y1) ~= sign(y2)
j = j + 1;
xb(j,1) = x(i);
xb(j,2) = x(i+1);
end
y1=y2;
end
if isempty(xb)
disp('no se han encontrado cambios de signo')
else
disp(['número de intervalos:' int2str(j)])
end
end
Los mínimos de intensidad son los ceros de la función de Bessel J1(x) cuya
representación gráfica vemos en la figura
Nota: omitimos el origen x=0, por que se produce un máximo (no un mínimo de
intensidad)
La función buscar_intervalos, busca los intervalos en los que la función J1(x) cambia de
signo, el intervalo en el que se explora la función es (0.1, 30), omitimos el origen. El
número de divisiones del intervalo es 50, incluyendo los extremos. La función devuelve
la matriz xb, que guarda los extremos (xj, yj) de cada intervalo en los que la función
cambia de signo. La dimensión de la martriz xb nos la proporciona la función size y se
guarda en el vector nb de dos elementos [filas, columnas]. El número de
15
Para cada intervalo en el que la función cambia de signo, se aplica el procedimiento del
punto medio, llamando a la función punto_medio, para buscar la raíz en dicho intervalo.
J1=@(x) besselj(1,x);
xb=buscar_intervalos(J1,0.1,30,50);
nb=size(xb);
disp('mínimos: difracción por abertura circular')
for i=1:nb(1)
min(i)=punto_medio(J1,xb(i,1),xb(i,2),50);
disp(min(i))
end
En la ventana de comandos corremos el script para resolver la ecuación
trascendente J1(x)=0 en el intervalo (0.1,30)
tan(x)-x=0
En la figura, se representan la recta y=x (color azul) y la función y=tan(x) (color rojo).
Se ha hecho más pequeña la escala vertical que la horizontal.
f=@(x) tan(x)-x;
xb=buscar_intervalos(f,0.1,7*pi/2,10);
nb=size(xb);
disp('máximos secundarios: difracción por una rendija')
for i=1:nb(1)
max(i)=punto_medio(f,xb(i,1),xb(i,2),50);
disp(max(i))
end
En la ventana de comandos corremos el script
y=x·cos(x)-sin(x)
f=@(x) x*cos(x)-sin(x);
xb=buscar_intervalos(f,0.1,7*pi/2,50);
nb=size(xb);
disp('máximos: difracción por una rendija')
for i=1:nb(1)
r(i)=punto_medio(f,xb(i,1),xb(i,2),50);
disp(max(i))
end
En la ventana de comandos
Integración numérica
Hay muchas situaciones en la que es preciso aplicar procedimientos numéricos para obtener la
integral definida de una función. En esta página, se explicarán los procedimientos:
Antes de introducir al lector en al cálculo del área comprendida entre una función y=f(x)
y el eje X en un intervalo dado [a,b]. Vamos a ver como se calcula el área de un
polígono como suma de las áreas de trapecios.
Areas
(x2-x1)·y1+(x2-x1)·(y2-y1)/2=(x2-x1)·(y2+y1)/2
El área de la figura de la derecha formada por los puntos (x1,y1), (x2,y2) y (x3,y3) es
(x2-x1)·(y2+y1)/2+(x3-x2)·(y3+y2)/2
t(s) 1 2 3 4 5 6 7 8 9 10
v(m/s) 5.0 6.0 5.5 7.0 8.3 7.6 6.2 6.1 7.0 5.7
x=1:10;
y=[5.0,6.0,5.5,7.0,8.3,7.6,6.2,6.1,7.0,5.7];
area=0;
for i=1:length(x)-1
area=area+(x(i+1)-x(i))*(y(i)+y(i+1))/2;
end
disp(['Area: ', num2str(area)]);
area=trapz(x,y);
disp(['Area: ', num2str(area)]);
Area 1: 59.05
Area 2: 59.05
18
Area de un polígono
El área del triángulo formado por tres
puntos (x1,y1), (x2,y2) y (x3,y3) es
(x2-x1)·(y2+y1)/2 + (x3-x2)·(y3+y2)/2
-(x3-x1)·(y3+y1)/2
=(x2-x1)·(y2+y1)/2 + (x3-x2)·(y3+y2)/2
+ (x1-x3)·(y1+y3)/2
Para cerrar la figura poligonal, añadimos el vértice n+1, que coincide con el primer
vértice (x1,y1), (x2,y2) ... (xn,yn), (x1,y1). El cálculo del área se simplifica
area = 21.3988
19
A=n·(a·h)/2
x = [15,13,5,4,0,0,1,4,5,7,9,12,14,13,15,15];
y = [1,0,1,2,4,4,7,8,10,11,10,9,8,4,4,1];
%las coordenadas del último vértice son las del primer vértice
hold on
fill(x,y,'y')
plot(x,y,'-ro', 'markersize',4,'markeredgecolor','r','markerfacecolor','r')
hold off
xlabel('x')
ylabel('y')
axis equal
area=0;
for i=1:length(x)-1
area=area+(x(i+1)-x(i))*(y(i+1)+y(i))/2;
end
title (['Area del polígono: ' num2str(area])
La función MATLAB polyarea solamente precisa los n vértices del polígono, dos
vectores x e yde dimensión n
>> x = [15,13,5,4,0,0,1,4,5,7,9,12,14,13,15];
>> y = [1,0,1,2,4,4,7,8,10,11,10,9,8,4,4];
>> polyarea(x,y)
ans = 108
20
function suma=integral_2(f,x)
suma=0;
for i=1:length(x)-1
xm=(x(i+1)+x(i))/2;
suma=suma+f(xm)*(x(i+1)-x(i));
end
end
La ecuación de la parábola y=ax2+bx+c que pasa por los puntos (x0, y0), (x0+h, y1),
(x0+2h, y2) es
function suma=simpson(f,x0,xf,n)
%n número par de intervalos, n+1 número de puntos en el vector
x=linspace(x0,xf,n+1);
h=x(2)-x(1);
suma=f(x(1))+f(x(n+1));
for i=2:2:n
suma=suma+4*f(x(i));
end
for i=3:2:n-1
suma=suma+2*f(x(i));
end
suma=suma*h/3;
end
Existe una versión del método de Simpson denominada 3/8 en el que se emplea una
ecuación cúbica para conectar cuatro puntos.
24
Integrales simples
La función integral(function, a, b);devuelve el resultado aproximado de la integral
cuando se le pasa la función a integrar en el primer parámetro function, los
límites a y b de la integral. Ejemplos:
Integrales dobles
MATLAB dispone de la función integral2 que realiza esta tarea. Supongamos que
queremos calcular la integral doble
f=@(x,y) x.^2.*y;
res=integral2(f,1,2,0,3);
fprintf('El valor de la integral es: %2.3f\n',res)
Al integrar la función f(x,y) respecto de la variable y entre los límites c(x) y d(x) nos
queda la función g(x) que integramos entre los límites a y b.
Utilizamos la función MATLAB quad, para resolver ambas integrales, tal como vemos en
el siguiente ejemplo.
function z=g(x)
n=length(x);
z=zeros(size(x));
for j=1:n
%límites de y
c=x(j)^3-x(j);
d=x(j)^2+x(j);
%integrando f(x,y)
f=@(y) x(j)^3*y.^4+x(j)*y.^2;
z(j)=integral(f,c,d);
end
end
En el script llamamos a la función quad para resolver la integral de g(x)
res=integral(@g,0,2);
fprintf('El valor de la integral es: %3.3f\n',res)
En la ventana de comandos corremos el script integral_doble1
Ejemplos
Comprobar los resultados de las integrales siguientes:
function z=g1(x)
n=length(x);
z=zeros(size(x));
for j=1:n
%límites de y
c=x(j)^3;
d=x(j)^2;
%integrando f(x,y)
f=@(y) exp(y./x(j));
z(j)=integral(f,c,d);
end
end
Modificamos el script para llamar a la función integral para calcular la integral de g1(x)
entre los nuevos límites de la integral a y b
res=quad(@g1,0.1,0.5);
fprintf('El valor de la integral es: %1.4f\n',res)
function z=g1(x)
n=length(x);
z=zeros(size(x));
for j=1:n
%límites de y
c=x(j);
d=2*x(j);
%integrando f(x,y)
f=@(y) x(j)^2+y.^3;
z(j)=integral(f,c,d);
end
end
Modificamos el script para llamar a la función integral para calcular la integral de g2(x)
entre los nuevos límites de la integral a y b
res=integral(@g2,0,1);
fprintf('El valor de la integral es: %1.4f\n',res)
En la ventana de comandos corremos el script
Pocas ecuaciones diferenciales tienen una solución analítica sencilla, la mayor parte de las veces
es necesario realizar aproximaciones, estudiar el comportamiento del sistema bajo ciertas
condiciones. Así, en un sistema tan simple como un péndulo, la amplitud de la oscilación ha de
ser pequeña y el rozamiento ha de ser despreciable, para obtener una solución sencilla que
describa aproximadamente su movimiento periódico.
Método de Euler
Vamos a resolver la ecuación diferencial de primer orden
xi+1=xi + h.f(ti,xi)
la función f(t,x),
la condición inicial de que en el instante t0 la posición es x0,
el instante final tf
el número de pasos de integración n
t x(Euler) x=sin t
0 1 0 0
t/6 0.866 0.523 0.5
t/3 0.5 0.977 0.866
t/2 0 1.239 1
2t/3 -0.5 1.239 0.866
5t/6 -0.866 0.977 0.5
t -1 0.523 0
Para aplicar el método de Euler precisamos de un paso h pequeño, incluso así los
errores se van acumulando y al cabo de cierto tiempo la diferencia entre el valor exacto
y el calculado es grande.
hold on
plot(t,x,'b')
y=sin(t);
plot(t,y,'r')
xlabel('t')
ylabel('x')
grid on
legend('aproximada','exacta')
title('dx/dt=cost')
hold off
Método de Runge-Kutta
En esta sección vamos a estudiar la aplicación del método de Runge-Kutta a:
Se elige una anchura de paso h y se calculan cuatro números k1, k2, k3, k4 de acuerdo
con el procedimiento esquematizado en la tabla adjunta. Según el procedimiento
ordinario de Runge-Kutta, a partir del valor de x en el instante t se determina el valor
de x en el instante t+hmediante la fórmula que figura en la última fila de dicha tabla.
Definimos la función rk_1 que resuelve la ecuación diferencial de primer orden, cuando
le pasamos:
la función f(t,x),
la condición inicial de que en el instante t0el valor inicial es x0,
el instante final tf
el número de pasos de integración n comprendidos entre el instante inical t0 y
final tf.
el valor inicial de x es x0
el valor inicial de y es y0
se esquematiza en la tabla adjunta. Como vemos además de los cuatro números k1, k2,
k3, k4para la primera ecuación diferencial precisamos otros cuatro números l1, l2, l3,
l4 para la segunda ecuación diferencial. A partir del valor de x en el instante t, se
determina el valor de x en el instante t+h, y a partir del valor de y en el instante t se
determina el valor de y en el instante t+h mediante las fórmulas de la última fila de la
tabla.
for i=1:n
k1=h*f(t(i),x(i),y(i));
l1=h*g(t(i),x(i),y(i));
k2=h*f(t(i)+h/2,x(i)+k1/2,y(i)+l1/2);
l2=h*g(t(i)+h/2,x(i)+k1/2,y(i)+l1/2);
k3=h*f(t(i)+h/2,x(i)+k2/2,y(i)+l2/2);
l3=h*g(t(i)+h/2,x(i)+k2/2,y(i)+l2/2);
k4=h*f(t(i)+h,x(i)+k3,y(i)+l3);
l4=h*g(t(i)+h,x(i)+k3,y(i)+l3);
x(i+1)=x(i)+(k1+2*k2+2*k3+k4)/6;
y(i+1)=y(i)+(l1+2*l2+2*l3+l4)/6;
end
end
Consideremos una serie radioactiva de tres elementos A-->B-->C en la que, una
sustancia radiactiva A se desintegra y se transforma en otra sustancia radiactiva B, que
a su vez se desintegra y se transforma en una sustancia C estable. Las ecuaciones
diferenciales que gobiernan el proceso y sus soluciones analíticas son, respectivamente,
32
a=input('parámetro a: ');
b=input('parámetro b: ');
x0=input('valor inicial de x: ');
y0=input('valor inicial de y: ');
tf=input('tiempo final, tf: ');
n=input('número de pasos, n: ');
f=@(t,x,y) -a*x;
g=@(t,x,y) a*x-b*y;
%condiciones iniciales
t0=0;
[t,x,y]=rk_2_1(f,g,t0,tf,x0,y0,n);
hold on
plot(t,x,'b')
plot(t,y,'r')
xlabel('t')
ylabel('x,y')
grid on
legend('x(t)','y(t)')
title('dx/dt=-ax, dy/dt=ax-by')
hold off
parámetro a: 0.1
parámetro b: .2
valor inicial de x: 100
valor inicial de y: 0
tiempo final, tf: 10
número de pasos, n: 40
33
la función f (t,x,v)
las condiciones iniciales: posición inicial x0 y velocidad inicial v0 en el instante t0
el número n de pasos de integración entre t0 y el tiempo final tf
Nos devuelve los vectores de las posiciones x y las velocidades v para cada instante que
se guarda en el vector t comprendido entre el instante inicial t0 y el final tf.
for i=1:n
k1=h*v(i);
l1=h*f(t(i),x(i),v(i));
k2=h*(v(i)+l1/2);
l2=h*f(t(i)+h/2,x(i)+k1/2,v(i)+l1/2);
k3=h*(v(i)+l2/2);
l3=h*f(t(i)+h/2,x(i)+k2/2,v(i)+l2/2);
k4=h*(v(i)+l3);
l4=h*f(t(i)+h,x(i)+k3,v(i)+l3);
x(i+1)=x(i)+(k1+2*k2+2*k3+k4)/6;
v(i+1)=v(i)+(l1+2*l2+2*l3+l4)/6;
end
end
>> oscilador
frecuencia angular, w0: 2
rozamiento, gamma: 0.5
posición inicial, x0: 1.5
velocidad inicial, v0: 0
tiempo final, tf: 8
número de pasos, n: 100