Tuesday, November 17, 2015

Limbajul C. O ecuatie neliniara rezolvata cu metoda bisectiei.


Problema urmatoare reprezinta proiectul de mid-term al cursului predat la University College Cork. Enuntul - sa se rezolve prin metoda bisectiei urmatoarea ecuatie neliniara:

sin(2x/5) - x + 1 = 0.

O prima observatie este ca avem o suma de doua functii continue, deci functia-rezultat este continua.

Ecuatia se poate rescrie sin(2x/5) = x - 1, deci intr-o rezolvare "geometrica" ar trebui determinat punctul de intersectie al dreptei x - 1 cu graficul lui sin(2x/5), conform figurii urmatoare, desenata chinuit, cu pixul:-)



f(x) = sin(2x/5) - x + 1 fiind continua si presupunand ca ecuatia f(x) = 0 are solutie (adica graficul ei intersecteaza axa Ox in punctul - solutie), inseamna ca intr-un interval care contine solutia functia va lua valori de semn contrar pentru argumente situate la stanga, respectiv la dreapta punctului - solutie.

Daca luam un interval inchis oarecare [l1, l2] care contine punctul - solutie, atunci f(l1)*f(l2) < 0. Daca restrangem cu un pas oarecare, p, acest interval, [l1 + p, l2 - p], si inegalitatea f(l1 + p) * f(l2 - p) < 0 se pastreaza, atunci putem sa repetam (sa iteram) aceasta operatiune pana cand inegalitatea nu mai este valabila.

Asta poate insemna doua lucruri:

1) fie pasul p nu a fost suficient de "fin" si am trecut cu ambele argumente, l1 + p, l2 - p, "de aceeasi parte" a punctului - solutie.

2) fie am atins cu una dintre extremitati, l1 + p sau l2 - p, punctul - solutie, cu o precizie convenabil aleasa anterior.

In continuare, codul in C, neoptimizat, si printscreen-urile cu ambele scenarii:
a) pas insuficient de fin si b) solutia gasita cu precizia ceruta (in cazul de fata, 10 la minus 5).

Observatie importanta: in cazul numerelor reale, precizia reprezentarii este limitata. Egalitatea stricta cu care suntem obisnuiti in cazul numerelor intregi nu se aplica aici.

Daca a si b sunt intregi si egali, are sens sa scriem a - b == 0. Daca ele sunt insa numere reale, ce putem face este sa scriem |a - b| < epsilon, unde epsilon este precizia aleasa convenabil. Evident, nu are sens sa alegem o precizie mai mare decat a tipului numeric cu care lucram, float sau double, adica 7 sau 15 zecimale.

// sinus2

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

double MyFunction(double x)
{
       return sin(2*x/5) - x + 1;
}

// functia e continua, ca suma de functii continue

int main(void)
{
    double l1, l2, pas;
str:puts("Introduceti limitele intervalului in format l1, l2 numere reale.");
    scanf("%lf, %lf", &l1, &l2);
 
if(MyFunction(l1)*MyFunction(l2) < 0)
printf("\nIntervalul este ok, specificati pasul. Precizia compararii cu zero este E-5.\n");
else goto str;
 
scanf("%lf", &pas);
 
while(MyFunction(l1)*MyFunction(l2) < 0)
    {
      l1 += pas;
      l2 -= pas;
      printf("\n[%.10f                    %.10f]", l1, l2);
    }
   
printf("\n\n%.10f, %.10f.\n", MyFunction(l1), MyFunction(l2));
  printf("\n%.10f, %.10f.\n", MyFunction(l1 - pas), MyFunction(l2 + pas));
   
if(fabs(MyFunction(l1)) < 1e-5)
  printf("\nSolutia este %.10f. MyFunction(%f) = %.10f", l1, l1, MyFunction(l1));
  else if(fabs(MyFunction(l2)) < 1e-5)
  printf("\nSolutia este %.10f. MyFunction(%f) = %.10f ", l2, l2, MyFunction(l2));
  else
      {
          printf("\nPasul nu e destul de fin. Introduceti altul cu aceleasi limite de interval!\n");
          goto str;
      }
     return 0;
}



Solutia obtinuta la un pas = 0.00000007 (7E-8):



No comments:

Post a Comment