Empecé a usar Sonar recientemente en un proyecto, y tengo una regla PMD rota sobre el uso del constructor new BigDecimal(double val)
. Cuando leí la documentación de Java, encontré que el nuevo BigDecimal (double val) es algo impredecible y que debería usar new BigDecimal(String val)
, que es predecible.Imprevisibilidad del constructor BigDecimal (doble)
Esto es lo que dice javadoc para BigDecimal
public BigDecimal(double val)
:
Traduce un doble en un BigDecimal que es el decimal exacto representación del valor de punto flotante binario del doble. La escala del BigDecimal devuelto es el valor más pequeño, de modo que (10scale × val) es un número entero.
Notas:
Los resultados de este constructor puede ser algo impredecible. Uno podría suponer que escrito en Java
new BigDecimal(0.1)
crea unaBigDecimal
que es exactamente igual a 0,1 (un valor sin escala de 1, con una escala de 1), pero en realidad es igual a 0,1000000000000000055511151231257827021181583404541015625. Esto se debe a que 0.1 no se puede representar exactamente como un doble (o, para esa materia , como una fracción binaria de cualquier longitud finita). Por lo tanto, el valor que se transfiere al constructor no es exactamente igual a 0.1, a pesar de las apariencias.La cadena de constructor, por el contrario, es perfectamente previsible: escribir
new BigDecimal("0.1")
crea unaBigDecimal
que es exactamente igual a 0,1, como era de esperar. Por lo tanto, generalmente se recomienda que el constructor de cadenas se use con preferencia a este .Cuando se debe utilizar un doble como fuente para
BigDecimal
, tenga en cuenta que este constructor proporciona una conversión exacta; no da el resultado mismo que convertir el doble en una Cadena usando el métodoDouble.toString(double)
y luego usando el constructorBigDecimal(String)
. Para obtener ese resultado, use el método estáticovalueOf(double)
.
¿Por qué este constructor realmente existe? No es new BigDecimal(String val)
suficiente para ese asunto? ¿Cuándo debería usar el constructor new BigDecimal(double val)
?
Entonces, si estoy trabajando con un valor doble, y lo cambio a una cadena, entonces a bigdecimal, pierdo precisión? Usando por ejemplo Double.toString? – gdfbarbosa
Lo haces, porque Double.toString() es una bestia complicada. Realmente no devuelve el valor exacto del doble que le está pasando. en su lugar, devuelve la cadena más corta que, una vez analizada, se convertirá exactamente en el valor doble especificado. Eso es un poco confuso, pero básicamente, significa que si Double.toString (0.100000000000000005551115123) es "0.1", entonces se garantiza que Double.parseDouble ("0.1") también sea 0.100000000000000005551115123. Y esta cosa complicada es por qué pierde precisión, pero nunca se ve así cuando imprime su doble valor en la consola. – LordOfThePigs
La pérdida de precisión ocurre porque el nuevo BigDecimal (Double.toString (0.1d)), realmente representa el valor "0.1" exacto, aunque 0.1d no es realmente igual a 0.1 (ya que realmente es 0.100000000000000005551115123). En algunos casos, ese comportamiento podría ser deseable, pero en algunos otros, es una pérdida de precisión inaceptable. – LordOfThePigs