Tipul | Lungimea | Intervalul de valori |
float | 4 octeti (32 biti) | [-3.402347e+38f, ... 3.402347e38f] |
double | 8 octeti (64 biti) | [-1.7976931348623157e+308, ... 1.7976931348623157e308] |
Reprezentarea internă a datelor în virgulă mobilă adoptată pentru mașina virtuală Java corespunde standardului ANSI/IEEE 754-1985.
Reprezentarea externă a numerelor în virgulă mobilă se poate
face în următoarele moduri:
a/ ca numere reale fără exponent, în care partea întreagă este
separată de cea fracționara prin punct;
b/ ca numere reale cu exponent, în care un număr întreg sau unul
real fără exponent, numit mantisa sau coeficient, este
urmat de un exponent zecimal, format din litera e sau
E urmata de un numar intreg. Semnificația este că mantisa se
înmultește cu 10 ridicat la o putere egală cu exponentul.
O caracteristică importantă a numerelor în virgulă mobilă este precizia.
Se numește precizie numărul maxim de cifre semnificative pe care îl
poate avea mantisa pentru tipul de date respectiv. Aceasta depinde de
numărul de biți alocați mantisei în reprezentarea internă. În cazul
limbajului Java, datele de tip float pot avea cel mult 7 cifre
semnificative, iar cele de tip double cel mult 16 cifre
semnificative. În reprezentarea externă a numărului se pot folosi și mai
multe cifre, dar cele care depășesc lungimea admisă nu vor fi luate în
considerație la conversia din forma externă în cea internă.
Cifrele semnificative sunt cifrele mantisei
numărului, care încep de la prima cifră diferită de zero și se termină
cu ultima cifra diferita de zero. De exemplu, numărul 000102.3015000
are 7 cifre semnificative (cele subliniate), deoarece zerourile de la
început și de la sfârșit nu influențează valoarea numărului. Același număr poate avea diferite reprezentări externe, de exemplu: 102.3015, 10.23015E1, 1.023015E2, 0.1023015E3, 0.01023015E4 etc. Pentru toate aceste numere, reprezentarea internă va fi aceeași. Menționăm că numerele de mai sus, deși au numai 7 cifre semnificative, vor fi reprezentate intern ca numere de tip double, deci pe 8 octeți fiecare. Pentru a fi reprezentate intern ca date de tip float (pe 4 octeti) trebuie scrise cu litera f sau F la sfârșit, de exemplu 102.3015f. |
În afară de valorile numerice, pentru datele în virgulă mobilă sunt prevăzute și următoarele valori speciale:
Infinity - corespunde valorii plus infinit;
-Infinity - corespunde valorii minus infinit;
NaN - reprezintă ceva care nu este număr (Nota Number).
În consecință, în cazul datelor de tipuri reale, dacă a este
un numar real pozitiv, operația a/0.0 dă ca rezultat Infinity,
iar operația a/(-0.0) da rezultatul -Infinity. Operația
0.0/0.0 dă rezultatul NaN.
Atenție: valorile Infinity, -Infinity și
NaN sunt formele externe sub care acestea se afișează pe
ecran, se tipăresc la imprimantă sau se scriu într-un fișier de text.
Fiecăreia dintre ele îi corespunde o reprezentare internă, sub
forma unui șir de 4 sau 8 octeți, corespunzător tipului float
sau double. Aceste reprezentări interne respectă regula,
conform căreia, dacă sunt interpretate ca numere în virgulă mobilă,
îndeplinesc următoarele condiții: Infinity este mai mare decat orice valoare de tipul respectiv; -Infinity este mai mică decât orice valoare de tipul respectiv. În acest fel, valorile menționate păstrează consistența operațiilor de comparație. |
Exemple de literali în virgulă mobilă a/ literali de tip float fără exponent: 123.7f, -1876.53f; b/ literali de tip float cu exponent: 7.28765e12f (echivalent cu 7.28765x1012) 5.0754286e-8f (echivalent cu 5.075428x10-8) -3.9104e3f (echivalent cu -3.9104x103) c/ literali de tip double fără exponent: 154236789.20973, -3401.76398653; d/ literali de tip double cu exponent: 2935.87628091e-12 -1.20937543872E23 12e23 (echivalent cu 12.0x1023) |
Atât la tipul float, cât și la tipul double, valoarea 0.0 are
semn: poate exista atât +0.0 cât și -0.0. Un 0 fără
semn este echivalent cu +0.0. Pentru tipul float,
aceste valori sunt scrise sub forma +0.0f și -0.0f.
Valorile speciale Infinity, -Infinity și NaN nu sunt literali, ci doar forme externe de afișare a valorilor interne corespunzătoare. În consecință, ele nu pot fi folosite în programele sursă. De exemplu, daca x este o variabilă în virgulă mobilă, nu putem face atribuirea x=Infinity. |
Conversia din double în float nu conduce niciodata la alterarea valorii, ci numai la pierderea de precizie. Aceasta se produce, întrucat se trece de la o mantisă de 52 de biți la una de 24 biți , deci de la cca 17 cifre semnificative la numai cca 7 cifre semnificative în sistemul zecimal.
În schimb, conversia explicită de la date în virgulă mobilă la oricare din datele de tip întreg poate duce la denaturarea valorii și a semnului numărului, la fel ca în cazul tipurilor intregi. Aceasta se întâmplă atunci când valoarea care trebuie convertită nu se încadrează în mulțimea de valori specifică tipului în care se face conversia.
Unei variabile în virgulă mobilă i se pot atribui orice valori de
tipuri numerice.
O particularitate importantă a operațiilor aritmetice în virgulă mobilă în limbajul Java este că împărțirea la zero nu mai este considerată o exceptie, ci este o operație permisă. Rezultatul împărțirii la zero depinde de valoarea deîmpărțitului și de semnele celor doi operanzi. Rezultatul împărțirii 0/0 este NaN (Not a Number, deci o valoare nedefinită). Dacă deîmpărțitul este diferit de zero, rezultatul împărțirii este Infinity cu un semn care se stabilește după semnele celor doi operanzi: + (plus) dacă au același semn, sau - (minus)dacă semnele operanzilor sunt diferite. Amintim că la numerele în virgulă mobilă în Java și valoarea zero are semn, deci există +0.0 si -0.0.
Exemplu
În programul din fișierul VirgulaMobila.java,
pe care îl reproducem mai jos, se testează diferite operații aritmetice
în virgulă mobilă, inclusiv cele care au ca rezultate valori speciale.
/* Testarea operatiilor aritmetice cu numere in virgula
mobila */
class VirgulaMobila { |
La executarea acestui program se afișează următorul rezultat:
a/b=-0.08089137723793256
b/a=-12.362257068001407 b%a=-4.631999999999991 a/c=Infinity b/c=-Infinity a/d=-Infinity b/d=Infinity c/d=NaN d/c=NaN p/q=1462896.8 q/p=6.835752E-7 p%q=0.001879394 p/r=Infinity p/s=-Infinity a/q=5381.048097062204 p/b=-21.991205809728285 a/inf1=0.0 a/inf2=-0.0 inf1/inf2=NaN inf2/inf1=NaN a*inf1=Infinity c*inf1=NaN |
Din aceste rezultate constatăm că:
- operațiile cu infiniți și nedeterminări respectă regulile
cunoscute din matematică (împărțirea la zero dă rezultat infinit, iar
0/0, infinit impartit la infinit și zero înmulțit cu infinit sunt
nedeterminări);
- dacă cel puțin un operand este în dublă precizie (double),
rezultatul este în dublă precizie; dacă ambii operanzi sunt în simplă
precizie (float), rezultatul este float;
- se verifică egalitatea [b/a]*a+(b%a)=b, in care [b/a]
este partea intreagă a câtului b/a, iar b%a este
restul împărțirii întregi a lui b la a; de exemplu, (-12)*12.7865-4.632=-158.07.