Sei sulla pagina 1di 21

Universidad Industrial de Santander

Facultad de ciencias
Escuela de Física

Proyecto Nº1

Andrei Jaimes Motta

Grupo: B1- 25439


Métodos Numéricos y Probabilidad

Presentado a:
Prof. ILIA DAVIDOVICH MIKHAILOV

Bucaramanga

2014
1. Problemas para Tarea N 1 (raíces de una ecuación algebraica)

Considere la ecuación ( ) dentro del intervalo ( ) con un parámetro p que se


varía dentro del intervalo . Las funciones ( ) y parámetros
están dados en la tabla. Denotaremos las raíces de esta ecuación ( ) donde
n es el número total de las raíces.

a) Análisis gráfico para separar las raíces.

La función a la cual se le van a hallar las raíces es:

( ) ( ), Con

Es necesario tener en cuenta el comportamiento matemático de estas dos funciones. Para


observar dicho comportamiento se requiere realizar un análisis gráfico, donde se
representaran con diferente color las dos funciones respectivamente, teniendo en cuenta que
los cruces o interceptos entre las funciones son las raíces que se quieren hallar
numéricamente. Cabe anotar que estos métodos numéricos funcionan en intervalos donde
solo se encuentra una raíz, así que se debe calcular un paso h que cumpla esta condicione.

Para este caso se tomó , donde se aprecia que sin importar el valor que se le dé a p,
h (paso) siempre es un intervalo que contiene una única raíz (figura 1)

Para el caso de la figura 1, donde se tomó p = 0.5, el valor del paso h = , lo


cual cumple lo dicho anteriormente, encerrando solo el valor de una raíz, así para cada una
de las raíces de esta función. El recuadro Evaluación muestra el punto de intersecto entre
las dos funciones, lo cual concuerda con los valores hallados mediante el método numérico.
Según la gráfica se podría decir que esto no cumple para valores en los cuales los
interceptos se hagan muy cercanos a cero o al paso, debido a que no es apreciable a simple
vista, pero si realizamos un zoom a la función (figura 2), en uno de estos puntos, se
corrobora que el paso sigue cumpliendo la condición de una sola raíz en su intervalo.
Figura 1. Grafica para p= 0.5. La línea punteada representa la primera raíz.

Figura 2. Grafica para p= 0.5 con zoom. La línea punteada representa la última raíz, y el paso es
un múltiplo de corte con el eje x.
Figura 3. Grafica para p= 5.0. La línea punteada representa la primera raíz.

b) Utilizando el método de bisección encuentre el número n de raíces y valores de todas


raíces con la precisión para valores del parámetro y .

Los resultados de las raíces.

p=0.5 12 6.911504
13 7.539822
n raíz 14 8.168141
1 1.177065 15 8.796459
2 6.192728 16 9.424778
3 12.570099 17 10.053096
4 18.849395 18 10.681415
19 11.309734
p=5.0 20 11.938052
21 12.566371
n raíz 22 13.194689
1 0.117707 23 13.823008
2 0.619273 24 14.451326
3 1.257010 25 15.079645
4 1.884939 26 15.707963
5 2.513275 27 16.336282
6 3.141593 28 16.964600
7 3.769911 29 17.592919
8 4.398230 30 18.221237
9 5.026548 31 18.849556
10 5.654867 32 19.477874
11 6.283185
El código del programa se realizó en lenguaje C, usando el compilador Code::Blocks 13.12.

#include<stdio.h>
#include<math.h>

double fun(double x);


double Raiz(double a,double b,double tol);
int main(){
double pi=3.1415926,p=5.0;
double a=0,b=20.0,tol=pow(10,-8),h=pi/(2*p),xl,xr,yl,yr,xraiz;
int cont=0,i;

FILE *fdat1;
fdat1=fopen("Punto1b_5.0.dat","w");
xl=a;
xr=a+h;
fprintf(fdat1,"%2s %6s \n","n","raíz");

while(xr<b){
yl=fun(xl);
yr=fun(xr);
if(yl*yr<0.0){
cont++;
xraiz=Raiz(xl,xr,tol);
fprintf(fdat1,"%2d %6lf\n",cont,xraiz);
}
xl=xr;
yl=yr;
xr=xl+h;
yr=fun(xr);
}
fclose(fdat1);
return 0;
}

//Función a la cual se le van a encontrar las raíces


double fun(double x){
double y,p=5.0;
y=exp(-p*x)-sin(p*x);
return y;
}
/*La función Raiz busca la solución de la ecuación F(x)=0
dentro del intervalo (a,b) con la precisión tol,
usando el método de bisección*/
double Raiz(double a,double b,double tol){
double xl,xr,fl,fr,x,f;

xl=a;
fl=fun(xl);
xr=b;
fr=fun(xr);
x=(xl+xr)/2.0;
f=fun(x);
while(f != 0 && (xr-xl)>tol){
if(f*fl<0){
xr=x;
fr=f;
}
else{
xl=x;
fl=f;
}
x=(xl+xr)/2.0;
f=fun(x);
}
return x;
}
El código de este programa es el mismo para cada uno de los dos valores de p
respectivamente.

c) Presente el gráfico del número de las raíces n en función del parámetro p para dentro
del intervalo

Se aprecia que el comportamiento del grafico (figura 4) es lineal (R=0.9989), esto se debe a
que a medida que el valor de p aumenta, los cruces o interceptos entre las funciones
también lo hacen, ya que la función ( ) aumenta su frecuencia debido a que p se
encuentra como su argumento, esto se corrobora en la figura 3.
Figura 4. Gráfica del número de raíces n en función del parámetro p, aumentando en intervalos
de 0.225.

El código del programa se realizó en lenguaje C, usando el compilador Code::Blocks 13.12.

#include<stdio.h>
#include<math.h>
double fun(double x,double p);
double Raiz(double a,double b,double p,double tol);
void allraiz(double a,double b,double p,double tol,double hraiz,int *nraiz,double
xraiz[1000]);
int main(){
double a=0.0,b=20.0,p0=0.5,pf=5.0,p,tol=pow(10,-8),hraiz=0.001,xraiz[1000],hp;
int nraiz,i,np=21,j;

FILE *fdat1;
fdat1=fopen("cantidad de raices.dat","w");
hp=(pf-p0)/(np-1);
for(j=1;j<=np;j++){
p=p0+(j-1)*hp;

//Llamada de la subrutina allraiz


allraiz(a,b,p,tol,hraiz,&nraiz,xraiz);

//Impresión de las raíces para cada valor de p en el archivo "cantidad de raices.dat"


fprintf(fdat1,"%9lf %3d\n",p,nraiz);
}

fclose(fdat1);
return 0;
}
//Función externa
double fun(double x, double p){
double y;
y=exp(-p*x)-sin(p*x);
return y;
}

/*La función Raiz busca la solución de la ecuación F(x)=0


dentro del intervalo (a,b) con la precisión tol,
usando el método de bisección*/
double Raiz(double a,double b,double p,double tol){
double xl,xr,fl,fr,x,f;
xl=a;
fl=fun(xl,p);
xr=b;
fr=fun(xr,p);
x=(xl+xr)/2.0;
f=fun(x,p);
while(f!=0 && (xr-xl)>tol){
if(f*fl<0){
xr=x;
fr=f;
}
else{
xl=x;
fl=f;
}
x=(xl+xr)/2.0;
f=fun(x,p);
}
return x;
}
/*La subrutina allraiz cubre el intervalo [a,b] en pasos de longitud de hraiz,
buscando los intervalos en cuyos extremos la función toma signos distintos */
void allraiz(double a,double b,double p,double tol,double hraiz,int *nraiz,double
xraiz[1000]){
double xl,xr,yl,yr;
xl=a;
xr=a+hraiz;
yl=fun(xl,p);
yr=fun(xr,p);
*nraiz=0;
while(xr<b){
if(yl*yr<0){
*nraiz=*nraiz+1;
xraiz[*nraiz-1]=Raiz(xl,xr,p,tol);
}
xl=xr;
yl=yr;
xr=xl+hraiz;
yr=fun(xr,p);
}
}

d) Para valores del parámetro encuéntrese la primera raíz utilizando los


métodos de bisección y de Newton con la misma precisión y compare la
cantidad de iteraciones que requieren estos dos métodos para lograr la precisión
sugerida.

Tabla1. Comparación de métodos.


Bisección Newton
Raíz #_Iteraciones Raíz #_Iteraciones
18.8493945 17 18.8493945 2
19.4778745 17 19.4778745 2

Se puede determinar que con la precisión que opto, los dos métodos arrojan resultados
similares, pero a la hora de mirar la cantidad de iteraciones, el método de bisección realizo
17, lo cual es mucho más que 2, las realizadas por el método de newton ; por lo que hace
que el método de newton sea más óptimo refiriéndonos al ámbito de la programación.

El código del programa se realizó en lenguaje C, usando el compilador Code::Blocks 13.12.


#include<stdio.h>
#include<math.h>
double fun(double x,double p);
double dfun(double x,double p);
double ddfun(double x,double p);
double bisec(double a,double b,double p,double eps,int *nit);
double newt(double a,double b,double p,double eps,int *nit);

int main(){
double a=0.0,b=20.0,p0=0.5,pf=5.0,p,eps=pow(10,-
8),hraiz=0.001,xraiz1,xraiz2,hp,xl,xr,fl,fr,xlu,xru;
int nraiz=0,i,nit1,nit2;
hp=(pf-p0)/9;
//hp=1.0;
FILE *fdat1;
fdat1=fopen("raices dif_metodos.txt","w");
fprintf(fdat1,"%6s %6s %12s %4s %12s %4s\n","p","#raiz","raiz bisecc","#it","raiz
newton","#it");
for(i=1;i<=10;i++){
p=p0+(i-1)*hp;
nraiz=0;
xl=a;
xr=a+hraiz;
fl=fun(xl,p);
fr=fun(xr,p);
xlu=xl;
xru=xl;
while(xr<b){
if(fl*fr<0){
nraiz++;
xlu=xl;
xru=xr;
}
xl=xr;
fl=fr;
xr=xl+hraiz;
fr=fun(xr,p);
}
xraiz1=bisec(xlu,xru,p,eps,&nit1);
xraiz2=newt(xlu,xru,p,eps,&nit2);
fprintf(fdat1,"%6.2lf %6d %12.7lf %4d %12.7lf %4d\n",p,nraiz,xraiz1,nit1,xraiz2,nit2);
}
fclose(fdat1);
return 0;
}
//Funcion original
double fun(double x, double p){
double y;
y=exp(-p*x)-sin(p*x);
return y;
}
//Primera derivada de la funcion original
double dfun(double x,double p){
double y;
y=-p*exp(-p*x)-p*cos(p*x);
return y;
}
//segunda derivada de la funcion original
double ddfun(double x,double p){
double y;
y=(p*p)*exp(-p*x)+(p*p)*sin(p*x);
return y;
}

//Funcion que halla las raices mediante el metodo de biseccion


double bisec(double a,double b,double p,double eps,int *nit){
double xl,xr,fl,fr,x,f;
xl=a;
fl=fun(xl,p);
xr=b;
fr=fun(xr,p);
x=(xl+xr)/2.0;
f=fun(x,p);
*nit=0;
while(f!=0 && (xr-xl)>eps){
if(f*fl<0){
xr=x;
fr=f;
}
else{
xl=x;
fl=f;
}
*nit=*nit+1;
x=(xl+xr)/2.0;
f=fun(x,p);
}
return x;
}

//Funcion que halla las raices mediante el metodo de Newton


double newt(double a,double b,double p,double eps,int *nit){
double x0,x,epsn;
x0=a;
x=x0-fun(a,p)/dfun(a,p);
*nit=1;
epsn=abs(x0-x);
while(epsn>=eps){
x0=x;
x=x0-fun(x0,p)/dfun(x0,p);
epsn=fabs(x-x0);
*nit=*nit+1;
}
return x;
}

2. Problemas para Tarea N 2: (Interpolación)

Considere función ( ) dada en la lista dentro del intervalo (a, b)

a) Encuentre los valores de la función sobre la malla equidistante *


+ con errores aleatorios ( ), - una vez con la precisión =0.1 y
-6
otra vez con la precisión = 10 y con número aleatorio rnd con la distribución homogénea
dentro del intervalo [0,1] y organice 2 tablas.

La función a trabajar es:

( ) ( ), Con
Tabla2. Valores de la función con precisión =0.1
i xi yi
1 0 0
2 0.314159 0.071138
3 0.628319 0.184565
4 0.942478 0.260384
5 1.256637 0.274482
6 1.570796 0.224760
7 1.884956 0.143500
8 2.199115 0.079511
9 2.513274 0.029865
10 2.827433 0.006146
11 3.141593 0.000000

Tabla3. Valores de la función con precisión =0.000001


i xi yi
1 0 0
2 0.314159 0.069747
3 0.628319 0.184316
4 0.942478 0.255037
5 1.256637 0.257432
6 1.570796 0.207880
7 1.884956 0.137337
8 2.199115 0.072586
9 2.513274 0.027986
10 2.827433 0.005650
11 3.141593 0.000000

b) usando estas dos tablas como valores de una función desconocida calcúlese valores de la
función sobre la malla equidistante * + usando la
fórmula de interpolación de LaGrange global y compare los resultados con los valores
exactos de la función ( ).

El código funciona para los valores de precisión =0.1 y =10-6, dichos valores se
encuentras en los archivos de texto tabla_1 y tabla_2 y genera un archivo de salida en el
cual se imprimen los valores de X, el valor exacto de la función Yexac y los valores al
hacer la interpolación de LaGrange Ylag para cada uno de los valores de . Se procede a
graficar el resultado de dichos archivos, con ayuda del programa Graph. En la figura44444
se observa la relación entre el valor exacto de la función y la interpolación de LaGrange
( =0.1), donde se puede apreciar que el comportamiento entre dichas graficas es semejante
en una buena cantidad de puntos. En fa figura 44445 representa la misma relación anterior
excepto que el valor de la precisión es =10-6 lo que hace que su comportamiento sea
aproximadamente el mismo. Se puede deducir de estas dos graficas que en general el
método de interpolación de LaGrange es bueno, pero es necesario tener en cuenta el error y
la precisión con la que se esté trabajando.

Figura 5. Gráfica de los valores exactos e interpolación de LaGrange para =0.1

Figura 6. Gráfica de los valores exactos e interpolación de LaGrange para =10^-6


El código del programa se realizó en lenguaje C, usando el compilador Code::Blocks 13.12.

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#define PI 3.14159265
double function(double xn);
double lagrange(double x[],double y[],int N,double xn);
int main(){
double e,a,b,I;
char t;
int s=201,i=0,N;
FILE *variable1;
variable1=fopen("tabla_1.txt","r");
fscanf(variable1,"%d %lf %lf %lf", &N,&e,&a,&b);
double x[N],y[N];
for(i=0;i<N;i++)fscanf(variable1,"%lf %lf\n", &x[i], &y[i]);
fclose(variable1);
double yn[s],yp[s],xn[s];
I=(b-a)/(s-1);
xn[0]=a;
for(i=0;i<s;i++){
yn[i]=lagrange(x,y,N,xn[i]);
yp[i]=function(xn[i]);
xn[i+1]=xn[i]+I;
}
variable1=fopen("interpolado_1.txt","w");
fprintf(variable1,"X Ylag X Yexac\n");
for(i=0;i<s;i++)fprintf(variable1,"%lf %lf %lf %lf\n",xn[i],yn[i],xn[i],yp[i]);
fclose(variable1);
return 0;
}
double lagrange(double x[],double y[],int N,double xn){
double yn=0.0,L=1.0;
int i=0,j=0;
for(i=1;i<=N;i++){
L=1.0;
for(j=1;j<=N;j++){
if(i!=j)L=L*(xn-x[j])/(x[i]-x[j]);
}
yn=yn+L*y[i];
}
return yn;
}
double function(double xn){
double yp;
yp=exp(-xn)*(sin(xn)*sin(xn));
return yp;
}

c) Repitiese el cálculo del punto anterior usando las interpolaciones segmentarias lineal y
parabólica y explíquese las diferencias que aparecen en estos cálculos.

 Interpolación segmentaria lineal

El código lee dos archivos de texto previos (tabla_presicion_0.1 y


tabla_presicion_0.000001), y genera dos archivos donde se encuentra la interpolación
segmentaria lineal para cada uno de los valore de . Nuevamente se realiza la relación entre
los valores de la función exacta y los de la interpolación (figura 7, 8), donde se aprecia que
dicha interpolación se ajusta en buena forma al valor original, pero presenta cambios
bruscos en algunos sectores.

Figura 7. Gráfica de los valores exactos e interpolación segmentaria lineal para =0.1
Figura 8. Gráfica de los valores exactos e interpolación segmentaria lineal para =10^-6

El código del programa se realizó en lenguaje C, usando el compilador Code::Blocks 13.12.

#include<stdio.h>
#include<math.h>
double lineal(double a,double h,double xe[],int ne,double p);
int main (){
int ne=11,i,j,np=201;
double pe1[ne],xe1[ne],pe2[ne],xe2[ne],x1,x2,p0=0,pf=3.141592,p,hp,d;
FILE *fdat1;
fdat1=fopen("tabla_presicion_0.1.txt","r");
for(i=0;i<11;i++){
fscanf(fdat1,"%lf %lf",&pe1[i],&xe1[i]);
}
FILE *fdat2;
fdat2=fopen("tabla_presicion_0.000001.txt","r");
for(i=0;i<11;i++){
fscanf(fdat2,"%lf %lf",&pe2[i],&xe2[i]);
}
fclose(fdat1);
fclose(fdat2);
d=(pf-p0)/(ne-1);
FILE *fdat3;
fdat3=fopen("seg_lineal_0.1 1.txt","w");
FILE *fdat4;
fdat4=fopen("seg_lineal_0.000001.txt","w");
hp=(pf-p0)/(np-1);
for(j=0;j<=1;j++){
for(i=1;i<=np;i++){
p=p0+hp*(i-1);
if(j==0){
x1=lineal(p0,d,xe1,ne,p);
fprintf(fdat3,"%9lf %9lf\n",p,x1);
}
if(j==1){
x2=lineal(p0,d,xe2,ne,p);
fprintf(fdat4,"%9lf %15lf\n",p,x2);
}
}
}
fclose(fdat3);
fclose(fdat4);
return 0;
}

double lineal(double a,double h,double xe[],int ne,double p){


double x,pk;
int k;
k=(p-a)/h;
if(k==(ne-1))k=k-1;
pk=a+(k)*h;
x=xe[k]+(xe[k+1]-xe[k])*(p-pk)/h;
return x;
}

 Interpolación segmentaria parabólica.

Este código nuevamente lee nuestros archivos previos (tabla_presicion_0.1 y


tabla_presicion_0.000001), en donde nos genera dos archivos de texto los cuales
graficamos (figura 9,10), donde se aprecia la relación entre la interpolación parabólica y el
valor exacto de la función, en este caso a diferencia de la interpolación segmentaria lineal,
esta no presenta saltos brusco entre valores, pero aparece una zona en la cual el ajuste no es
muy bueno.
Figura 9. Gráfica de los valores exactos e interpolación segmentaria parabólica para =0.1

Figura 10. Gráfica de los valores exactos e interpolación segmentaria parabólica para =10^-6
El código del programa se realizó en lenguaje C, usando el compilador Code::Blocks 13.12.

#include<stdio.h>
#include<math.h>
double cuadratica(double a,double h,double xe[],int ne,double p);
int main (){
int ne=11,i,j,np=201;
double pe1[ne],xe1[ne],pe2[ne],xe2[ne],x1,x2,p0=0,pf=3.141592,p,hp,d;
FILE *fdat1;
fdat1=fopen("tabla_presicion_0.1.txt","r");
for(i=0;i<11;i++){
fscanf(fdat1,"%lf %lf",&pe1[i],&xe1[i]);
}
FILE *fdat2;
fdat2=fopen("tabla_presicion_0.000001.txt","r");
for(i=0;i<11;i++){
fscanf(fdat2,"%lf %lf",&pe2[i],&xe2[i]);
}
fclose(fdat1);
fclose(fdat2);
d=(pf-p0)/(ne-1);
FILE *fdat3;
fdat3=fopen("seg_parabol_0.1 1.txt","w");
FILE *fdat4;
fdat4=fopen("seg_parabol_0.000001.txt","w");
hp=(pf-p0)/(np-1);
for(j=0;j<=1;j++){
for(i=1;i<=np;i++){
p=p0+hp*(i-1);
if(j==0){
x1=cuadratica(p0,d,xe1,ne,p);
fprintf(fdat3,"%9lf %15lf\n",p,x1);
}
if(j==1){
x2=cuadratica(p0,d,xe2,ne,p);
fprintf(fdat4,"%9lf %15lf\n",p,x2);
}
}
}
fclose(fdat3);
fclose(fdat4);
return 0;
}
double cuadratica(double a,double h,double xe[],int ne,double p){
double x,pk,pk1;
int k;
k=(p-a)/h;
if(k==(ne-1))k=k-1;
xe[5]=xe[4];
pk=a+(k)*h;
pk1=pk+h;
x=xe[k]+((xe[k+1]-xe[k])*(p-pk)/h)+((xe[k+2]-2*xe[k+1]+xe[k])*(p-pk)*(p-
pk1)/(2*pow(h,2)));
return x;
}

Se puede concluir de estos métodos de interpolación, que el proceso de interpolación de


LaGrange nos arroja menos error en comparación al segmentario lineal y parabólico ya que
no presenta cambios abruptos, y tiene en cuanta la suavidad de los puntos. por el contrario
los métodos segmentarios lineal y parabólico presentan ventajas a la hora de la
programación ya que su algoritmo es menos complejo y por ende el programa se puede
hacer mas rápido.

Potrebbero piacerti anche