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?
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.
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)
.
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.
Il affiche la valeur exacte exacte de la double
.
Double.toString()
, qui convertit double
s en String
s, 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!)
Pourquoi pas :
b = b.setScale(2, RoundingMode.HALF_UP);
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
BigDecimal b = new BigDecimal(c).setScale(2,BigDecimal.ROUND_HALF_UP);