2012-08-29 20 views
6

posible duplicado:
ArithmeticException thrown during BigDecimal.divideBigDecimals resultados en ArithmeticException

Esto se traduce en ArithmeticException: http://ideone.com/RXeZw

Proporcionar una escala y modo de redondeo me va a dar un resultado erróneo. Este ejemplo debería dar como resultado 50.03%. ¿Cómo redondear esto correctamente?

Para facilitar la referencia, este es el código:

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

Respuesta

9

BigDecimal.divide(BigDecimal divisor) lanza una ArithmeticException si el resultado no se puede representar con exactitud.
Deberá utilizar proporcionar un MathContext o un RoundingMode que indique cómo desea manejar esto. Por ejemplo:

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

obras e impresiones

50.0250125062531265632816408204102100 

Además, tenga en cuenta el uso de la BigDecimal(String) constructor para evitar problemas cuando se crea utilizando un BigDecimaldouble literal.

4

Debe utilizar un MathContext como su división como un número infinito de decimales:

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

Sin embargo, que imprime 50.025 ...

Esto imprimiría 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

Las operaciones de BigDecimal siempre intentan calcular el resultado exacto. Prueba esto.

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

similares a la respuesta de @ Keppil

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

impresiones

50.03% 

que no van a obtener 49,98% ya que esta no es la respuesta a su ecuación.

+0

sí, me confundí con todos estos números :-) – dtrunk

+0

@dtrunk Me parece que usar 'double' es menos confuso. ;) –

+0

No puedo usar el doble ya que causaría tantos cambios en el código – dtrunk

2

Desde el Javadoc:

En el caso de la división, el cociente exacto podría tener una expansión decimal de longitud infinita; por ejemplo, 1 dividido por 3. Si el cociente tiene una expansión decimal no determinante y la operación se especifica para devolver un resultado exacto, se lanza una ArithmeticException.

La solución es proporcionar un MathContext a la división, por ejemplo MathContext.DECIMAL128.Si quieres redondeo hace de la manera convencional (redondeo mitades de arriba en vez de al número par más cercano), utilice MathContext(int precision)

También debe crear sus BigDecimal s con String argumentos en lugar de double argumentos, debido a que la última provoca pérdida de precisión .