2012-09-12 12 views
38

In Java, voglio prendere un doppio valore e convertirlo in un BigDecimal e stampare il suo valore di stringa in una certa precisione.Converti double in BigDecimal e imposta 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 
    } 
} 

Esso stampa questa cosa enorme:

47,47999999999999687361196265555918216705322265625

e non

47,48

La ragione per cui sto facendo la conversione BigDecimal è a volte il doppio valore conterrà molte cifre decimali (ad es. -.000012) e quando si converte il doppio in una stringa verrà generata la notazione scientifica -1.2E-4. Voglio memorizzare il valore di stringa in notazione non scientifica.

Voglio che BigDecimal abbia sempre due unità di precisione come questa: "47.48". BigDecimal può limitare la precisione alla conversione in stringa?

+1

Nota: BigDecimal anche a volte utilizzare la notazione scientifica (credo per numero <10^-6) – assylias

risposta

36

Esso stampa 47,48 mila se si utilizza un altro MathContext:

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

basta scegliere il contesto è necessario.

+12

Utilizzando la doppia funzione di costruzione non è raccomandato. – assylias

+1

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

+14

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

15

Si desidera provare String.format("%f", d), che stamperà il tuo doppio in notazione decimale. Non usare affatto BigDecimal.

quanto riguarda la questione di precisione: Si sono prima archiviano 47.48 nel double c, poi fare un nuovo BigDecimal da quel double. La perdita di precisione sta nell'assegnare a c. Potresti fare

BigDecimal b = new BigDecimal("47.48") 

per non perdere alcuna precisione.

+1

+1 si dovrebbe (quasi) non usare mai il doppio costruttore. – assylias

5

Sta stampando il valore esatto attuale di double.

Double.toString(), che converte double s per String s, fa non stampa l'esatto valore decimale dell'ingresso - se x è il vostro valore doppio, esso stampa abbastanza esattamente le cifre che x è il più vicino al valore double stampato

Il punto è che lo non è tale double come 47.48 esattamente. I valori del negozio raddoppia come binari frazioni, non come decimali, quindi non è possibile memorizzare valori decimali esatti. (Questo è ciò che BigDecimal è per!)

3

La sintassi String.format ci aiuta a convertire doppi e BigDecimals in stringhe di qualsiasi precisione.

questo codice 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))); 

Stampe:

8.88E-8 
0.0000001 
0.000000089 
0.0000000888000000000 
63

La ragione di tale comportamento è che la stringa che viene stampato è il valore esatto - probabilmente non è soddisfacente, ma questo è il valore reale memorizzato in memoria - è solo una limitazione della rappresentazione in virgola mobile.

Secondo javadoc, BigDecimal (doppio val) comportamento costruttore può essere inaspettato, se non si prendono in considerazione questa limitazione:

I risultati di questo costruttore può essere un po 'imprevedibile. Un potrebbe supporre che la scrittura nuova BigDecimal (0,1) in Java crea un BigDecimal che è esattamente pari a 0,1 (valore non in scala di 1, con una scala da 1), ma in realtà è uguale a 0,1000000000000000055511151231257827021181583404541015625. Questo perché 0.1 non può essere rappresentato esattamente come un doppio (o, per quella materia , come una frazione binaria di qualsiasi lunghezza finita). Pertanto, il valore che viene passato al costruttore non è esattamente uguale a 0,1, nonostante le apparenze.

Quindi nel tuo caso, invece di usare

double val = 77.48; 
new BigDecimal(val); 

uso

BigDecimal.valueOf(val); 

valore che viene restituito da BigDecimal.valueOf è pari a quello risultante dalla chiamata di Double.toString(double).

+2

Ranellato nello stesso identico problema oggi e questo è IMHO la risposta più adatta! Grazie! – PhilDulac

+1

Suggerisco di aggiungere '.stripTrailingZeros()' dopo 'BigDecimal.valueOf (val)' per eseguire il commit degli zeri finali. esempio: 'BigDecimal.valueOf (15.0) .stripTrailingZeros();' -> 15 (invece di 15.0 se non si chiama '.stripTrailingZeros() ' – pierrefevrier

3

Perché non:

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

why not 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

In Java 9 seguente è deprecato:

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

invece utilizzare:

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

Esempio:

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