Compactarea multor numere reale infinite într-un număr finit de biți necesită o reprezentare aproximativă. Majoritatea programelor stochează rezultatul calculelor întregi la 32 sau 64 de biți max. Având în vedere orice număr fix de biți, majoritatea calculelor cu numere reale vor produce cantități care nu pot fi reprezentate exact folosind atât de mulți biți. Prin urmare, rezultatul unui calcul în virgulă mobilă trebuie adesea să fie rotunjit pentru a se potrivi înapoi în reprezentarea sa finită. Această eroare de rotunjire este o caracteristică caracteristică calculului în virgulă mobilă. Prin urmare, atunci când gestionăm calcule în numere în virgulă mobilă (mai ales dacă calculele sunt în termeni de bani), trebuie să avem grijă de erorile de rotunjire într-un limbaj de programare. Să vedem un exemplu:
Javapublic class Main { public static void main(String[] args) { double a = 0.7; double b = 0.9; double x = a + 0.1; double y = b - 0.1; System.out.println('x = ' + x); System.out.println('y = ' + y ); System.out.println(x == y); } }
harta vs set
Ieșire:
x = 0.7999999999999999
y = 0.8
false
Aici răspunsul nu este ceea ce ne așteptam, motivul fiind rotunjirea făcută de compilatorul java.
Motivul din spatele erorii de rotunjire
Tipurile de date Float și Double implementează specificația IEEE 754 în virgulă mobilă. Aceasta înseamnă că numerele sunt reprezentate într-o formă ca:
SIGN FRACTION * 2 ^ EXP 0,15625 = (0,00101)2care în format virgulă mobilă este reprezentată ca: 1,01 * 2^-3
Nu toate fracțiile pot fi reprezentate exact ca o fracțiune a unei puteri a lui doi. Ca exemplu simplu 0,1 = (0,000110011001100110011001100110011001100110011001100110011001… )2 și astfel nu poate fi stocat în interiorul unei variabile în virgulă mobilă.
Un alt exemplu:
javapublic class Main { public static void main(String[] args) { double a = 0.7; double b = 0.9; double x = a + 0.1; double y = b - 0.1; System.out.println('x = ' + x); System.out.println('y = ' + y ); System.out.println(x == y); } }
Ieșire:
x = 0.7999999999999999
y = 0.8
false
Un alt exemplu:
Javapublic class Main { public static void main(String args[]) { double a = 1.0; double b = 0.10; double x = 9 * b; a = a - (x); // Value of a is expected as 0.1 System.out.println('a = ' + a); } }
Ieșire:
a = 0.09999999999999998Cum să remediați erorile de rotunjire?
- Rotunjiți rezultatul: Funcția Round() poate fi utilizată pentru a minimiza orice efect al inexactității stocării aritmetice în virgulă mobilă. Utilizatorul poate rotunji numerele la numărul de zecimale cerut de calcul. De exemplu, atunci când lucrați cu monedă, probabil că veți rotunji la 2 zecimale.
- Algoritmi și funcții: Utilizați algoritmi stabili numeric sau proiectați-vă propriile funcții pentru a gestiona astfel de cazuri. Puteți trunchia/rotunji cifrele pentru care nu sunteți sigur că sunt corecte (puteți calcula și precizia numerică a operațiilor)
- Clasa BigDecimal: Puteți folosi java.math.BigDecimal clasă care este concepută pentru a ne oferi acuratețe mai ales în cazul numerelor fracționale mari. Următorul program arată cum poate fi eliminată eroarea:
import java.math.BigDecimal; import java.math.RoundingMode; public class Main { public static void main(String args[]) { BigDecimal a = new BigDecimal('1.0'); BigDecimal b = new BigDecimal('0.10'); BigDecimal x = b.multiply(new BigDecimal('9')); a = a.subtract(x); // Rounding to 1 decimal place a = a.setScale(1 RoundingMode.HALF_UP); System.out.println('a = ' + a); } }
Ieșire:
0.1Aici a = a.setScale(1 RoundingMode.HALF_UP);
Runde ala 1 zecimală utilizând modul de rotunjire HALF_UP. Prin urmare, utilizarea BigDecimal oferă un control mai precis asupra operațiunilor aritmetice și de rotunjire, care poate fi deosebit de util pentru calcule financiare sau alte cazuri în care precizia este crucială.
Notă importantă:
Math.round rotunjește valoarea la cel mai apropiat număr întreg. Deoarece 0,10 este mai aproape de 0 decât de 1, se rotunjește la 0. După rotunjire și împărțire la 1,0 rezultatul este 0,0. Deci, puteți observa diferența dintre ieșirile cu clasa BigDecimal și funcția Maths.round.
Javapublic class Main { public static void main(String args[]) { double a = 1.0; double b = 0.10; double x = 9 * b; a = a - (x); /* We use Math.round() function to round the answer to closest long then we multiply and divide by 1.0 to to set the decimal places to 1 place (this can be done according to the requirements.*/ System.out.println('a = ' + Math.round(a*1.0)/1.0); } }
Ieșire:
0.0