Vrijedi li da je ? Da, naravno!
Što ispisuje slijedeći programski isječak?
if (0.7 + 0.2 + 0.1 == 1) {
cout << "da, naravno!" << endl;
} else {
cout << "wait." << endl;
}Operator == će u programu provjeriti jesu li lijeva i desna strana jednake, odnosno sadržavaju li (privremeni) objekti s lijeve i desne strane istu vrijednost u memoriji.
Pogledajmo na kratko kako izgledaju gore uspoređeni brojevi u memoriji (hexadecimalno) i kada se ispišu na 20 decimalnih mjesta.
union broj { long long ll; double lf; } A, B; A.lf = 1; B.lf = 0.7 + 0.2 + 0.1; printf("%lx %.20lf\n", A.ll, A.lf); // ispisuje 3ff0000000000000 1.00000000000000000000 printf("%lx %.20lf\n", B.ll, B.lf); // ispisuje 3fefffffffffffff 0.99999999999999988898
Ovdje je union iskorišten da bi pogledali zapis broja s pomičnom točkom kako je zapisan u memoriji.
Razlog ovom hazardu je ograničena preciznost zapisa brojeva koji se koristi. Odnosno, broj 0.7 kada se zapiše u binarnom zapisu je periodičan broj, slično kao što je periodičan broj u dekadskom zapisu. Kada bi u takvom ograničenom zapisu pokušali izračunati također bi dobili broj koji nije točno već približno. Za one koji žele više - numerička matematika.
Stoga, uvijek kada je potrebno u zadatku koristiti i uspoređivati decimalne brojeve potrebno je to raditi imajući na umu preciznost:
typedef double lf;
const lf EPSILON = 1e-12;
inline bool lt(const lf& a, const lf& b) { return b - a > EPSILON; }
inline bool gt(const lf& a, const lf& b) { return lt(b, a); }
inline bool eq(const lf& a, const lf& b) { return !lt(a, b) && !lt(b, a); }
inline bool le(const lf& a, const lf& b) { return !gt(a, b); }
inline bool ge(const lf& a, const lf& b) { return !lt(a, b); }Definirani operatori redom predstavljaju C operatore <, >, ==, <=, >=.
Uz ovako definirane operatore usporedbe, nemamo problema jer je eq(0.7 + 0.2 + 0.1, 1) - da, naravno!
Ovaj članak objavljen je pod
Creative Commons Attribution-ShareAlike 3.0 Croatia License