2013-03-28 13 views
7

Qualcuno può spiegare perché sulla Terra queste "stesse" espressioni restituiscono valori diversi?Android: errore di arrotondamento java. Non capisco perché?

(new BigDecimal(String.valueOf(131.7d))).multiply(new BigDecimal(String.valueOf(0.95d))).doubleValue() = 125.115 

(new BigDecimal(    131.7d)).multiply(new BigDecimal(    0.95d)).doubleValue() = 125.11499999999998 

Che cosa fa BigDecimal in modo diverso tra di loro?

+1

per chi ha il diritto di chiudere come duplicato, le domande sono simili ma non sono duplicati. – Woot4Moo

risposta

5

Se leggi la documentazione dell'API, troverai che il String.valueOf(dobule) utilizza Double.toString(double) per formattare il valore. Non è forse ovvio, ma Double.toString(double) arrotonda il valore, prima di formattare come una stringa:

Quante cifre devono essere stampate per la parte frazionaria di m o di un? Ci deve essere almeno una cifra per rappresentare la parte frazionaria, e oltre a tante quante, ma solo quante più cifre necessarie per distinguere in modo univoco il valore dell'argomento dai valori adiacenti del tipo doppio. Cioè, supponiamo che x sia l'esatto valore matematico rappresentato dalla rappresentazione decimale prodotta da questo metodo per un argomento finito diverso da zero d. Quindi d deve essere il doppio valore più prossimo a ; o se due valori doppi sono ugualmente vicino a x, allora d deve essere uno di loro e il bit meno significativo del significando di D deve essere 0.

Il risultato di ciò è che String.valueOf(131.7d) restituirà la stringa "131.7" anche se il valore esatto dell'argomento è 131.69999999999998863131622783839702606201171875. La ragione di ciò è che le frazioni decimali non possono sempre essere rappresentate esattamente usando le frazioni binarie (come quelle usate con i float e i doppi).

Quindi, il nuovo new BigDecimal(String.valueOf(131.7)) creerà un BigDecimal con il valore esatto 131.7. new BigDecimal(131.7) creerà un BigDecimal con il valore esatto 131.69999999999998863131622783839702606201171875.

+0

Questo spiega il punto. Grazie! – Christian

6

Se si guarda al API documentation:

BigDecimal(double val) 
      Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value. 

contro

BigDecimal(String val) 
      Translates the string representation of a BigDecimal into a BigDecimal. 

Questi sono, infatti, non è la stessa cosa. Nel costruttore double utilizza un numero in virgola mobile (che è intrinsecamente impreciso). Nel costruttore String sta prendendo il valore esatto che hai fornito e non facendo una conversione in virgola mobile. Quindi questo significa che i costruttori sopra non sono le "stesse" espressioni

+0

Quindi, non c'è altro modo per ottenere il valore "corretto" di questo calcolo (131.7 * 0.95 = 125.115) del valore convertito in stringa prima di passarlo a BigDecimal? Questo mi sembra così strano! – Christian

+0

Non capisco perché 2 costruttori con gli stessi valori di input restituiscano 2 risultati diversi. Se Double.valueOf (String.valueOf (131.7d)) == 131.7d, perché BigDecimal dovrebbe restituire valori diversi? Non ha alcun senso per me! – Christian

+2

Hmm, in realtà non stai rispondendo alla domanda di Christian, visto che inizia con 131.7d e 0.95d in entrambi i casi. La ragione della differenza che osserva non è dovuta ai diversi costruttori BigDecimal, ma che String.valueOf (dobule) arrotonda indirettamente l'argomento prima di convertirsi in una stringa e non restituisce una stringa con il valore esatto dell'argomento. – jarnbjo