2011-01-04 22 views

risposta

647

Dalle Java 5 documenti (Java 8 documenti here):

Quando un oggetto MathContext viene fornito con una regolazione di precisione di 0 (per esempio , MathContext.UNLIMITED), le operazioni aritmetiche sono esatte, come sono i metodi aritmetici che non accettano alcun oggetto MathContext. (Questa è l'unica comportamento che era supportato in versioni precedenti a 5.)

Come corollario di calcolare il risultato esatto, la modalità di arrotondamento di un oggetto MathContext con un ambiente precisione di 0 non viene utilizzato e pertanto irrilevante. In il caso di divisione, il quoziente esatto potrebbe avere un'espansione decimale infinitamente lunga ; ad esempio, 1 diviso per 3.

Se il quoziente ha un'espansione decimale non terminante e l'operazione viene specificata per restituire un risultato esatto, viene generata un'eccezione ArithmeticException. In caso contrario, viene restituito il risultato esatto della divisione, come fatto per le altre operazioni .

Per risolvere, è necessario fare qualcosa di simile:

a.divide(b, 2, RoundingMode.HALF_UP) 

where 2 is precision and RoundingMode.HALF_UP is rounding mode 

Maggiori dettagli: http://jaydeepm.wordpress.com/2009/06/04/bigdecimal-and-non-terminating-decimal-expansion-error/

+2

Non penso che ha bisogno del 'toPlainString'. –

+2

questo funziona anche per errore jasper grazie http://community.jaspersoft.com/questions/528968/help-please-adding-two-double-values#comment-807628 – shareef

+15

2 NON è 'precisione'; è 'scala'. Vedere http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#divide%28java.math.BigDecimal,%20int,%20java.math.RoundingMode%29 –

68

perché non sei specificando una precisione e una modalità di arrotondamento. BigDecimal si lamenta del fatto che potrebbe utilizzare 10, 20, 5000 o cifre decimali a infinito e non sarebbe comunque in grado di fornire una rappresentazione esatta del numero. Quindi, invece di darti un BigDecimal errato, ti sta solo fischiando.

Tuttavia, se fornisci un RoundingMode e una precisione, allora sarà in grado di convertire (ad esempio, da 1.333333333 a infinito a qualcosa come 1.3333 ... ma tu come programmatore devi dire quale precisione tu sia " re 'soddisfatti'.

5

Ho avuto questo stesso problema, perché la mia riga di codice è:

txtTotalInvoice.setText(var1.divide(var2).doubleValue() + ""); 

cambio di questo, la lettura precedente risposta, perché ero non scrivere la precisione decimale:

txtTotalInvoice.setText(var1.divide(var2,4, RoundingMode.HALF_UP).doubleValue() + ""); 

4 è decimale Precion

E RoundingMode sono costanti Enum, è possibile scegliere qualsiasi di questo UP, DOWN, CEILING, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP

In questo caso HALF_UP, avrete questo risultato:

2.4 = 2 
2.5 = 3 
2.7 = 3 

È possibile controllare le informazioni RoundingMode qui : http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/

10

Per risolvere un problema di questo tipo ho utilizzato il codice sottostante

a.divide(b, 2, RoundingMode.HALF_EVEN) 

2 è precisione. Ora il problema è stato risolto.

+3

in aggiunta al codice, dovrebbero essere fornite alcune spiegazioni. –

+6

2 NON è 'precisione'; è 'scala'. Vedere http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#divide%28java.math.BigDecimal,%20int,%20java.math.RoundingMode%29 –

+1

RoundingMode. HALF_EVEN è consigliato per le applicazioni finanziarie. Questo è ciò che viene utilizzato nel settore bancario – ACV

1

risposta per BigDecimal throws ArithmeticException

public static void main(String[] args) { 
     int age = 30; 
     BigDecimal retireMentFund = new BigDecimal("10000.00"); 
     retireMentFund.setScale(2,BigDecimal.ROUND_HALF_UP); 
     BigDecimal yearsInRetirement = new BigDecimal("20.00"); 
     String name = " Dennis"; 
     for (int i = age; i <=65; i++){ 
      recalculate(retireMentFund,new BigDecimal("0.10")); 
     } 
     BigDecimal monthlyPension = retireMentFund.divide(
       yearsInRetirement.divide(new BigDecimal("12"), new MathContext(2, RoundingMode.CEILING)), new MathContext(2, RoundingMode.CEILING));  
     System.out.println(name+ " will have £" + monthlyPension +" per month for retirement"); 
    } 
public static void recalculate (BigDecimal fundAmount, BigDecimal rate){ 
     fundAmount.multiply(rate.add(new BigDecimal("1.00"))); 
    } 

Aggiungi oggetto MathContext nella vostra chiamata di metodo divide e regolare la precisione e la modalità di arrotondamento. Questo dovrebbe risolvere il tuo problema

0

È perché il Bigdecimal non ha perso, e se dividi 1/3 per esempio, si tradurrà in un decimale ripetuto all'infinito. 0.33333333 ... in teoria se si moltiplica di nuovo, si ottiene il risultato esatto. Ma un numero infinito genererà lo stack sul flusso e in questo caso verrà lanciata l'eccezione.

La mia soluzione:

try { 
    result = n1.divide(n2); 
} catch (ArithmeticException e){ 
    Log.d("Error bigdecimal", e.toString()); 
    result = (n1.doubleValue()/n2.doubleValue()); 
}; 

in questo caso il risultato non sarà tagliato arrotondando

+2

Questo è un "gambiarra". Si prega di utilizzare la soluzione con RoundingMode. –