De ce contează?
Gândește-te la o riglă obișnuită: cu ea poți măsura 12 centimetri, dar 12,4 centimetri deja îi „ghicești” între liniuțe. Oricât de fină ar fi rigla, mereu rămâne un firicel pe care nu îl poți măsura perfect — doar îl aproximezi. Numerele reale din calculator sunt exact așa: o riglă uimitor de fină, dar tot finită. Te apropii enorm de valoarea adevărată, însă aproape niciodată nu o nimerești la milimetru.
Ce este
Un tip real stochează numere cu virgulă: 3.14, 0.5, -2.75, 100.0. Le folosești când întregii nu sunt suficienți — medii, prețuri, măsurători, procente.
Atenție la un detaliu de C++: separatorul zecimal este punctul, nu virgula. Scrii 3.14, nu 3,14.
În C++ ai două tipuri reale principale:
float— „real simplu”, ține cam 7 cifre exacte.double— „real dublu”, ține cam 15–16 cifre exacte.
double ocupă mai mult spațiu (8 octeți față de 4), dar pe calculatoarele de azi diferența nu se simte. De aceea regula practică e simplă.
Folosește mereu double, nu float. „Double” înseamnă „dublă precizie”: de la ~7 cifre corecte sări la ~15–16. Cu float, 1.0 / 3.0 îți dă 0.3333333, apoi cifrele devin gunoi; cu double ai 0.333333333333333. La concurs alegi double fără să stai pe gânduri.
Cum arată
Aici e partea pe care mulți o trec cu vederea: numerele reale sunt aproximări, nu valori exacte. Calculatorul gândește în baza 2, iar multe numere care arată simplu pentru noi nu încap perfect acolo — exact ca 1/3 = 0.3333..., care nu se termină niciodată în baza 10.
Hai să adunăm 0.1 + 0.2. Tu te aștepți la 0.3. Iată ce ține calculatorul de fapt în memorie, dacă ne uităm la primele cifre:
0.1 | + | 0.2 | = | ? |
a | op | b | eq | rez |
0.100000000 | 0.200000000 | 0.300000000 |
0.1 | 0.2 | 0.3-asteptat |
0.10000...001 | 0.20000...000 | 0.30000...004 |
0.1-real | 0.2-real | 0.1+0.2 |
NU-e-0.3 |
Diferența e minusculă — pe la a 17-a zecimală. Pentru afișat nu te deranjează deloc. Devine însă o capcană când compari numere (vezi mai jos).
Pentru a afișa frumos, controlezi câte zecimale vrei cu fixed și setprecision. Cu setprecision(2) ceri exact 2 zecimale:
3.14159265 | cu-2-zecimale | 3.14 |
valoare | regula | rezultat |
rotunjit |
Implementare C++
Ai nevoie de #include <iomanip> pentru fixed și setprecision.
#include <iostream>
#include <iomanip> // pentru fixed si setprecision
using namespace std;
int main() {
double a = 0.1, b = 0.2;
double suma = a + b;
// afisare bruta: vezi eroarea de aproximare
cout << setprecision(17) << suma << endl; // 0.30000000000000004
// afisare cu exact 2 zecimale, cum vrei la rezultate
cout << fixed << setprecision(2);
cout << suma << endl; // 0.30
double pret = 19.5, bucati = 3;
cout << pret * bucati << endl; // 58.50
return 0;
}Reține: fixed spune „număr cu zecimale fixe”, iar setprecision(2) spune „câte zecimale”. Împreună dau exact 2 zecimale la fiecare afișare care urmează.
Comparația cu == te trădează
Pentru că 0.1 + 0.2 nu e fix 0.3, o verificare directă dă fals:
#include <iostream>
#include <cmath> // pentru fabs (valoare absoluta)
using namespace std;
int main() {
double x = 0.1 + 0.2;
// GRESIT: == cere egalitate perfecta, dar x = 0.30000000000000004
if (x == 0.3)
cout << "egale" << endl;
else
cout << "diferite" << endl; // se afiseaza "diferite" !
// CORECT: sunt "egale" daca diferenta e neglijabila
if (fabs(x - 0.3) < 1e-9) // 1e-9 = 0.000000001
cout << "practic egale" << endl; // se afiseaza asta
else
cout << "chiar diferite" << endl;
return 0;
}Ideea-cheie, pe care merită s-o ții minte toată viața: la numere reale nu întrebi „sunt egale?”, ci „sunt suficient de apropiate?”. Verifici dacă diferența lor, în valoare absolută, e mai mică decât un prag minuscul (numit epsilon), de obicei 1e-9. Funcția fabs îți dă valoarea absolută, ca să meargă și când diferența iese negativă.
Greșeala numărul unu cu reale: compari cu ==. Codul tău crede că 0.1 + 0.2 e 0.3, scrie if (suma == 0.3), trece pe exemplul din enunț și apoi pică misterios pe testele ascunse. Calculatorul are dreptate, tu ai uitat că realele sunt aproximări. Regula de aur: compară mereu cu o toleranță — fabs(a - b) < 1e-9 — niciodată cu ==. Și încă o capcană: nu uita #include <iomanip> pentru setprecision, altfel codul nici nu compilează.