L’aggiunta e la sottrazione di doppi stanno dando strani risultati

Quindi quando aggiungo o sottraggo in Java con Doubles, mi danno strani risultati. Eccotene alcune:

Se aggiungo 0.0 + 5.1 , mi dà 5.1 . È corretto.

Se aggiungo 5.1 + 0.1 , mi dà 5.199999999999 (il numero di ripetizioni 9 s potrebbe essere spento). È sbagliato.

Se sottraggo 4.8 - 0.4 , mi dà 4.39999999999995 (Anche in questo caso, i 9 s che si ripetono possono essere distriggersti). È sbagliato.

All’inizio pensavo che questo fosse solo il problema con l’aggiunta di doppi con valori decimali, ma mi sbagliavo. Il seguente ha funzionato bene:

 5.1 + 0.2 = 5.3 5.1 - 0.3 = 4.8 

Ora, il primo numero aggiunto è un doppio salvato come variabile, anche se la seconda variabile cattura il testo da un campo JTextField . Per esempio:

 //doubleNum = 5.1 RIGHT HERE //The textfield has only a "0.1" in it. doubleNum += Double.parseDouble(textField.getText()); //doubleNum = 5.199999999999999 

In Java, i valori double sono numeri in virgola mobile IEEE . A meno che non siano una potenza di 2 (o somme di potenze di 2, ad es. 1/8 + 1/4 = 3/8), non possono essere rappresentate esattamente, anche se hanno un’alta precisione. Alcune operazioni in virgola mobile comporteranno l’errore di arrotondamento presente in questi numeri in virgola mobile. Nei casi che hai descritto sopra, gli errori in virgola mobile sono diventati abbastanza significativi da apparire nell’output.

Non importa quale sia la fonte del numero, se sta analizzando una stringa da un JTextField o specificando un double letterale – il problema è ereditato dalla rappresentazione in virgola mobile.

soluzioni alternative:

  • Se sai che avrai solo tanti decimali, quindi utilizza l’aritmetica dei numeri interi, quindi converti in un decimale:

     (double) (51 + 1) / 10 (double) (48 - 4) / 10 
  • Usa BigDecimal

  • Se devi usare il double , puoi ridurre gli errori in virgola mobile con l’ algoritmo di sum di Kahan .

In Java, il doppio utilizza l’aritmetica in virgola mobile IEEE 754 (vedere questo articolo di Wikipedia), che è intrinsecamente impreciso. Usa BigDecimal per una perfetta precisione decimale. Per arrotondare la stampa, accettando la precisione “abbastanza buona”, usa printf("%.3f", x) .