2012-08-29 7 views
6

Eventuali duplicati:
ArithmeticException thrown during BigDecimal.dividedivisorie BigDecimals risultati in ArithmeticException

Questo si traduce in ArithmeticException: http://ideone.com/RXeZw

Fornire una scala e la modalità di arrotondamento mi darà il risultato sbagliato. Questo esempio dovrebbe produrre il 50,03%. Come arrotondare correttamente?

Per riferimento più semplice, questo è il codice:

BigDecimal priceDiff = BigDecimal.ONE 
    .subtract(new BigDecimal(9.99) 
    .divide(new BigDecimal(19.99))) 
    .multiply(new BigDecimal(100)); 
System.out.println(priceDiff.toPlainString()); 

risposta

9

BigDecimal.divide(BigDecimal divisor) genera ArithmeticException se il risultato non può essere esattamente rappresentato.
Dovrai usare fornire un MathContext o un RoundingMode che dice come vuoi gestirlo. Per esempio:

public class Test { 
    public static void main(String[] args) throws java.lang.Exception { 
     BigDecimal priceDiff = BigDecimal.ONE.subtract(new BigDecimal("9.99").divide(new BigDecimal("19.99"), MathContext.DECIMAL128)) 
              .multiply(new BigDecimal(100)); 
     System.out.println(priceDiff.toPlainString()); 
    } 
} 

opere e stampe

50.0250125062531265632816408204102100 

Inoltre, nota l'uso del BigDecimal(String) constructor per evitare problemi quando si crea BigDecimal utilizzando un double letterale.

4

È necessario utilizzare un MathContext come la divisione di un numero infinito di decimali:

BigDecimal priceDiff = BigDecimal.ONE 
      .subtract(new BigDecimal(9.99) 
      .divide(new BigDecimal(19.99), new MathContext(10, RoundingMode.UP))) 
      .multiply(new BigDecimal(100)); 
    System.out.println(priceDiff.toPlainString()); 

Tuttavia, che consente di stampare 50,025 ...

Questa sarebbe la stampa 49.98:

BigDecimal priceDiff = new BigDecimal(9.99) 
     .divide(new BigDecimal(19.99), new MathContext(10, RoundingMode.UP)) 
     .multiply(new BigDecimal(100), new MathContext(4, RoundingMode.UP)); 
System.out.println(priceDiff.toPlainString()); 
1

Le operazioni BigDecimal cercano sempre di calcolare il risultato esatto. Prova questo.

BigDecimal priceDiff = BigDecimal.ONE 
       .subtract(new BigDecimal(9.99) 
         .divide(new BigDecimal(19.99),RoundingMode.HALF_UP)) 
       .multiply(new BigDecimal(100)); 
     System.out.println(priceDiff.toPlainString()); 
1

Simile a @ di Keppil risposta

double d = (1 - 9.99/19.99) * 100; 
System.out.printf("%.2f%%%n", d); 

stampe

50.03% 

non si ha intenzione di ottenere 49.98% come questa non è la risposta alla tua equazione.

+0

sì, mi sono solo confuso su tutti questi numeri :-) – dtrunk

+0

@dtrunk trovo usando 'double' meno confuso. ;) –

+0

Non riesco a usare il doppio in quanto causerebbe così tante modifiche nel codice – dtrunk

2

Dal Javadoc:

Nel caso della divisione, il quoziente esatto potrebbe avere un'espansione decimale infinitamente lungo; ad esempio, 1 diviso per 3. Se il quoziente presenta un'espansione decimale non terminata e l'operazione viene specificata per restituire un risultato esatto, viene generata un'eccezione ArithmeticException.

La soluzione è quello di fornire un MathContext alla divisione, per esempio MathContext.DECIMAL128.Se si desidera arrotondamento fatto nel modo convenzionale (arrotondando metà fino piuttosto che al numero pari più vicino), utilizzare MathContext(int precision)

Si dovrebbe anche essere la creazione di vostri BigDecimal s con String argomenti piuttosto che double argomenti, perché la perdita ultime cause di precisione .

Problemi correlati