2011-11-10 13 views
5

La fuente de round en apache commons se ve así:¿Por qué tenemos que convertir el doble en una cadena, antes de que podamos convertirlo en un BigDecimal?

public static double round(double x, int scale, int roundingMethod) { 
    try { 
     return (new java.math.BigDecimal(Double.toString(x)).setScale(scale, roundingMethod)).doubleValue(); 
    } catch (NumberFormatException ex) { 
     if (Double.isInfinite(x)) { 
      return x; 
     } else { 
      return Double.NaN; 
     } 
    } 
} 

Me preguntaba, al crear la BigDecimal ¿por qué eligieron para convertir el doble a una cadena (usando el Double.toString) en lugar de simplemente utilizar el doble ¿sí mismo?

En otras palabras, ¿qué pasa con esto? :

public static double round(double x, int scale, int roundingMethod) { 
    try { 
     return (new java.math.BigDecimal(x).setScale(scale, roundingMethod)).doubleValue(); 
    } catch (NumberFormatException ex) { 
     if (Double.isInfinite(x)) { 
      return x; 
     } else { 
      return Double.NaN; 
     } 
    } 
} 

Respuesta

7

Es porque el resultado del constructor BigDecimal(double) es impredecible como se menciona en javadoc.

Uno podría suponer que escribir un nuevo BigDecimal (0.1) en Java crea un 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

El constructor String, por otro lado, es perfectamente previsible: escribir nuevo BigDecimal ("0,1") crea un BigDecimal que es exactamente igual a 0.1, como uno esperaría. Por lo tanto, generalmente se recomienda que el constructor de cadenas se use con preferencia a este .

caso de prueba:

System.out.println(java.math.BigDecimal.valueOf(0.1).toString()); 
System.out.println(new java.math.BigDecimal(0.1).toString()); 
+0

@@ Fatal Thanks! – Pacerier

1

No tiene que convertir a Cadena.
usa el método estático BigDecimal.valueOf(double val):

para utilizar en su código:

... 
return (BigDecimal.valueOf(x).setScale(scale, roundingMethod)).doubleValue(); 
.... 
+0

Los documentos escribieron que 'BigDecimal.valueOf (x)' es equivalente a hacer 'new java.math.BigDecimal (Double.toString (x))', así que básicamente me preguntaba cuál es la diferencia entre 'new java.math .BigDecimal (Double.toString (x)) 'y' new java.math.BigDecimal (x) '? – Pacerier

+0

Si así es como se implementa, que así sea. Eso puede cambiar en futuros JDK. Concéntrese en la API: la implementación no debería preocuparlo (a menos que, por supuesto, afecte sus decisiones de diseño, lo que probablemente significaría que su diseño tiene algún defecto) – Bohemian

4

De la documentación here para el constructor BigDecimal(String val):

Nota: Para los valores distintos de float y double NaN e ± Infinity, este constructor es compatible con los valores devueltos por Float.toString (float) y Double.toString (double). Esto es generalmente , la forma preferida de convertir un flotante o doble en un BigDecimal, como no sufre de la imprevisibilidad del constructor BigDecimal (doble) .

+0

Y si realmente desea ver la diferencia, recuerde que la fuente de BigDecimal es disponible. http://www.docjar.com/html/api/java/math/BigDecimal.java.html – madth3

1

Me parece que la clave está en esta declaración:

BigDecimal (doble val)
Traduce un doble en un BigDecimal que es la representación decimal exacta del binario de coma flotante de doble valor.

frente

BigDecimal (String val)
traduce la representación de cadena de un BigDecimal en un BigDecimal.

Al ir primero a String, ve el doble como un BigDecimal, pero si lo construye directamente desde un doble, está trabajando con la representación a nivel de bit, y estoy dispuesto a apostar que obtener una respuesta sutilmente diferente. Recuerde que los valores de punto flotante se representan usando una sección de los 64 bits para la parte completa, y una sección para la parte de fracción, y una sección para representar un exponente (en la base 2): todo es muy esotérico, difiere de máquina a máquina, y creo que la única definición formal se encuentra en el maldito Necronomicon.

Actualización: ¿Qué Borodin dicho.

1

Sin embargo, me encontré con una pregunta:

System.out.println(java.math.BigDecimal.valueOf(0.1000000000000000055511151231257827021181583404541015625).toString()); 

se imprimirá 0,1.

Creo que la clave es java.lang.Double.toString (doble d). Cuando la entrada 0,1 (En Java, el valor exacto es 0.1000000000000000055511151231257827021181583404541015625), la función se reducirá la cola y tenemos 0,1. Sin embargo. si ingresamos 0.1000000000000000055511151231257827021181583404541015625, siempre cae la cola y también obtenemos 0.1 lo que está en contra de nuestras expectativas.

lo tanto, debemos ser conscientes de nuestras necesidades para elegir java.math.BigDecimal.valueOf (doble val) o java.math.BigDecimal.BigDecimal (doble val).

+0

sí, si queríamos que eso funcione, teníamos que 'nuevo java.math.BigDecimal (" 0.1000000000000000055511151231257827021181583404541015625 ")' – Pacerier

Cuestiones relacionadas