185 votes

Conserver la précision avec Doubles en java

Double Possible:
Pourquoi dois-je voir un double variable initialisée à une valeur comme 21.4 comme 21.399999618530273?

public class doublePrecision {
    public static void main(String[] args) {

        double total = 0;
        total += 5.6;
        total += 5.8;
        System.out.println(total);
    }
}

Qui renvoie

11.399999999999

Bon de clarifier la question un peu: comment puis-je obtenir cela, il suffit d'imprimer (ou être capable de l'utiliser comme) 11.4?

182voto

coobird Points 70356

Comme d'autres l'ont mentionné, vous voudrez probablement utiliser l' BigDecimal classe, si vous voulez avoir une représentation exacte de 11.4.

Maintenant, un peu d'explication sur le pourquoi de ce qui se passe:

L' float et double types primitifs de Java sont à virgule flottante , où le nombre est stocké comme une représentation binaire d'une fraction et d'un exposant.

Plus précisément, un double précision en virgule flottante valeur tels que l' double type est une valeur 64 bits, d'où:

  • 1 bit indique le signe (positif ou négatif).
  • 11 bits pour l'exposant.
  • 52 bits pour les chiffres significatifs (la partie fractionnaire d'un système binaire).

Ces pièces sont combinés pour produire une double représentation d'une valeur.

(Source: Wikipédia: Double précision)

Pour une description détaillée de la façon dont les valeurs à virgule flottante sont traitées en Java, consultez la Section 4.2.3: les Types à virgule Flottante, les Formats et les Valeurs de la Java Language Specification, 3e Ed..

L' byte, char, int, long types de point fixe de numéros, qui sont l'exacte representions de nombres. À la différence de point fixe des chiffres, des nombres à virgule flottante sera quelques fois (sûr de supposer que la "plupart du temps") de ne pas être en mesure de retourner une représentation exacte d'un nombre. C'est la raison pour laquelle vous vous retrouvez avec 11.399999999999 comme le résultat d' 5.6 + 5.8.

Lorsque vous avez besoin d'une valeur exacte, tels que de 1,5 ou 150.1005, vous aurez envie d'utiliser l'un des points fixes des types, qui sera en mesure de représenter le nombre exact.

Comme il a été mentionné à plusieurs reprises déjà, Java a un BigDecimal de la classe qui va gérer des nombres très grands et très petits nombres.

À partir de l'API Java de Référence pour l' BigDecimal classe:

Immuable, précision arbitraire décimal signé les numéros. Un BigDecimal se compose d'un précision arbitraire entier non mis à l'échelle valeur et d'un entier de 32 bits de l'échelle. Si zéro ou positif, l'échelle est nombre de chiffres à droite de la point décimal. Si le résultat est négatif, le non mis à l'échelle de la valeur du nombre est multiplié par dix à la puissance de l' la négation de l'échelle. La valeur de le nombre représenté par la BigDecimal est donc (unscaledValue × 10^-échelle).

Il y a eu de nombreuses questions sur Stack Overflow relative à la question de nombres en virgule flottante et sa précision. Voici une liste de questions qui peuvent être d'intérêt:

Si vous voulez vraiment g

111voto

Stephen Canon Points 58003

Lorsque vous tapez 33.33333333333333, la valeur que vous obtenez est en fait le plus proche représentable double précision de la valeur, ce qui est exactement:

33.3333333333333285963817615993320941925048828125

Diviser le résultat par 100 donne:

0.333333333333333285963817615993320941925048828125

ce qui n'est pas représentable comme un nombre double précision, de façon encore, il est arrondi à la valeur représentable, ce qui est exactement:

0.3333333333333332593184650249895639717578887939453125

Lorsque vous imprimez cette valeur, il obtient arrondie encore une fois à 17 chiffres décimaux:

0.33333333333333326

24voto

Viral Shah Points 959

Si vous voulez juste pour traiter les valeurs sous forme de fractions, vous pouvez créer une classe de Fraction qui contient un champ numérateur et dénominateur.

Écrire des méthodes pour ajouter, soustraire, multiplier et diviser ainsi qu’une méthode toDouble. De cette façon que vous pouvez éviter les flotteurs lors de calculs.

EDIT : Exécution rapide,

16voto

Steve Jessop Points 166970

Observez que vous auriez le même problème si vous avez utilisé limitée de décimales de précision arithmétique, et je voulais traiter avec 1/3: 0.333333333 * 3 est 0.999999999, pas 1.00000000.

Malheureusement, 5.6, 5.8 et 11.4 ne sont pas seulement des chiffres ronds, en binaire, parce qu'ils impliquent des cinquièmes. Donc, la représentation du flotteur d'entre eux n'est pas exact, tout comme 0.3333 n'est pas exactement 1/3.

Si tous les numéros que vous utilisez sont non-récurrents décimales, et que vous voulez des résultats exacts, l'utilisation BigDecimal. Ou comme d'autres l'ont dit, si vos valeurs sont comme de l'argent dans le sens qu'ils sont tous des multiples de 0,01 ou 0,001, ou quelque chose, puis multipliez le tout par une puissance fixe de 10 et de l'utilisation de type int ou long (l'addition et la soustraction sont triviales: watch out pour la multiplication).

Toutefois, si vous êtes heureux avec le binaire pour le calcul, mais vous voulez juste pour imprimer des choses un peu plus convivial format, essayez java.util.Formatter ou String.format. Dans la chaîne de format spécifier une précision inférieure à la précision d'un double. À 10 chiffres significatifs, disons, 11.399999999999 est de 11,4, de sorte que le résultat sera presque aussi précis et plus lisible par l'homme, dans les cas où le résultat en binaire est très proche d'une valeur ne nécessitant que quelques décimales.

La précision de spécifier dépend un peu sur la façon dont beaucoup de maths que vous avez fait avec vos numéros - en général, le plus vous le faites, plus d'erreur s'accumule, mais certains algorithmes s'accumulent beaucoup plus rapide que les autres (on les appelle des "instable" par opposition à "stable" à l'égard des erreurs d'arrondi). Si tout ce que vous avez à faire est d'ajouter quelques valeurs, alors je suppose que passant à un nombre de décimales de précision va arranger les choses. Expérience.

9voto

Vinny Points 410

Vous pouvez l'examiner à l'aide de java java.les mathématiques.BigDecimal classe si vous avez vraiment besoin de mathématiques de précision. Voici un bon article à partir d'Oracle/Sun sur le cas de BigDecimal. Bien que vous ne pouvez jamais représentent 1/3 comme quelqu'un l'a mentionné, vous pouvez avoir le pouvoir de décider exactement comment précise du résultat que vous voulez être. setScale() est votre ami.. :)

Ok, parce que j'ai beaucoup trop de temps sur mes mains pour le moment voici un exemple de code qui se rapporte à votre question:

import java.math.BigDecimal;
/**
 * Created by a wonderful programmer known as:
 * Vincent Stoessel
 * xaymaca@gmail.com
 * on Mar 17, 2010 at  11:05:16 PM
 */
public class BigUp {

    public static void main(String[] args) {
        BigDecimal first, second, result ;
        first = new BigDecimal("33.33333333333333")  ;
        second = new BigDecimal("100") ;
        result = first.divide(second);
        System.out.println("result is " + result);
       //will print : result is 0.3333333333333333


    }
}

et pour brancher mon nouveau favori de la langue, Groovy, ici, c'est un plus soignée exemple de la même chose:

import java.math.BigDecimal

def  first =   new BigDecimal("33.33333333333333")
def second = new BigDecimal("100")


println "result is " + first/second   // will print: result is 0.33333333333333

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X