Je dois calculer quelques variables à virgule flottante et mon collègue me suggère de les utiliser à la BigDecimal
place double
car ce sera plus précis. Mais je veux savoir de quoi il s'agit et comment en tirer le meilleur parti BigDecimal
?
java
floating-point
double
bigdecimal
Truong Ha
la source
la source
Réponses:
A
BigDecimal
est une façon exacte de représenter les nombres. ADouble
a une certaine précision. Travailler avec des doubles de différentes grandeurs (disonsd1=1000.0
etd2=0.001
) pourrait entraîner0.001
une chute totale lors de la sommation car la différence de grandeur est si grande. AvecBigDecimal
cela ne se produirait pas.L'inconvénient
BigDecimal
est qu'il est plus lent et qu'il est un peu plus difficile de programmer des algorithmes de cette façon (en raison de la surcharge+
-
*
et/
sans être surchargés).Si vous avez affaire à de l'argent, ou si la précision est indispensable, utilisez
BigDecimal
. Sinon, ilsDoubles
ont tendance à être assez bons.Je recommande la lecture de la javadoc de
BigDecimal
comme ils le font mieux expliquer les choses que je fais ici :)la source
if (Math.abs(loadPerServer - maxLoadPerServer) < 0.000001d) {
BigDecimal
", un Double aurait plus de "précision" (plus de chiffres).Mon anglais n'est pas bon donc je vais juste écrire un exemple simple ici.
Sortie du programme:
Quelqu'un veut toujours utiliser le double? ;)
la source
System.out.println(0.003f - 0.002f);
BigDecimal est exact:System.out.println(new BigDecimal("0.003").subtract(new BigDecimal("0.002")));
Il y a deux différences principales par rapport au double:
La raison pour laquelle vous devez utiliser BigDecimal pour les calculs monétaires n'est pas qu'il peut représenter n'importe quel nombre, mais qu'il peut représenter tous les nombres qui peuvent être représentés sous forme décimale et qui incluent pratiquement tous les nombres dans le monde monétaire (vous ne transférez jamais 1/3 $ à quelqu'un).
la source
Si vous écrivez une valeur fractionnaire comme une valeur
1 / 7
décimale, vous obtenezavec une séquence infinie de
142857
. Comme vous ne pouvez écrire qu'un nombre fini de chiffres, vous introduisez inévitablement une erreur d'arrondi (ou de troncature).Les nombres comme
1/10
ou1/100
exprimés en nombres binaires avec une partie fractionnaire ont également un nombre infini de chiffres après la virgule décimale:Doubles
stocker les valeurs sous forme binaire et peut donc introduire une erreur uniquement en convertissant un nombre décimal en nombre binaire, sans même faire d'arithmétique.Les nombres décimaux (comme
BigDecimal
), d'autre part, stockent chaque chiffre décimal tel quel. Cela signifie qu'un type décimal n'est pas plus précis qu'un type à virgule flottante binaire ou à virgule fixe dans un sens général (c'est-à-dire qu'il ne peut pas être stocké1/7
sans perte de précision), mais il est plus précis pour les nombres qui ont un nombre fini de chiffres décimaux comme c'est souvent le cas pour les calculs d'argent.Java
BigDecimal
a l'avantage supplémentaire de pouvoir avoir un nombre arbitraire (mais fini) de chiffres des deux côtés de la virgule décimale, limité uniquement par la mémoire disponible.la source
BigDecimal est la bibliothèque numérique à précision arbitraire d'Oracle. BigDecimal fait partie du langage Java et est utile pour une variété d'applications allant du financier au scientifique (c'est là que je suis).
Il n'y a rien de mal à utiliser des doubles pour certains calculs. Supposons toutefois que vous vouliez calculer Math.Pi * Math.Pi / 6, c'est-à-dire la valeur de la fonction Riemann Zeta pour un argument réel de deux (un projet sur lequel je travaille actuellement). La division en virgule flottante vous présente un problème douloureux d'erreur d'arrondi.
BigDecimal, d'autre part, comprend de nombreuses options pour calculer des expressions avec une précision arbitraire. Les méthodes d'ajout, de multiplication et de division décrites dans la documentation Oracle ci-dessous "prennent la place" de +, * et / dans BigDecimal Java World:
http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
La méthode compareTo est particulièrement utile dans les boucles while et for.
Soyez toutefois prudent lorsque vous utilisez des constructeurs pour BigDecimal. Le constructeur de chaîne est très utile dans de nombreux cas. Par exemple, le code
BigDecimal onethird = nouveau BigDecimal ("0.33333333333");
utilise une représentation sous forme de chaîne de 1/3 pour représenter ce nombre à répétition infinie avec un degré de précision spécifié. L'erreur d'arrondi est très probablement quelque part si profondément dans la machine virtuelle Java que les erreurs d'arrondi ne perturberont pas la plupart de vos calculs pratiques. Cependant, d'après mon expérience personnelle, j'ai vu des arrondissements se multiplier. La méthode setScale est importante à cet égard, comme le montre la documentation Oracle.
la source
/* * Portions Copyright IBM Corporation, 2001. All Rights Reserved. */
Si vous avez affaire au calcul, il existe des lois sur la façon de calculer et sur la précision à utiliser. Si vous échouez, vous ferez quelque chose d'illégal. La seule vraie raison est que la représentation binaire des décimales n'est pas précise. Comme Basil l'a dit simplement, un exemple est la meilleure explication. Pour compléter son exemple, voici ce qui se passe:
Production:
Nous avons aussi cela:
Nous donne la sortie:
Mais:
A la sortie:
la source