RAÍCES E INTERPOLACIÓN Universidad Industrial de Santander Métodos Numéricos y Probabilidad Profesor: Ilia Davidovich Mikhailov Yesid Román Gómez Código:2121030 27 de Junio 2014 Hallaremos las raíces de la ecuación ( ) para los valores donde para esto, con base en lo dicho, graficamos las funciones y1 y y2(x, ). ( ( x 1 0.8 1 x2 0.6 0.4 0.2 5 ) 10 15 20 Donde las respectivas raíces corresponden a aquellos valores en los cuales se intersectan las gráficas, éstas intersecciones se hallan de forma periódica a lo largo de la función y cambiarán a medida que el parámetro p varía. Para poder hallar las raíces con los métodos mencionados se escogió un intervalo de análisis, en este caso será . De igual forma procedimos a graficar y1 y 1.2 Análisis gráfico Estableciendo la función como ( ) 2 ) Dada la función ( , con dominio ( ) , se hallarán las raíces de la ecuación utilizando los métodos de análisis y cálculo, como lo son el método de Newton y el de Bisección; también el respectivo comportamiento de las raíces a los largo del dominio. ) ( 1.0 sin 2 1. Planteamiento obtención de raíces ( ) ) ( ). Se observa que ésta función es una superficie en . (ver figura 1) y2(x, ). 1.0 0.8 0.6 0.4 0.2 Figura 1. Grafica ( ) 1 Pero, si ( ) los valores que cumplirán con la condición deben ser las líneas equipotenciales correspondientes al nivel cero de la función. Si despejamos la ecuación se tiene que cumplir que ( ), por lo tanto, para cada valor infinitesimal de ‘p’ habrá un número de raíces que cumplirán con la ecuación. 2 3 4 5 sin 2 x 25 1 1 x2 El intervalo de análisis es . Observando el comportamiento, las raíces y por el ángulo de la función y2, el intervalo de análisis corresponderán a para cada valor de p. 1.3 Métodos de raíces Continuando, se usó el código de programación ‘C’ para hallar las raíces con una precisión deseada de . Inicialmente se realizó con el método de la bisección, que se muestra a continuación, en el cual las raíces halladas se encuentran en la tabla 1. No. Raíz Raíz 1 1.306542 2 5.950173 3 6.584620 4 12.405500 5 12.723241 6 18.742950 7 18.954971 Tabla 1. Raíces de f(x,p) para p=0.5 Se utilizó códigos de programación ya que usualmente se presentan cálculos bastante extensos volviéndose imposible realizarlos a mano. Como se ve para cuando p=25.0 se presentan 319 raíces distintas en el intervalo de . 0.060418 0.065446 0.181321 0.196247 0.302413 0.326793 0.423789 0.456968 0.545511 0.586710 0.667604 0.716006 0.790068 0.844875 0.912882 0.973354 1.036018 1.101488 1.159441 1.283118 1.356896 1.407016 1.484249 1.531107 1.611412 1.655365 1.738411 1.779768 1.865271 1.904297 1.992009 2.028936 2.118643 2.153671 2.245186 2.278490 2.371649 2.403382 2.528340 2.624376 2.653355 2.750654 2.778421 2.876884 2.903533 3.003071 3.028685 3.129220 3.153874 3.255335 3.279096 3.381419 3.404348 3.507474 3.529627 3.633505 3.654930 3.780256 3.885499 3.905601 4.011466 4.030965 4.137416 4.156347 4.263350 4.281743 4.389270 4.407155 4.515175 4.532579 4.641068 4.658016 4.766950 4.783464 4.892820 4.908923 1.229321 5.034392 5.144532 5.159869 5.270375 5.285355 5.396210 5.410849 5.522037 5.536351 5.647857 5.661859 5.773671 5.787375 5.899478 5.912896 6.025279 6.038423 6.151075 6.163955 6.276866 2.498043 6.289492 6.402652 6.415035 6.528433 6.540581 6.654210 6.666132 6.779983 6.791688 6.905752 6.917247 7.031517 7.042809 7.157278 7.168376 7.283037 7.293945 7.408792 7.419518 7.534544 3.759512 7.545093 7.660294 7.670671 7.786040 7.796253 7.911784 7.921836 8.037526 8.047422 8.163265 8.173011 8.289002 8.298602 8.414737 8.424194 8.540470 8.549789 8.666200 8.675386 8.791929 5.018681 8.800985 8.917656 8.926586 9.043382 9.052188 9.169105 9.177792 9.294827 9.303397 9.420548 9.429004 9.546267 9.554613 9.671984 9.680223 9.797701 9.805834 9.923415 9.931447 10.049129 10.057061 10.174842 10.182676 10.300553 10.308292 10.426263 10.433910 10.551972 10.559528 10.677680 10.685148 10.803387 10.810768 10.929093 10.936390 11.054798 11.062012 11.180502 11.187636 11.306205 11.313260 11.431907 11.438885 11.557609 11.564511 11.683309 11.690138 11.809009 11.815766 11.934708 11.941394 12.060407 12.067023 12.186104 12.192653 12.311801 12.318283 12.437498 12.443914 12.563193 12.569546 12.688888 12.695179 12.814583 12.820812 12.940277 12.946445 13.065970 13.072079 13.191663 13.197714 13.317355 13.323349 13.443047 13.448985 13.568738 13.574622 13.694428 13.700258 13.820118 13.825896 13.945808 13.951534 14.071497 14.077172 14.197186 14.202810 14.322874 14.328450 14.448562 14.454089 14.574250 14.579729 14.699937 14.705370 14.825623 14.831010 14.951310 14.956651 15.076996 15.082293 16.338727 17.595190 15.202681 16.459518 17.716327 15.207935 16.464372 17.720837 15.328366 16.585200 17.842007 15.333577 16.590017 17.846485 15.454051 16.710882 17.967686 15.459220 16.715663 17.972133 15.579736 16.836564 18.093365 15.584863 16.841309 18.097782 15.705420 16.962245 18.219044 15.710506 16.966955 18.223430 15.831104 17.087926 18.344723 15.836149 17.092602 18.349079 15.956787 17.213607 18.470401 15.961793 17.218248 18.474728 16.082470 17.339287 18.596080 16.087438 17.343895 18.600377 16.208153 17.464967 18.721758 16.213082 17.469542 18.726026 16.333836 17.590647 18.847436 Tabla 2. Raíces de f(x,p) para p=25.0 18.851676 18.973113 18.977325 19.098791 19.102975 19.224468 19.228625 19.350145 19.354276 19.475822 19.479926 19.601499 19.605577 19.727176 19.731227 19.852852 19.856878 19.978529 19.982529 scanf("%lf", &b); printf("Ingrese el valor del parametro p:"); scanf("%lf", &p); printf("tolerancia:"); scanf("%lf", &tol); inter=PI/(2*p); xl1=a; xr1=a+inter; while(xl1<b){ xl=xl1; xr=xr1; y0=function(xl,p)*function(xr,p); if(y0<0.0){ wid=(xr-xl)/2.0; while(wid>tol){ xm=(xr+xl)/2.0; y1=function(xl,p)*function(xm,p); if(y1<0.0)xr=xm; else xl=xm; wid=(xr-xl)/2.0; } x[i]=xm; i++;} xl1=xr1; xr1=xr1+inter;} ----------------------------------------------------------- raiz=fopen("raices.txt","w"); fprintf(raiz,"Raíces para %lf\n", p); for(j=0;j<i;j++)fprintf(raiz,"%lf\n", x[j]); fclose(raiz); return 0;} #include<stdio.h> #include<stdlib.h> #include<math.h> #define PI 3.14159265358979323846 double function(double x, double p){ double y; y=(1/(1+(x*x)))-(sin(x*p)*sin(x*p)); return y;} double function(double x, double p); ----------------------------------------------------------- El código usado para hallar las raíces se presenta a continuación. int main(){ double a, b, p, tol, inter, xl, xr, y0, xl1, xr1, wid, xm, y1, x[340]; int i=0,j=0; FILE *raiz; printf("Por favor introduzca el intervalo [a,b] en el que desea hallar la raiz\n"); printf("a:"); scanf("%lf", &a); printf("b:"); 1.3 Comportamiento y número de raíces Se encontró éste incremento significativo de raíces; para un análisis más detallado se halló el número de raíces N con respecto al crecimiento del parámetro P a un paso iterativo de 0.6 y se graficó respecto su incremento. El código utilizado en C para realizar el conteo es el siguiente. ----------------------------------------------------------- #include<stdio.h> #include<stdlib.h> #include<math.h> #define PI 3.14159265358979323846 Los datos obtenidos se organizaron en la tabla 3, se graficó la dependencia de las variables encontrando un crecimiento lineal. P N 12,5 160 0,5 7 13,1 167 1,1 15 13,7 175 1,7 22 14,3 183 2,3 30 14,9 190 2,9 37 15,5 198 3,5 45 16,1 205 4,1 53 16,7 213 4,7 60 17,3 221 5,3 68 17,9 228 5,9 76 18,5 236 6,5 83 19,1 244 7,1 91 19,7 251 7,7 99 20,3 259 8,3 106 20,9 267 8,9 114 21,5 274 9,5 121 22,1 282 10,1 129 22,7 290 10,7 137 23,3 297 11,3 144 23,9 305 11,9 152 24,5 312 Tabla 3. Datos del número de raíces contra el valor de P, las tercera y cuarta columna corresponden a la continuación de la primera y segunda respectivamente. double function(double x, double p); int main(){ double a,b,p[500],p0,pf,inter,xl,xr,y0,j,x[500]; int i=0,s=0; FILE *raiz; printf("Por favor introduzca el intervalo [a,b] en el que desea hallar la raiz\n"); printf("a:"); scanf("%lf", &a); printf("b:"); scanf("%lf", &b); printf("Por favor introduzca el intervalo [p0,pf] del parametro p:\n"); printf("p0:"); scanf("%lf", &p0); printf("pf:"); scanf("%lf", &pf); for(j=p0;j<=pf;j=j+0.6){ p[s]=j; i=0; inter=PI/(2*j); xl=a; xr=a+inter; while(xl<b){ y0=function(xl,j)*function(xr,j); if(y0<0.0)i++; xl=xr; xr=xr+inter;} x[s]=i; s++;} N Vs P 300 raiz=fopen("numeros.txt","w"); fprintf(raiz,"p raíz\n"); for(i=0;i<s;i++)fprintf(raiz,"%lf \n", x[i]); fclose(raiz); 250 system("pause"); return 0;} 100 double funtion(double x, double p){ double y; y=(1/(1+(x*x)))-(sin(x*p)*sin(x*p)); return y;} 200 150 50 0 0 5 10 15 Gráfica 1. Número de raíces Vs P 20 25 1.4 Error entre métodos De igual forma, se halló la primera raíz con el método de Newton, agregando un contador en éste, comparando con el método de Bisección se encontró que en éste último se requirió una cantidad de 28 iteraciones mientras con el método de Newton sólo 2. Por lo tanto, mientras cumpla las condiciones es recomendable usar el método de Newton ya que consume menos memoria en cálculos extensos. El código para hallar las raíces con el método de Newton es: #include <stdio.h> #include <math.h> #include<stdlib.h> #define pi 3.14159265358979323846 double fun(double x, double p); double fund(double x, double p); double fun2d(double x, double p); double newton(double a,double b,double p, double tol); int main (){ double a,b,tol,p,inter,xl1,xr1,xl,xr,yt; double x[330]; int i=0,j=0,n=0; FILE *raiz; printf("Por favor introduzca el intervalo [a,b] en el cual desea hallar la raiz\n"); printf("a:"); scanf("%lf", &a); printf("b:"); scanf("%lf", &b); printf("tolerancia:"); scanf("%lf", &tol); printf("Ingrese el valor del parametro p: "); scanf("%lf", &p); inter=(pi/(2*p*1000)); xl=a; xr=a+inter; while(xl<b){ yt=fun(xl,p)*fun(xr,p); if(yt<0.0){ x[i]=newton(xl,xr,p,tol); printf("1\n"); i++;} xl=xr; xr=xr+inter;} raiz=fopen("raicesnewton.txt","w"); fprintf(raiz,"Raíces para %lf\n", p); for(j=0;j<i;j++)fprintf(raiz,"%lf \n", x[j]); fclose(raiz); return 0;} double newton(double a,double b,double p, double tol){ double y,yl,yr,wid,u; yl=fun(a,p)*fun2d(a,p); yr=fun(b,p)*fun2d(b,p); if(yl>0.0)y=a; if(yr>0.0)y=b; wid=sqrt((fun(y,p)/fund(y,p))*(fun(y,p)/fund(y,p) )); while(wid>tol){ y=(y)-(fun(y,p)/fund(y,p)); wid=sqrt((fun(y,p)/fund(y,p))*(fun(y,p)/fund(y,p) )); } return y;} double fun(double x, double p){ double y; y=(1/(1+(x*x)))-(sin(x*p)*sin(x*p)); return y;} double fund(double x, double p){ double y; y=(-2*x/pow((x*x+1),2))(2*p*sin(p*x)*cos(p*x)); return y;} double fun2d(double x, double p){ double y; y=((2*pow((x*x+1),2)+8*x*x*pow((x*x+1),2))/pow( x*x+1,4))-(2*x*x*(pow(cos(p*x),2)pow(sin(p*x),2))); return y;} 2 Interpolación Cuando se tiene un conjunto de valores de variables dependientes respecto a unas independientes de una función desconocida y se desea hallar otros posibles valores en un rango específico, se pueden utilizar distintos métodos para encontrar funciones que modelen su comportamiento y, a partir de esta función, obtener datos con una precisión específica. 2.1 Función Inicialmente se estableció una función conocida ( ) de la cual hallamos valores equidistantes entre el rango y encontramos sus imágenes respectivas . ( ) A partir de los valores de la imágenes les aplicamos un ruido aleatorio de la siguiente forma donde es la precisión, éste proceso se realizará para una precisión de y (ver tabla 4). Raíces para =0.100000 x[i] yex[i] y[i] 0.000000 0.000000 0.000000 0.314159 0.086913 0.088834 0.628318 0.247702 0.249690 0.942478 0.346619 0.347034 1.256637 0.350702 0.358166 1.570796 0.288401 0.296479 1.884955 0.198660 0.202461 2.199114 0.112148 0.113720 2.513274 0.047221 0.047384 2.827433 0.010617 0.010630 3.141592 0.000000 0.000000 Raíces para =0.000010 x[i] yex[i] y[i] 0.000000 0.000000 0.000000 0.314159 0.086913 0.086914 0.628318 0.247702 0.247703 0.942478 0.346619 0.346619 1.256637 0.350702 0.350702 1.570796 0.288401 0.288401 1.884955 0.198660 0.198660 2.199114 2.513274 2.827433 3.141592 0.112148 0.047221 0.010617 0.000000 0.112149 0.047221 0.010617 0.000000 Programa ----------------------------------------------------------#include<stdio.h> #include<stdlib.h> #include<math.h> #include<time.h> #define PI 3.14159265358979323846 double function(double x); int main(){ double a,b,e,m,n,u,rnd,j; int v,k,i=0,s=0; FILE *variable1; srand (time(NULL)); printf("Por favor introduzca el intervalo [a,b] en el que desea hallar la raiz\n"); printf("a:"); scanf("%lf", &a); printf("b:"); scanf("%lf", &b); printf("númebro de nodos: "); scanf("%d", &v); printf("precision: "); scanf("%lf", &e); double x[v],y[v]; m=(b-a)/(v-1); n=(b-a)/(k-1); u=rand() % 100000 + 0; rnd=u/100000; j=a; x[i]=j; y[i]=function(j)*(1+e*rnd); while(j<=b){ j=j+m; i++; u=rand() % 100000 + 0; rnd=u/100000; x[i]=j; y[i]=function(j)*(1+e*rnd);} variable1=fopen("tabla interpolación.txt","w"); fprintf(variable1,"%d %lf %lf %lf\n", v,e,a,b); for(s=0;s<=i;s++)fprintf(variable1,"%lf %3lf\n", x[s],y[s]); fclose(variable1); return 0;} double function(double x){ double y; y=(sin(x)*sin(x))/(1+(x*x)); return y;} ----------------------------------------------------------Continuando, aplicamos el método de interpolación de Lagrange para los dos casos y hallamos las imágenes de una malla de 201 nodos contenida en el mismo intervalo [a,b], así obteniendo una gráfica de la función (ver gráfica 2 y 3). Ya teniendo los N valores ( ), con el programa anterior, el programa de interpolación de Lagrange global es: ----------------------------------------------------------#include<stdio.h> #include<stdlib.h> #include<math.h> #include<time.h> #define PI 3.14159265358979323846 double function(double xn); double lagrange(double x[],double N,double xn); int main(){ double e,a,b,I; char t; int s,i=0,N; FILE *variable1; variable1=fopen("tabla interpolación.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); printf("Introduzca el número interpolar: "); scanf("%d", &s); double yn[s],yp[s],xn[s]; Gráfica 2. Valores de x Vs y para ᢄ=0.1 y[],int de nodos a 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]); printf("%lf\n", xn[i]); xn[i+1]=xn[i]+I;} variable1=fopen("interpolado.txt","w"); fprintf(variable1,"xn[i] yn[i] yp[i]\n"); for(i=0;i<s;i++)fprintf(variable1,"xn[%d]:%lf yn[%d]:%lf yp[%d]:%lf\n", i,xn[i],i,yn[i],i,yp[i]); fclose(variable1); Gráfica 3. Valores de x Vs y para ᢄ system("pause"); 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=(sin(xn)*sin(xn))/(1+(xn*xn)); return yp;} ----------------------------------------------------------Finalmente, con el fin de comparar, se realizó el mismo procedimiento con interpolaciones segmentarias lineal y parabólica; lo que se obtuvo fue lo siguiente: Gráfica 4. Valores de x Vs y para ᢄ=0.1 Interpolación Cuadrática Gráfica 5. Valores de x Vs y para ᢄ Interpolación Cuadrática El código para realizar segmentaria o lineal es: Gráfica 4. Valores de x Vs y para ᢄ=0.1 Interpolación lineal la interpolación ----------------------------------------------------------#include<stdio.h> #include<stdlib.h> #include<math.h> #define PI 3.14159265358979323846 double segmentadaL(double a,double h,double y[],int N,double xn); double segmentadaC(double a,double h,double y[],int N,double xn); double function(double xn); Gráfica 5. Valores de x Vs y para ᢄ Interpolación Lineal int main(){ double e,a,b,h,he; int s,i=0,N,P; FILE *variable1; variable1=fopen("tabla interpolación.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); printf("Introduzca el número de nodos a interpolar: "); scanf("%d", &s); double yn[s],yp[s],xn[s]; printf("Introduzca el tipo de interpolación segmentaria deseada: "); scanf("%d", &P); double segmentadaC(double a,double h,double y[],int N,double xn){ double yn,xs1,xs2; int k; k=(xn-a)/h; if(k==(N-1))k=k-1; y[5]=y[4]; xs1=a+(k)*h; xs2=xs1+h; yn=y[k]+((y[k+1]-y[k])*(xn-xs1)/h)+((y[k+2]2*y[k+1]+y[k])*(xn-xs1)*(xnxs2)/(2*pow(h,2))); return yn;} variable1=fopen("segmentariado.txt","w"); fprintf(variable1,"xn[i] yn[i] yp[i]\n"); for(i=0;i<s;i++)fprintf(variable1,"xn[%d]:%lf yn[%d]:%lf yp[%d]:%lf\n", i,xn[i],i,yn[i],i,yp[i]); fclose(variable1); double function(double xn){ double yp; yp=(sin(xn)*sin(xn))/(1+(xn*xn)); h=(b-a)/(N-1); he=(b-a)/(s-1); xn[0]=a; Comparando con los dato originales (ver gráfica 6) se observa que en estos casos es conveniente realizar una interpolación por el método de Lagrange y dejar un margen de error bastante pequeño, ya que proporciona una exactitud mayor a los datos for(i=0;i<s;i++){ if(P==1)yn[i]=segmentadaL(a,h,y,N,xn[i]); if(P==2)yn[i]=segmentadaC(a,h,y,N,xn[i]); yp[i]=function(xn[i]); xn[i+1]=xn[i]+he;} return yp;} 0.35 0.30 variable1=fopen("segmentariado.txt","w"); fprintf(variable1,"xn[i] yn[i] yp[i]\n"); for(i=0;i<s;i++)fprintf(variable1,"%lf\n", yn[i]”); fclose(variable1); 0.25 0.20 0.15 return 0;} double segmentadaL(double a,double h,double y[],int N,double xn){ double yn,xs; int k; k=(xn-a)/h; if(k==(N-1))k=k-1; xs=a+(k)*h; yn=y[k]+(y[k+1]-y[k])*(xn-xs)/h; return yn;} 0.10 0.05 0.5 1.0 1.5 2.0 2.5 3.0 Gráfica 6. Función ( ) Los datos exactos y los interpolados por lagrange, Newton lineal y Newton cuadrática se pueden encontrar en el documento Datos.xlsx anexo a la carpeta comprimida. [email protected] 3.5