logo

Arrotondamento degli errori in Java

Compattare molti numeri reali infiniti in un numero finito di bit richiede una rappresentazione approssimata. La maggior parte dei programmi memorizza il risultato dei calcoli con numeri interi a 32 o 64 bit al massimo. Dato un numero fisso di bit, la maggior parte dei calcoli con numeri reali produrrà quantità che non possono essere rappresentate esattamente utilizzando quel numero di bit. Pertanto il risultato di un calcolo in virgola mobile deve spesso essere arrotondato per rientrare nella sua rappresentazione finita. Questo errore di arrotondamento è una caratteristica del calcolo in virgola mobile. Pertanto, durante la gestione dei calcoli con numeri in virgola mobile (specialmente se i calcoli sono in termini di denaro), dobbiamo prestare attenzione agli errori di arrotondamento in un linguaggio di programmazione. Vediamo un esempio:

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


comando arp

Produzione:



x = 0.7999999999999999  
y = 0.8
false

Qui la risposta non è quella che ci aspettavamo, poiché l'arrotondamento effettuato dal compilatore Java.

Motivo dietro l'errore di arrotondamento

I tipi di dati Float e Double implementano la specifica IEEE in virgola mobile 754. Ciò significa che i numeri sono rappresentati in una forma come:

SIGN FRACTION * 2 ^ EXP 

0,15625 = (0,00101)2che nel formato a virgola mobile è rappresentato come: 1.01 * 2^-3
Non tutte le frazioni possono essere rappresentate esattamente come una frazione di una potenza di due. Come semplice esempio 0.1 = (0.000110011001100110011001100110011001100110011001100110011001… )2 e quindi non può essere memorizzato all'interno di una variabile a virgola mobile.

Un altro esempio:

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

Produzione:

x = 0.7999999999999999  
y = 0.8
false

Un altro esempio:

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

Produzione:

a = 0.09999999999999998

Come correggere gli errori di arrotondamento?

  • Arrotonda il risultato: La funzione Round() può essere utilizzata per ridurre al minimo gli effetti dell'imprecisione della memorizzazione aritmetica in virgola mobile. L'utente può arrotondare i numeri al numero di cifre decimali richiesto dal calcolo. Ad esempio, mentre lavori con la valuta probabilmente arrotonderesti a 2 cifre decimali.
  • Algoritmi e funzioni: Utilizza algoritmi numericamente stabili o progetta le tue funzioni per gestire tali casi. Puoi troncare/arrotondare le cifre di cui non sei sicuro che siano corrette (puoi anche calcolare la precisione numerica delle operazioni)
  • Classe BigDecimal: Puoi usare il java.math.BigDecimal classe progettata per darci precisione soprattutto in caso di grandi numeri frazionari. Il seguente programma mostra come eliminare l'errore:
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);  } } 


Produzione:

0.1

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

Turni aa 1 cifra decimale utilizzando la modalità di arrotondamento HALF_UP. Pertanto, l'utilizzo di BigDecimal fornisce un controllo più preciso sulle operazioni aritmetiche e di arrotondamento che possono essere particolarmente utili per i calcoli finanziari o altri casi in cui la precisione è fondamentale.

Nota importante:

Math.round arrotonda il valore all'intero più vicino. Poiché 0,10 è più vicino a 0 che a 1, viene arrotondato a 0. Dopo l'arrotondamento e la divisione per 1,0 il risultato è 0,0. Quindi puoi notare la differenza tra gli output con la classe BigDecimal e la funzione 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);  } } 

Produzione:

0.0