2012-09-12 65 views
38

En Java, quiero tomar un doble valor y convertirlo a BigDecimal e imprimir su valor String con una cierta precisión.Convertir doble a BigDecimal y establecer BigDecimal Precision

import java.math.BigDecimal; 
public class Main { 
    public static void main(String[] args) { 
     double d=-.00012; 
     System.out.println(d+""); //This prints -1.2E-4 

     double c=47.48000; 
     BigDecimal b = new BigDecimal(c); 
     System.out.println(b.toString()); 
     //This prints 47.47999999999999687361196265555918216705322265625 
    } 
} 

Imprime esta cosa enorme:

47,47999999999999687361196265555918216705322265625

y no

47,48

La razón por la que estoy haciendo la conversión BigDecimal es a veces el doble valor que contiene una gran cantidad de decimales (es decir -.000012) y al convertir el doble en una cadena producirá la notación científica -1.2E-4. Quiero almacenar el valor de cadena en notación no científica.

Quiero que BigDecimal siempre tenga dos unidades de precisión como esta: "47.48". ¿Puede BigDecimal restringir la precisión en la conversión a cadena?

+1

Nota: BigDecimal también utilizará a veces la notación científica (creo que para la serie <10^-6) – assylias

Respuesta

36

Imprime 47.48000 si utiliza otra MathContext:

BigDecimal b = new BigDecimal(d, MathContext.DECIMAL64); 

Sólo tiene que elegir el marco que necesita.

+12

Usando el doble constructor no es recomendable. – assylias

+1

http://stackoverflow.com/questions/1056722/why-is-the-bigdecimaldouble-d-construction-still-around –

+14

BigDecimal b = BigDecimal.valueOf (d); – rvazquezglez

15

Quiere probar String.format("%f", d), que imprimirá su doble en notación decimal. No use BigDecimal en absoluto.

cuanto a la cuestión de precisión: Usted está almacenando primera 47.48 en el double c, a continuación, hacer un nuevo BigDecimal de ese double. La pérdida de precisión está en la asignación a c. Puede hacer

BigDecimal b = new BigDecimal("47.48") 

para evitar perder cualquier precisión.

+1

+1 uno debería (casi) nunca usar el constructor doble. – assylias

5

Está imprimiendo el valor real y exacto de double.

Double.toString(), que convierte a double s String s, hace no de impresión el valor decimal exacto de la entrada - si x es su doble valor, imprime exactamente suficientes dígitos que x es el más cercano al valor double imprimió

El punto es que no es tal double como 47.48 exactamente. Dobla los valores almacenados como fracciones binarias, no como decimales, por lo que no puede almacenar valores decimales exactos. (Para eso sirve BigDecimal)

3

La sintaxis String.format nos ayuda a convertir dobles y BigDecimales en cadenas de cualquier precisión.

Este código Java:

double dennis = 0.00000008880000d; 
System.out.println(dennis); 
System.out.println(String.format("%.7f", dennis)); 
System.out.println(String.format("%.9f", new BigDecimal(dennis))); 
System.out.println(String.format("%.19f", new BigDecimal(dennis))); 

Lienzo:

8.88E-8 
0.0000001 
0.000000089 
0.0000000888000000000 
63

La razón de tal comportamiento es que la cadena que se imprime es el valor exacto - probablemente no es lo que esperaba, pero eso es el valor real almacenado en la memoria; es solo una limitación de la representación en coma flotante.

De acuerdo con javadoc, BigDecimal (doble val) el comportamiento del constructor puede ser inesperado si no se tiene en cuenta esta limitación:

Los resultados de este constructor puede ser algo impredecible. Uno podría suponer que escribir 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. 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.

Así, en su caso, en lugar de utilizar

double val = 77.48; 
new BigDecimal(val); 

uso

BigDecimal.valueOf(val); 

valor que se devuelve por BigDecimal.valueOf es igual a la que resulta de la invocación de Double.toString(double).

+2

Se metió en el mismo problema hoy mismo y esta es en mi humilde opinión la respuesta más adecuada! ¡Gracias! – PhilDulac

+1

Sugiero que se agregue '.stripTrailingZeros()' después de 'BigDecimal.valueOf (val)' para omitir los ceros de rastreo. ejemplo: 'BigDecimal.valueOf (15.0) .stripTrailingZeros();' -> 15 (en lugar de 15.0 si no llama a '.stripTrailingZeros() ' – pierrefevrier

3

Por qué no:

b = b.setScale(2, RoundingMode.HALF_UP); 
+0

por qué no BigDecimal b = new BigDecimal (c) .setScale (2, BigDecimal.ROUND_HALF_UP); – zee

1
BigDecimal b = new BigDecimal(c).setScale(2,BigDecimal.ROUND_HALF_UP); 
0

En Java 9 el siguiente está en desuso:

BigDecimal.valueOf(d). setScale (2, BigDecimal. ROUND_HALF_UP );

utilizar en su lugar:

BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP); 

Ejemplo:

double d = 47.48111; 

    System.out.println(BigDecimal.valueOf(d)); //Prints: 47.48111 

    BigDecimal bigDecimal = BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP); 
    System.out.println(bigDecimal); //Prints: 47.48