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