Pagini: [1]   În jos
  Imprimă  
Ajutor Subiect: calcule cu zecimale  (Citit de 12980 ori)
0 Utilizatori şi 1 Vizitator pe acest subiect.
mihai.plesa
Client obisnuit
**

Karma: 0
Deconectat Deconectat

Mesaje: 74



Vezi Profilul
« : Aprilie 30, 2012, 13:51:44 »

Salut!
Trebuie sa fac un program in care apar foarte multe impartiri...am observat ca dupa anumit numar de zecimale (rezultat in urma impartirii) zecimalele scrise de calculator nu mai corespund cu zecimalele reale...mai exact ultimele zecimale nu mai corespund cu cele reale ...spre exemplu daca in realitate este 2.158958759 imi afiseaza 2.15895876 . Problema apare atunci cand vreau sa inmultesc valoarea afisata (2.15895876) cu doi ...cele 2 zecimale finale (cele afisate de calculator) conteaza...valoarea care imi este afisata nu este valoarea reala (cea pe care am inmpartit-o la 2 rezultand 2.15895876 pe calculator si 2.158958759 in realitate). O problema mai mare apare atunci cand eu vreau sa inmultesc valoarea afisata de calculator (in urma inmultirii cu 2) cu 2 iar valoarea afisata sa o inmultesc iarasi cu 2 si tot asa....pe masura ce inmultesc cu 2 ,valoarea afisata este mai departata de cea reala.

Eu vrea sa fac o impartire cu 4 zecimale....zecimale reale fara aproximare...eu NU vreau doar sa se afiseze cu 4 zecimale exacte eu vreau ca rezultatul impartirii sa fie cu 4 zecimale exacte . Cum as putea sa fac acest lucru? Trebuie setat ceva din MinGW?

Multumesc mult!
Memorat
MciprianM
Nu mai tace
*****

Karma: 87
Deconectat Deconectat

Mesaje: 324



Vezi Profilul
« Răspunde #1 : Aprilie 30, 2012, 14:16:47 »

Numerele reale sunt numere care nu pot fi reprezentate exact in calculator. Gandeste-te la 1/3 sau radical din 2. Acestea au o infinitate de zecimale. Si de aceea daca ai o variabila de tip double, ea va fi tot timpul o aproximare a numarului pe care il doresti. Totusi, de obicei, aproximarea e destul de buna. Eventual poti sa incerci long double daca double nu e de ajuns. O alta idee ar fi sa incerci sa eviti sa faci multe operatii pe un numar real, deoarece eroarea se acumuleaza. De exemplu daca ai x * (y + z) - y * (x + z) e bine sa simplifici la z * (x - y).
Daca vrei sa compari doua numere reale, ele pot fi putin diferite chiar daca reprezinta acelasi numar. De aceea, nu se foloseste direct operatorul ==, ci se verifica daca diferenta e suficient de mica incat sa consideram numerele egale. Exemplu:
Cod:
const double eps = 1e-6;
double a = 2.1 * (2.3 + 2.4) - 2.3 * (2.1 + 2.4);
double b = 2.4 * (2.1 - 2.3);
if (a == b) {
  cout << "== egale" << endl;
}
else {
  cout << "== diferite" << endl;
}
if (abs (a - b) < eps) {
  cout << "eps egale" << endl;
}
else {
  cout << "eps diferite" << endl;
}

Totul depinde de precizia de care ai nevoie la problema (de acolo il ei pe eps). Daca ai nevoie de precizie foarte mare s-ar putea sa nu poti face ce vrei, dar la 4 zecimale dupa virgula, de obicei ajunge double. Ideea e ca daca diferenta dintre doua numere e mai mica decat 0.00001, atunci cele doua numere au primele 4 cifre de dupa virgula identice.
Multa lume s-a pacalit cu numerele reale. Uite cateva exemple din viata reala: http://ta.twi.tudelft.nl/users/vuik/wi211/disasters.html
Memorat
mihai.plesa
Client obisnuit
**

Karma: 0
Deconectat Deconectat

Mesaje: 74



Vezi Profilul
« Răspunde #2 : Aprilie 30, 2012, 14:25:02 »

Numerele reale sunt numere care nu pot fi reprezentate exact in calculator. Gandeste-te la 1/3 sau radical din 2. Acestea au o infinitate de zecimale. Si de aceea daca ai o variabila de tip double, ea va fi tot timpul o aproximare a numarului pe care il doresti. Totusi, de obicei, aproximarea e destul de buna. Eventual poti sa incerci long double daca double nu e de ajuns. O alta idee ar fi sa incerci sa eviti sa faci multe operatii pe un numar real, deoarece eroarea se acumuleaza. De exemplu daca ai x * (y + z) - y * (x + z) e bine sa simplifici la z * (x - y).
Daca vrei sa compari doua numere reale, ele pot fi putin diferite chiar daca reprezinta acelasi numar. De aceea, nu se foloseste direct operatorul ==, ci se verifica daca diferenta e suficient de mica incat sa consideram numerele egale. Exemplu:
Cod:
const double eps = 1e-6;
double a = 2.1 * (2.3 + 2.4) - 2.3 * (2.1 + 2.4);
double b = 2.4 * (2.1 - 2.3);
if (a == b) {
  cout << "== egale" << endl;
}
else {
  cout << "== diferite" << endl;
}
if (abs (a - b) < eps) {
  cout << "eps egale" << endl;
}
else {
  cout << "eps diferite" << endl;
}

Totul depinde de precizia de care ai nevoie la problema (de acolo il ei pe eps). Daca ai nevoie de precizie foarte mare s-ar putea sa nu poti face ce vrei, dar la 4 zecimale dupa virgula, de obicei ajunge double. Ideea e ca daca diferenta dintre doua numere e mai mica decat 0.00001, atunci cele doua numere au primele 4 cifre de dupa virgula identice.
Multa lume s-a pacalit cu numerele reale. Uite cateva exemple din viata reala: http://ta.twi.tudelft.nl/users/vuik/wi211/disasters.html

Multumesc de raspuns...as vrea sa te mai intreb ceva...
Daca spre exemplu in urma unei impartiri calculatorul imi afiseaza 2.258456 cum fac ca atunci cand inmultesc cu 2 sa ia in calcul numai primele 4 zecimale... adica in loc de 2.258456*2 sa calculeze numai 2.2584*2...de chestia asta am eu nevoie pana la urma...trebuie sa adaug ceva in cod?
Multumesc mult !
Memorat
MciprianM
Nu mai tace
*****

Karma: 87
Deconectat Deconectat

Mesaje: 324



Vezi Profilul
« Răspunde #3 : Aprilie 30, 2012, 14:37:45 »

Daca tu tai aiurea din zecimale, doar faci aproximarea mai proasta. Uite un exemplu:

5/7=0.71428571...
(5/7)*2=10/7=1.428571...
Deci raspunsul de care ai nevoie e 1.4285
Dar 0.7142*2=1.4284

Daca ai nevoie sa afisezi exact 4 zecimale, poti sa folosesti functia printf pentru afisare pe ecran:
Cod:
double v = 0.54346;
printf ("%.4lf", v);

".4" inseamna 4 zecimale dupa virgula.
« Ultima modificare: Aprilie 30, 2012, 14:47:38 de către Marginean Ninu Ciprian » Memorat
PlayLikeNeverB4
Nu mai tace
*****

Karma: 212
Deconectat Deconectat

Mesaje: 721



Vezi Profilul
« Răspunde #4 : Aprilie 30, 2012, 15:32:15 »

Daca vrei sa retii valoarea doar cu ultimele 4 zecimale poti inmulti cu 10000, tai toate zecimalele si apoi imparti cu 10000.
Memorat
Pagini: [1]   În sus
  Imprimă  
 
Schimbă forumul:  

Powered by SMF 1.1.19 | SMF © 2006-2013, Simple Machines