9
votes

Quelle est la bonne façon de parsfloat en Java

Je remarque des problèmes avec la précision de flotteur Java xxx

i non seulement je pose un problème avec float mais aussi avec double .

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?


0 commentaires

7 Réponses :


5
votes

Vous obtenez les bons résultats. Il n'y a pas de tel float comme 0.027 exactement, pas plus que ce n'est un tel double . Vous allez toujours obtenir ces erreurs si vous utilisez float ou double .

float et double sont stockés comme fractions binaires : 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.

La seule alternative est d'utiliser bigdecimal , que vous pouvez utiliser pour obtenir des valeurs décimales exactes.


8 commentaires

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 obtenir la bonne réponse, en fonction du comportement de l'arrondi, ou non.) Vous doit utiliser BigDecimal si vous ne voulez pas ces problèmes.


-1 - nouveau float ("0.027") - 0.001F retournera .026 . Le problème n'est pas les valeurs spécifiques qu'ils utilisent ( 0,027 ) mais plutôt qu'ils mélangent une valeur de flotteur ( nouveau flotteur ("0.027") ) avec un double valeur (le littéral 0,001 ). 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 et vous obtiendrez .026 . Sortie nouveau double ("0.027") - 0.001D et vous obtiendrez .026 . Sortie Nouveau flotteur ("0.027") - 0.001D 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 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 . 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.



6
votes

voir Ce que chaque informatique doit savoir sur l'arithmétique de point flottant . Vos résultats ont l'air me corrigé.

Si vous n'aimez pas comment fonctionnent les numéros de points flottants, essayez quelque chose comme BigDecimal à la place.


0 commentaires

1
votes

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.

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.


0 commentaires

30
votes

Le problème est simplement que float a une précision finie; Il ne peut pas représenter 0.0065 exactement. (La même chose est vraie de double , bien sûr: il a une plus grande précision, mais toujours fini.)

Un autre problème, ce qui rend le problème ci-dessus plus évident, est que 0.001 < / code> est un double plutôt qu'un float , donc votre float est promu à un double 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 pourrait être représenté pour commencer. Pour résoudre ce problème, vous écririez: xxx

à l'aide de 0.001f au lieu de 0.001 .


4 commentaires

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 (Java Se 7 édition) , il existe divers opérateurs numériques, y compris - , 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 , l'autre est converti en double ."


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 a la priorité la plus élevée car, à l'exception de long , tous les autres types numériques peuvent être convertis en double 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 , il est plus complexe, mais en général, vous perdrez moins d'informations convertissant de long à double que vice-versa - Surtout depuis la plupart des valeurs possibles de Double bien en dehors de la plage de long .



1
votes

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: xxx


0 commentaires

4
votes

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


5 commentaires

Je me demande quoi arriver à système.out.println ((0.0065F - 0.001D)); ?


Vous obtenez 0.005500000134110451 ; 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?



3
votes

Je convertirais votre flotteur en chaîne puis utilisez BigDecimal.

Ce lien l'explique bien xxx

n'utilisez pas le constructeur double bigdecimal, car vous obtiendrez toujours des erreurs


0 commentaires