logo

Zaokrúhľovanie chýb v jazyku Java

Zhutnenie mnohých nekonečných reálnych čísel do konečného počtu bitov vyžaduje približnú reprezentáciu. Väčšina programov ukladá výsledok celočíselných výpočtov maximálne 32 alebo 64 bitov. Pri akomkoľvek pevnom počte bitov väčšina výpočtov s reálnymi číslami vytvorí množstvá, ktoré nemožno presne reprezentovať pomocou takého počtu bitov. Preto musí byť výsledok výpočtu s pohyblivou rádovou čiarkou často zaokrúhlený, aby sa zmestil späť do jeho konečnej reprezentácie. Táto chyba zaokrúhľovania je charakteristickým znakom výpočtu s pohyblivou rádovou čiarkou. Preto pri spracovávaní výpočtov v číslach s pohyblivou rádovou čiarkou (najmä ak ide o výpočty v peniazoch) sa musíme postarať o zaokrúhľovacie chyby v programovacom jazyku. Pozrime sa na príklad:

Java
public 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);  } } 


stránky java servera

výstup:



x = 0.7999999999999999  
y = 0.8
false

Tu odpoveď nie je to, čo sme očakávali, dôvodom je zaokrúhlenie vykonané kompilátorom java.

Dôvod chyby zaokrúhlenia

Dátové typy Float a Double implementujú špecifikáciu IEEE s pohyblivou rádovou čiarkou 754. To znamená, že čísla sú reprezentované vo forme ako:

SIGN FRACTION * 2 ^ EXP 

0,15625 = (0,00101)2ktorý je vo formáte s pohyblivou rádovou čiarkou reprezentovaný ako: 1,01 * 2^-3
Nie všetky zlomky môžu byť vyjadrené presne ako zlomok mocniny dvoch. Ako jednoduchý príklad 0,1 = (0,000110011001100110011001100110011001100110011001100110011001…)2 a preto ich nemožno uložiť do premennej s pohyblivou rádovou čiarkou.

Ďalší príklad:

java
public 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);  } } 

výstup:

x = 0.7999999999999999  
y = 0.8
false

Ďalší príklad:

Java
public 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);  } } 

výstup:

a = 0.09999999999999998

Ako opraviť chyby pri zaokrúhľovaní?

  • Výsledok zaokrúhlite: Funkciu Round() možno použiť na minimalizáciu akýchkoľvek účinkov nepresnosti aritmetického ukladania s pohyblivou rádovou čiarkou. Používateľ môže zaokrúhliť čísla na počet desatinných miest, ktorý si vyžaduje výpočet. Napríklad pri práci s menou by ste pravdepodobne zaokrúhlili na 2 desatinné miesta.
  • Algoritmy a funkcie: Na zvládnutie takýchto prípadov použite numericky stabilné algoritmy alebo navrhnite svoje vlastné funkcie. Môžete skrátiť/zaokrúhliť číslice, o ktorých si nie ste istí, či sú správne (môžete vypočítať aj číselnú presnosť operácií)
  • Trieda BigDecimal: Môžete použiť java.math.BigDecimal triedy, ktorá je navrhnutá tak, aby nám poskytla presnosť najmä v prípade veľkých zlomkových čísel. Nasledujúci program ukazuje, ako možno chybu odstrániť:
Java
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);  } } 


výstup:

0.1

Tu a = a.setScale(1 Režim zaokrúhľovania.HALF_UP);

Kola ana 1 desatinné miesto pomocou režimu zaokrúhľovania HALF_UP. Takže použitie BigDecimal poskytuje presnejšiu kontrolu nad aritmetickými a zaokrúhľovacími operáciami, ktoré môžu byť obzvlášť užitočné pri finančných výpočtoch alebo iných prípadoch, kde je presnosť rozhodujúca.

Dôležitá poznámka:

Math.round zaokrúhli hodnotu na najbližšie celé číslo. Keďže 0,10 je bližšie k 0 ako k 1, zaokrúhli sa na 0. Po zaokrúhlení a vydelení 1,0 je výsledok 0,0. Môžete si teda všimnúť rozdiel medzi výstupmi s triedou BigDecimal a funkciou Maths.round.

Java
public 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);  } } 

výstup:

0.0