logo

A Java hibák kerekítése

Sok végtelen valós szám véges számú bitre történő tömörítése közelítő ábrázolást igényel. A legtöbb program az egész számítások eredményét legfeljebb 32 vagy 64 biten tárolja. Bármilyen rögzített bitszám mellett a legtöbb valós számokkal végzett számítás olyan mennyiségeket eredményez, amelyeket nem lehet pontosan ábrázolni ennyi bittel. Ezért a lebegőpontos számítás eredményét gyakran le kell kerekíteni, hogy visszaférjen a véges reprezentációjába. Ez a kerekítési hiba a lebegőpontos számítások jellemző tulajdonsága. Ezért a lebegőpontos számokkal végzett számítások kezelésekor (különösen, ha a számításokat pénzben értjük) ügyelnünk kell a kerekítési hibákra egy programozási nyelvben. Lássunk egy példát:

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


dinamikus tömb java-ban

Kimenet:



x = 0.7999999999999999  
y = 0.8
false

Itt a válasz nem az, amit vártunk, a java fordító által végzett kerekítés miatt.

A kerekítési hiba oka

A lebegő és a kettős adattípusok az IEEE lebegőpontos 754 specifikációt valósítják meg. Ez azt jelenti, hogy a számok a következő formában vannak ábrázolva:

SIGN FRACTION * 2 ^ EXP 

0,15625 = (0,00101)2amely lebegőpontos formátumban a következőképpen jelenik meg: 1.01 * 2^-3
Nem minden tört ábrázolható pontosan a kettő hatványának törtrészeként. Egyszerű példaként 0,1 = (0,000110011001100110011001100110011001100110011001100110011001…)2 és így nem tárolható lebegőpontos változón belül.

Egy másik példa:

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

Kimenet:

x = 0.7999999999999999  
y = 0.8
false

Egy másik példa:

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

Kimenet:

a = 0.09999999999999998

Hogyan lehet kijavítani a kerekítési hibákat?

  • Az eredmény kerekítése: A Round() függvény használható a lebegőpontos aritmetikai tárolási pontatlanság hatásainak minimalizálására. A felhasználó a számokat a számításhoz szükséges tizedesjegyekre kerekítheti. Például, ha pénznemekkel dolgozik, valószínűleg 2 tizedesjegyre kerekít.
  • Algoritmusok és funkciók: Használjon numerikusan stabil algoritmusokat, vagy tervezze meg saját függvényeit az ilyen esetek kezelésére. Levághatja/kerekítheti azokat a számjegyeket, amelyek helyességében nem biztos, hogy helyesek (a műveletek numerikus pontosságát is kiszámíthatja)
  • BigDecimális osztály: Használhatja a java.math.BigDecimal osztály, amelyet arra terveztek, hogy pontosságot adjon nekünk, különösen nagy törtszámok esetén. A következő program megmutatja, hogyan lehet eltávolítani a hibát:
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);  } } 


Kimenet:

0.1

Itt a = a.setScale(1 RoundingMode.HALF_UP);

Kerekek a1 tizedesjegyig a HALF_UP kerekítési mód használatával. Így a BigDecimal használata pontosabb ellenőrzést biztosít az aritmetikai és kerekítési műveletek felett, ami különösen hasznos lehet pénzügyi számításoknál vagy más olyan esetekben, ahol a pontosság kulcsfontosságú.

Fontos megjegyzés:

A Math.round az értéket a legközelebbi egész számra kerekíti. Mivel a 0,10 közelebb van a 0-hoz, mint az 1-hez, akkor 0-ra kerekítjük. A kerekítés és az 1,0-val való osztás után az eredmény 0,0. Így észreveheti a különbséget a BigDecimal osztály és a Maths.round függvény kimenetei között.

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

Kimenet:

0.0