BigDecimal división de regresar mal resultado para algunos cálculos

XtremeBaumer:

He leído algunas preguntas acerca de flaoting números de punto y sus matemáticas. Me parece que los problemas sólo ocurren a escalas mayores (es decir, 10 + decimales). Ahora mi problema ocurre a los 2 decimales y ya es bastante grande apagado en algunos casos:

Siguiente código:

System.out.println(
        String.format("%.2f", BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2).doubleValue()));
System.out.println(
        String.format("%.2f", BigDecimal.valueOf(2.41).divide(BigDecimal.valueOf(2.73), 2).doubleValue()));

genera esta salida respectivamente:

0.80
0.89

Si realizo los cálculos a mano (utilizando una fórmula de Google), consigo estos resultados:

0.72351421188
0.88278388278

durante los primeros cálculos de los resultados son muy grandes (~ 0,08 apagado) mientras que para el segundo su muy baja (~ 0,01 apagado).

¿Hay alguna explicación sensata de por qué Thie primer resultado es tan grande? O cualquier forma de obtener el resultado correcto usando BigDecimal?

Tenga en cuenta que

System.out.println(2.8/3.87);

En realidad devuelve el resultado correcto (,7235142118863048).

Tenga en cuenta también que el String.formatmaterial sólo se utiliza para comprobar si el resultado fue cambiado por lo que no es el caso. BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2).doubleValue()produce exactamente el mismo resultado.

Kevin Cruijssen:

El problema es que usted está utilizando el mal BigDecimal#dividepara su redondeo a 2 decimales. Estos son los argumentos disponibles para los BigDecimal#dividemétodos:

  • divide(BigDecimal divisor)
  • divide(BigDecimal divisor, int roundingMode)
  • divide(BigDecimal divisor, MathContext mc)
  • divide(BigDecimal divisor, RoundingMode roundingMode)
  • divide(BigDecimal divisor, int scale, int roundingMode)
  • divide(BigDecimal divisor, int scale, RoundingMode roundingMode)

Puesto que usted está usando una dividecon una BigDecimaly intargumento, por lo tanto, utiliza el divide(BigDecimal divisor, int roundingMode), donde su 2es el modo de redondeo y NO la escala. En este caso, 2es en realidad ROUND_CEILING, y la escala no se especifica.

En su lugar, usted tiene que utilizar el divide(BigDecimal divisor, int scale, int roundingMode)o divide(BigDecimal divisor, int scale, RoundingMode roundingMode). Así que cambiar sus llamadas a:

System.out.println(BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2, 
  BigDecimal.ROUND_HALF_UP));
System.out.println(BigDecimal.valueOf(2.41).divide(BigDecimal.valueOf(2.73), 2, 
  BigDecimal.ROUND_HALF_UP));

(Siéntase libre de utilizar un modo de redondeo distinta ROUND_HALF_UP.)

Pruébelo en línea.

No estoy seguro de qué escala se utiliza de forma predeterminada, pero el ROUND_CEILINGque ha especificado con las 2causadas a los problemas en sus cálculos.


En cuanto a los comentarios mencionados, hay tres formas posibles para crear la BigDecimalcon los valores especificados:

  • BigDecimal.valueOf(2.8)
  • new BigDecimal(2.8)
  • new BigDecimal("2.8")

El new BigDecimal(2.8)todavía da errores de punto flotante, por lo que aconsejaría a utilizar ya sea BigDecimal.valueOf(2.8)como ya lo hizo, o el constructor de String new BigDecimal("2.8").

Pruébelo en línea.

Todo esto es un poco irrelevante para sus problemas de redondeo sin embargo, ya que el uso correcto del dividemétodo dará los resultados correctos, independientemente de la BigDecimalinicialización que ha utilizado:

Pruébelo en línea.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=278848&siteId=1
Recomendado
Clasificación