web-dev-qa-db-fra.com

Conversion double en BigDecimal et définition de BigDecimal Precision

En Java, je veux prendre une double valeur et la convertir en une BigDecimal et afficher sa valeur String avec une certaine précision. 

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 
    }
}

Il imprime cette énorme chose:

47.4799999999999999687361196265555918216705322265625

et pas

47,48

La raison pour laquelle j’effectue la conversion BigDecimal est parfois que la valeur double contiendra un grand nombre de décimales (c.-à-d. -.000012) et lorsqu’une conversion du double en chaîne produira la notation scientifique -1.2E-4. Je veux stocker la valeur de chaîne en notation non scientifique. 

Je veux que BigDecimal ait toujours deux unités de précision comme celle-ci: "47.48". BigDecimal peut-il limiter la précision lors de la conversion en chaîne?

51
c12

Il imprime 47.48000 si vous utilisez un autre MathContext :

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

Il suffit de choisir le contexte dont vous avez besoin.

42
Gilberto Torrezan

La raison d'un tel comportement est que la chaîne imprimée correspond à la valeur exacte - probablement pas à ce que vous attendiez, mais c'est la valeur réelle stockée en mémoire - il s'agit simplement d'une limitation de la représentation en virgule flottante.

Selon javadoc, le comportement du constructeur BigDecimal (double valeur) peut être inattendu si vous ne prenez pas en compte cette limitation:

Les résultats de ce constructeur peuvent être quelque peu imprévisibles. Un peut supposer que l’écriture du nouveau BigDecimal (0.1) en Java crée un BigDecimal qui est exactement égal à 0,1 (une valeur non échelonnée de 1, avec Une échelle de 1), mais il est en réalité égal à 0.1000000000000000055511151231257827021181583404541015625. En effet, 0.1 ne peut pas être représenté exactement comme un double (ou, pour cela, une matière, une fraction binaire d’une longueur finie quelconque). Ainsi, la valeur le fait qu’il soit transmis au constructeur n’est pas exactement égal à 0,1 malgré les apparences.

Donc, dans votre cas, au lieu d'utiliser

double val = 77.48;
new BigDecimal(val);

utilisation

BigDecimal.valueOf(val);

La valeur renvoyée par BigDecimal.valueOf est égale à celle résultant de l’appel de Double.toString(double).

84
omnomnom

Vous voulez essayer String.format("%f", d), qui imprimera votre double en notation décimale. N'utilisez pas BigDecimal du tout.

Concernant le problème de précision: Vous stockez d’abord 47.48 dans le double c, puis créez une nouvelle BigDecimal à partir de cette double. La perte de précision réside dans l’affectation à c. Vous pourriez faire

BigDecimal b = new BigDecimal("47.48")

pour ne pas perdre de précision.

15
Jonathan Paulson

Il affiche la valeur exacte exacte de la double.

Double.toString(), qui convertit doubles en Strings, ne pas affiche la valeur décimale exacte de l'entrée - si x est votre valeur double, il affiche suffisamment de chiffres pour que x soit le plus proche double de la valeur imprimée.

Le fait est qu’il y a n’existe pas de telle double que 47,48 exactement. Les doubles stockent les valeurs sous forme de fractions binaires, et non sous forme de nombres décimaux, de sorte qu'il ne peut pas stocker de valeurs décimales exactes. (C'est pour ça que BigDecimal est pour!)

5
Louis Wasserman

Pourquoi pas :

b = b.setScale(2, RoundingMode.HALF_UP);
4
urOutsourced

La syntaxe String.format nous aide à convertir les doubles et les BigDecimals en chaînes de quelque précision que ce soit.

Ce code 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)));

Impressions:

8.88E-8
0.0000001
0.000000089
0.0000000888000000000
3
kk yadav
BigDecimal b = new BigDecimal(c).setScale(2,BigDecimal.ROUND_HALF_UP);
2
Leaxus