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