1. Rotunjirea numerelor reale

După cum am discutat deja, atunci când un număr real este atribuit unei intvariabile, acesta este întotdeauna rotunjit în jos la cel mai apropiat număr întreg mai mic - partea fracțională este pur și simplu aruncată.

Dar este ușor să ne imaginăm o situație în care un număr fracționar trebuie rotunjit la cel mai apropiat număr întreg în orice direcție sau chiar rotunjit în sus. Ce faci in acest caz?

Pentru aceasta și pentru multe situații similare, Java are clasa Math, care are metodele round(), ceil()și floor().


Math.round()metodă

Metoda Math.round()rotunjește un număr la cel mai apropiat număr întreg:

long x = Math.round(real_number)

Dar există o altă nuanță aici: această metodă returnează un longnumăr întreg (nu un int). Deoarece numerele reale pot fi foarte mari, creatorii Java au decis să folosească cel mai mare tip întreg disponibil din Java: long.

În consecință, dacă un programator dorește să atribuie rezultatul unei intvariabile, atunci ea trebuie să indice în mod explicit compilatorului că acceptă posibila pierdere de date (în cazul în care numărul rezultat nu se încadrează într-un inttip).

int x = (int) Math.round(real_number)

Exemple:

Afirmație Rezultat
int x = (int) Math.round(4.1);
4
int x = (int) Math.round(4.5);
5
int x = (int) Math.round(4.9);
5

Math.ceil()metodă

Metoda Math.ceil()rotunjește un număr la un număr întreg. Iată exemple:

Afirmație Rezultat
int x = (int) Math.ceil(4.1);
5
int x = (int) Math.ceil(4.5);
5
int x = (int) Math.ceil(4.9);
5

Math.floor()metodă

Metoda Math.floor()rotunjește un număr la un număr întreg. Iată exemple:

Afirmație Rezultat
int x = (int) Math.floor(4.1);
4
int x = (int) Math.floor(4.5);
4
int x = (int) Math.floor(4.9);
4

Desigur, atunci când rotunjiți un număr la un număr întreg, este mai ușor să utilizați pur și simplu un operator de tip cast:(int)

Afirmație Rezultat
int x = (int) 4.9
4

Dacă vă este dificil să vă amintiți aceste nume, o scurtă lecție de engleză vă va ajuta:

  • Mathînseamnă matematică
  • Roundînseamnă rotund
  • Ceilingînseamnă tavan
  • Floorînseamnă podea

2. Cum sunt structurate numerele în virgulă mobilă

Tipul doublepoate stoca valori în intervalul de la până la . Această gamă uriașă de valori (în comparație cu tipul) se explică prin faptul că tipul (precum și ) are o structură internă complet diferită de tipurile întregi. Pe plan intern, tipul își codifică valoarea ca două numere: primul se numește mantisa , iar al doilea se numește exponent .-1.7*10308+1.7*10308intdoublefloatdouble

Să presupunem că avem numărul 123456789și îl stocăm într-o doublevariabilă. Când o facem, numărul este convertit în , iar în interior tipul stochează două numere — și . Semnificativul („partea semnificativă a numărului” sau mantisa) este evidențiat cu roșu, în timp ce exponentul este evidențiat cu albastru.1.23456789*108double234567898

Această abordare face posibilă stocarea atât a unor numere foarte mari, cât și a celor foarte mici. Dar pentru că reprezentarea numărului este limitată la 8 octeți (64 de biți) și unii dintre biți sunt utilizați pentru a stoca exponentul ( precum și semnul mantisei și semnul exponentului), cifrele maxime disponibile pentru a reprezenta mantisa . este 15 .

Aceasta este o descriere foarte simplificată a modului în care sunt structurate numerele reale.


3. Pierderea preciziei la lucrul cu numere reale

Când lucrați cu numere reale, rețineți întotdeauna că numerele reale nu sunt exacte . Pot exista întotdeauna erori de rotunjire și erori de conversie la conversia de la zecimal la binar. În plus, cea mai comună sursă de eroare este pierderea preciziei la adunarea/scăderea numerelor la scări radical diferite.

Acest ultim fapt este puțin uimitor pentru programatorii începători.

Dacă scadem din , obținem .1/109109109

Scăderea numerelor pe scări radical diferite Explicaţie
 1000000000.000000000;
-         0.000000001;
 1000000000.000000000;
Al doilea număr este extrem de mic , ceea ce va face ca semnificația sa (evidențiată cu gri) să fie ignorată. Cele 15 cifre semnificative sunt evidențiate cu portocaliu.

Ce putem spune, programarea nu este la fel cu matematica.


4. Capcană la compararea numerelor reale

Un alt pericol îl așteaptă pe programatori atunci când compară numerele reale. Apare atunci când lucrați cu numere reale, deoarece se pot acumula erori de rotunjire. Rezultatul este că există situații în care se așteaptă ca numerele reale să fie egale, dar nu sunt. Sau invers: se așteaptă ca numerele să fie diferite, dar sunt egale.

Exemplu:

Afirmație Explicaţie
double a = 1000000000.0;
double b = 0.000000001;
double c = a - b;
Valoarea variabilei a va fi 1000000000.0
Valoarea variabilei c va fi 1000000000.0
(numărul din b variabilă este excesiv de mic)

În exemplul de mai sus, ași cnu ar trebui să fie egale, dar sunt.

Sau să luăm un alt exemplu:

Afirmație Explicaţie
double a = 1.00000000000000001;
double b = 1.00000000000000002;
Valoarea variabilei a va fi 1.0
Valoarea variabilei b va fi1.0

5. Un fapt interesant desprestrictfp

Java are un cuvânt cheie special (strictfp strict floating point ) , care nu se găsește în alte limbaje de programare. Și știi de ce ai nevoie? Înrăutățește acuratețea operațiunilor cu numere în virgulă mobilă . Iată povestea cum a apărut:

Creatorii Java:
Ne dorim cu adevărat ca Java să fie super popular și să ruleze programe Java pe cât mai multe dispozitive posibil. Așa că ne-am asigurat că specificația pentru mașina Java spune că toate programele trebuie să ruleze la fel pe toate tipurile de dispozitive!
Producătorii procesoarelor Intel:
Buna tuturor! Ne-am îmbunătățit procesoarele, iar acum toate numerele reale sunt reprezentate folosind 10 octeți în loc de 8 octeți în interiorul procesoarelor noastre. Mai mulți octeți înseamnă cifre mai semnificative. Ce înseamnă asta? Asta e corect! Acum calculele tale științifice vor fi și mai precise!
Oamenii de știință și toți cei implicați în calcule ultra-precise:
Misto! Bine făcut. Vești excelente!
Creatorii Java:
Nu-nu-nu, băieți! V-am spus deja că toate programele Java trebuie să ruleze la fel pe toate dispozitivele . Vom dezactiva forțat capacitatea de a folosi numere reale de 10 octeți în interiorul procesoarelor Intel.
Acum totul este bine din nou! Nu ne mulțumi.
Oamenii de știință și toți cei implicați în calcule ultra-precise:
Ai înnebunit complet? Readuceți rapid totul așa cum a fost!
Creatorii Java:
Băieți, asta este pentru binele vostru! Imaginează-ți: toate programele Java rulează în același mod pe toate dispozitivele . E atât de tare!
Oamenii de știință și toți cei implicați în calcule ultra-precise:
Nu. Nu e deloc cool. Pune repede totul la loc cum a fost! Sau știți unde vă vom pune Java?
Creatorii Java:
Hmm. De ce nu ai spus asta imediat? Desigur, îl vom pune înapoi.
V-am restabilit capacitatea de a utiliza toate caracteristicile celor mai recente procesoare.
Apropo... Am adăugat special cuvântul strictfpcheie la limbă. Dacă îl scrieți înaintea numelui unei funcții, atunci toate operațiunile care implică numere reale din acea funcție vor fi la fel de proaste pe toate dispozitivele !