Je remarque des problèmes avec la précision de flotteur Java i non seulement je pose un problème avec Quelqu'un peut-il expliquer ce qui se passe dans les coulisses et comment pouvons-nous obtenir un nombre précis? Quelle serait la bonne façon de gérer cela lorsque vous traitez de ces problèmes? P> P> float code> mais aussi avec
double code>. P>
7 Réponses :
Vous obtenez les bons résultats. Il n'y a pas de tel La seule alternative est d'utiliser float code> comme 0.027 exactement, pas plus que ce n'est un tel
double code>. Vous allez toujours em> obtenir ces erreurs si vous utilisez
float code> ou
double code>. P>
float code> et
double code> sont stockés comme fractions binaires em>: quelque chose comme 1/2 + 1/4 + 1/16 ... vous Impossible d'obtenir toutes les valeurs décimales pour être stockées exactement comme des fractions binaires finies-précision. Ce n'est tout simplement pas mathématiquement possible. P>
bigdecimal code>, que vous pouvez utiliser pour obtenir des valeurs décimales exactes. P>
Je me demande donc comment pouvons-nous gérer quelque chose comme Float.Valueof ("0.074") // 0.073999999999999999999, puis Times 1000 à cela. Vais-je revenir 74? Ou dois-je faire un reux à chaque fois?
@ user1389813, si vous utilisez BigDecimal, vous pouvez atténuer la majorité de ces préoccupations.
Vous ne pouvez pas simplement multiplier par 1000 et obtenir la bonne réponse. (Vous pourrait i> obtenir la bonne réponse, en fonction du comportement de l'arrondi, ou non.) Vous doit I> utiliser BigDecimal code> si vous ne voulez pas ces problèmes.
-1 - nouveau float ("0.027") - 0.001F code> retournera
.026 code>. Le problème n'est pas les valeurs spécifiques qu'ils utilisent (
0,027 code>) mais plutôt qu'ils mélangent une valeur de flotteur (
nouveau flotteur ("0.027") code>) avec un double valeur (le littéral
0,001 code>). Voir ma réponse et la réponse de @ Ruakh, ci-dessous.
Les doubles auront toujours les mêmes problèmes d'arrondi.
@Louiswasserman - Oui, mais les valeurs qu'ils utilisent seulement causent des problèmes lorsqu'ils mélangent des types. Sortie nouveau flotteur ("0.027") - 0.001F code> et vous obtiendrez
.026 code>. Sortie
nouveau double ("0.027") - 0.001D code> et vous obtiendrez
.026 code>. Sortie
Nouveau flotteur ("0.027") - 0.001D CODE> Et vous allez bien faire le désordre que l'OP se rencontre. Le problème n'est pas qu'ils utilisent des flotteurs ou des doubles, mais qu'ils utilisent des flotteurs et i> doubles.
Imaginez-vous vraiment que les seules valeurs que l'OP ne se souciera jamais de 0,027, 0,001 et 0,026? Même si collé à tous les floattes ou que tous les doubles aideront dans ce cas spécifique, vous repoussez toujours la touche sur une route où le même problème viendra éventuellement.
C'est vrai, mais il y a beaucoup de réponses - à la fois ici et sur d'autres questions similaires - qui sont rapidement à la conclusion que l'arithmétique des points flottants est le cœur du problème et l'OP devrait utiliser bigdecimal code>. Je préfère @ Ruakh's Reshante (et moi-même) car ils sont moins génériques et essaient de se rapporter à l'extrait de code spécifique dans la question.
voir Ce que chaque informatique doit savoir sur l'arithmétique de point flottant . Vos résultats ont l'air me corrigé. P>
Si vous n'aimez pas comment fonctionnent les numéros de points flottants, essayez quelque chose comme
histoire longue courte si vous avez besoin d'une précision arbitraire, utilisez BigDecimal, ne pas flotter ou double. Vous verrez toutes sortes de problèmes d'arrondi de cette nature en utilisant du flotteur. P>
En défilé, faites très attention à ne pas utiliser le flotteur / double constructeur de BigDecimal car il aura le même problème. Utilisez plutôt le constructeur de cordes. P>
Le problème est simplement que Un autre problème, ce qui rend le problème ci-dessus plus évident, est que à l'aide de float code> a une précision finie; Il ne peut pas représenter
0.0065 code> exactement. (La même chose est vraie de
double code>, bien sûr: il a une plus grande précision, mais toujours fini.)
0.001 < / code> est un
double code> plutôt qu'un
float code>, donc votre
float code> est promu à un
double code> pour effectuer La soustraction, et bien sûr à ce point, le système n'a aucun moyen de récupérer la précision manquante qu'un
double code> pourrait être représenté pour commencer. Pour résoudre ce problème, vous écririez: p>
0.001f code> au lieu de
0.001 code>. P> p>
En disant que "float se fait promouvoir à un double" signifie-t-il que le compilateur le jette à double interne? Promouve-t-il le flotteur pour doubler sans condition chaque fois que nous l'utilisons avec un double pour calcul?
@ user1389813: oui. Selon §5.6.2 "Promotion numérique binaire" de la spécification de langue Java i> (Java Se 7 édition) , il existe divers opérateurs numériques, y compris - code>, avec la propriété que les deux Leurs opérandes seront convertis au même type afin d'effectuer le calcul. L'une des règles de conversion est: "Si l'un ou l'autre des opérandes est de type
double code>, l'autre est converti en
double code>."
Pourquoi double a-t-il la plus haute priorité? Est-ce parce que c'est 64 bits? Parce que je vois le double -> flotteur -> long -> int, et qu'en est-il du court?
@ user1389813: double code> a la priorité la plus élevée car, à l'exception de
long code>, tous les autres types numériques peuvent être convertis en
double code> sans perte d'informations ( mais aussi, évidemment, sans récupérer aucune information qui a précédemment été perdue). Dans le cas de
long code>, il est plus complexe, mais en général, vous perdrez moins d'informations convertissant de
long code> à
double code> que vice-versa - Surtout depuis la plupart des valeurs possibles de
Double code> bien en dehors de la plage de
long code>.
Le point flottant ne peut pas représenter avec précision des nombres décimaux. Si vous avez besoin d'une représentation précise d'un numéro en Java, vous devez utiliser la classe Java.Math.bigdecimal:
du Page de tutoriels Java sur les types de données primitifs :
Un littéral à point flottant est de type float si elle se termine par la lettre
f code> ou
f code>; Sinon, son type est double et peut éventuellement terminer avec la lettre
d code> ou
d code>. p> blockQuote>
Donc, je pense que vos littéraux (
0.001 code>) sont des doubles et vous soustrayez les doubles des flotteurs. P>
Essayez cela à la place: P>
Float.parseFloat("0.0065") - 0.001F new Float("0.027") - 0.001F Float.valueOf("0.074") - 0.001F
Je me demande quoi arriver à système.out.println ((0.0065F - 0.001D)); ?
Vous obtenez 0.005500000134110451 code>; essayez-le. Je l'ai édité pour rendre cela plus clair.
Oui je l'ai essayé, mais pourquoi finit-il comme ça quand D-F, alors que F-D?
Je ne comprends pas ce que tu veux dire.
Je veux dire qu'il a toujours une longue décimale flottante chaque fois que vous mélangez de type? Comme double soustraction de float ou de flotteur soustrait le double?
Je convertirais votre flotteur en chaîne puis utilisez BigDecimal.
Ce lien l'explique bien p> n'utilisez pas le constructeur double bigdecimal, car vous obtiendrez toujours des erreurs p> p>