Enrere Mòdul 3
Fonaments de Programació. Llenguatge C/C++---
Pràctica  Resum teòric Exercicis
Pràctica d'ampliació

 
Mètodes numèrics per la resolució d'equacions 

No podem concebre un curs de programació sense citar, encara que sigui en una pràctica d'ampliació, una de les parts més importants dels mètodes numèrics: La resolució d'equacions. Veurem dos dels molts mètodes numèrics que existeixen per aquesta tasca.

 

Desenvolupament de la pràctica

Hi dues pràctiques anomenades m3pa11.c  i  m3pa12.c respectivament la primera i la segona.

Des de fa molt de temps són conegudes fórmules analítiques exactes per resoldre equacions polinòmiques de grau més petit o igual a 4. No obstant això, no existeixen mètodes analítics generals per resoldre equacions polinòmiques de grau superior a 4 i equacions que incorporen altres tipus de funcions (exponencials, logarítmiques, trigonomètriques, etc.). Els mètodes numèrics esdevenen imprescindibles per abordar la resolució d'aquests tipus d'equacions. 

Mètode de la bisecció

El mètode més senzill per resoldre una equació del tipus: f(x)=0, en el cas que la funció f(x) sigui una funció contínua, és una aplicació directa d'un dels teoremes més importants i coneguts de les funcions contínues: el teorema de Bolzano. Aquest teorema afirma que si una funció contínua en un interval tancat [a,b] pren valors de diferent signe en els extrems de l'interval, existirà, almenys un punt de l'interior de l'interval en el qual el valor de la funció serà 0. 

El mètode de la bisecció consisteix en un procés iteratiu en el qual es divideix l'interval en dues parts iguals i es tria un dels dos subintervals per continuar el mateix procediment. L'interval inicial és un interval en els extrems del qual la funció pren valors de diferent signe. El subinterval triat és un subinterval en el qual passa exactament el mateix que en l'interval inicial. Aquest procediment es pot continuar fins que la mida de l'interval sigui tan petit com es vulgui. 

El codi que implementa el mètode de la bisecció és el següent:

//m3pa11.c - mètode de la bisecció -

 

#include <stdio.h>

#include <stdlib.h>

 

double biseccio(double ,double , double);
double funcio(double);

 

int main(){

 

    double a,b,error;

 

    printf("introduïu els valors d'a,b...:");
    scanf("%lf %lf",&a,&b);

 

    printf("introduïu l'error màxim admet...:");
    scanf("%lf",&error);

 

    printf("\nsolució : %lf",biseccio(a,b,error));

    return 0;

}

 

 

double biseccio(double a, double b, double error){

 

    double fa,fb,fc,c;

 

    if (!funcio(a)) return a;
    if (!funcio(b)) return b;
    if (funcio(a)*funcio(b)>0){

        printf("L'interval [%lf,%lf] no compleix la
             condició",a,b);

        return 0;

    }

 

    if (a>b){

        c=a;a=b;b=c;

    }

 

    fa=funcio(a);fb=funcio(b);

    while (b-a>error){

        c=(a+b)/2;fc=funcio(c);

        if (!fc) return c;

        if (fa*fc>0){

            a=c;fa=fc;}
        else{
 

                        b=c;fb=fc;}

    }

    return (a+b)/2;

}

 

 

double funcio(double x){

    return x*x*x-5*x-2;

}

 

 

Captura de l'execució del programa.

 

 

Explicació del programa

En aquest cas s'ha implementat el mètode de la bisecció per trobar solucions de l'equació:

x3 - 5x - 2 = 0

Aquesta equació es pot expressar com f(x)=0, on f(x) és el primer membre de l'equació. Aquesta funció matemàtica correspon justament a la funció funcio() del programa anterior.

El programa demana com dades inicials els extrems de l'interval inicial i l'error màxim que es vol admetre.

El càlcul es fa a través de la funció bisecció(). Aquesta funció comença comprovant si els propis extrems de l'interval satisfan l'equació o bé si la funció no pren signes diferents en aquests extrems. Si no és així va dividint l'interval en dos fins que b-a, la mida de l'interval, sigui inferior a l'error preestablert. Quant passa això últim, la funció torna com valor de retorn el punt mig de l'interval.

En el cas de la funció de l'exemple hi ha tres arrels. La gràfica de la funció f(x) és:

 

Mètode de Newton

Encara que pot semblar que el mètode anterior troba la solució ràpidament, veurem un altre mètode que millora substancialment el mètode anterior, es tracta del mètode de Newton. 

Aquest mètode és un procés iteratiu que en cada pas dóna una millor aproximació a la solució de l'equació f(x)=0.

Sigui xn una aproximació de l'arrel. Traçant la recta tangent a la corba y = f(x) pel punt (xn, f(xn)), la intersecció d'aquesta recta amb l'eix d'abscisses serà una millor aproximació de la solució. Si anomenem a aquest punt xn+1 i tornem a aplicar aquest procés s'arriba a una successió d'aproximacions que, en condicions habituals, convergeix molt més ràpidament que pel mètode de la bisecció.

 

El valor d' xn+1 es pot trobar amb la intersecció de la recta tangent: y - f(xn) = f'(xn)·(x-xn) i l'eix d'abscisses, donant lloc a la relació:

  

En el següent programa podrem calcular una solució de l'equació f(x)=0 amb el mètode de Newton. En aquest programa hem afegit dues funcions que corresponen a la definició de f(x) i la seva derivada. En aquest cas f(x)=ex - x i f'(x)=ex-2x.

 

//m3pa12.c - Mètode de Newton -

 

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

#include <stdlib.h>

 

#define MAX_ITER 20

 

double newton(double, double);
double f (double);
double df (double);

 

int main(){

 

    double x0,error;

 

    printf("introduïu x0 i error...");
    scanf("%lf %lf",&x0, &error);
    printf("\nLa solució és %lf\n",newton(x0,error));

     return 0;

}

 

 

double newton(double x0,double error){

 

    int iter=0;

    double x;

 

    x=x0;

    do{

       x0=x;
       x=x0-f(x0)/df(x0);
       printf("%lf %lf\n",x,x-x0);

    }while(fabs(x-x0)>error&&iter++<MAX_ITER);

 

    return x;

}

 

double f(double x){           //definició de f(x) 

     return exp(x)-x*x;

}

 

double df(double x){         //definició de f'(x)

    return exp(x)-2*x;

}

 

 

Captura de l'execució del programa.

 

 

L'única arrel de l'equació f(x)=0 està entre -1 i 0 tal i com es pot comprovar en la gràfica de f(x):