2012-08-31 13 views
8

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 BigDecimalpublic 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 una BigDecimal 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 una BigDecimal 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étodo Double.toString(double) y luego usando el constructor BigDecimal(String). Para obtener ese resultado, use el método estático valueOf(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)?

Respuesta

5

¿Por qué este constructor realmente existe?

Convierte el valor real representado de double en un BigDecimal. El objetivo de BigDecimal es dar la mayor precisión posible y eso es lo que hace este constructor.

Si usted quiere tomar el valor que se obtendría con una pequeña cantidad de redondeo del Double.toString(double) usos puede utilizar

System.out.println(BigDecimal.valueOf(0.1)); 

impresiones

0.1 

¿Cuándo debo utilizar el nuevo BigDecimal (doble val) constructor

Cuando quieras saber el valor double realmente representa. Puede aplicar su propio redondeo según sea necesario.

Cuando usa double siempre debe aplicar un redondeo razonable. Pero, si lo hiciste, es posible que no necesites BigDecimal. ;)

2

Porque si ya comenzó con un valor de double como datos, ya ha perdido esa precisión. Así que no tenerlo te obligaría a convertirlo a String para BigDecimal para convertirlo de nuevo.

Y también, quizás a veces solo necesite valor de.

+0

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

+3

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

+1

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

1

Utilizaría el constructor doble cuando los datos con los que desea trabajar ya existen como un valor doble. Tener que convertirlo en una cadena antes de convertirlo a BigDecimal sería un desperdicio en ese caso.

1

When should I use the new BigDecimal(double val) constructor?

Preferiblemente - ninguna parte.

Si está dispuesto a jugar con BigDecimales, usar el constructor con doble significa perder todos los beneficios de la presentación del número exacto.

Why does this constructor really exists?

Porque a veces sólo tiene doble, que desea traducir a BigDecimal. Obligar a utilizar .toString() entre medias sería simplemente una tontería;)

0

quería comentar, pero no puedo imaginar cómo colocar "código" en un comentario, así que la respuesta:

double val = 0.1; // this is not 0.1, but an approximination as pointed out in other answers. BigDecimal biggy = new BigDecimal(val); // this variable conatains the "same" value as val does, however it is not 0.1, but as pointed out in other answers: 0.100000000000000005551115123

Así, en el caso en esta lista, donde se tiene plena control sobre el código fuente, se debe escribir el val como 'cadena val = '0.1''

Sin embargo, el contructor BigDecimal(double val) es muy útil en caso de que lea dobles binarios de un archivo. Obviamente, usted querrá en casi todos los casos BigDecimals que sean exactamente los mismos que los "dobles"

0

Imprevisibles? Estoy en desacuerdo.

final double before = 0.1; 
BigDecimal bd = new BigDecimal(before); 
double after = bd.doubleValue(); 
assert before == after; 

clave para comprender:

assert 0.1 == 0.1000000000000000055511151231257827021181583404541015625; 

Si realmente quería decir "0.1", entonces sí, utilice el constructor String =) Pero si usted tiene un double ya, después de que el doble no es "0,1 ".

el Javadoc usted ha citado dice:

Cuando un doble debe ser utilizado como una fuente de un BigDecimal, tenga en cuenta que este constructor proporciona una conversión exacta ;

No veo cómo una conversión exacta es "impredecible" y estoy a favor de eliminar la palabra "imprescindible" de esta cita.

Al final del día, ambos constructores funcionan como se esperaba. Si tiene String "0.1", BigDecimal (String) convierte este valor exactamente. Si tiene un doble 0.1, entonces BigDecimal (doble) convierte este valor exactamente.