Question

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

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

Le code ci-dessus s'imprime:

11.399999999999

Comment puis-je obtenir ceci pour simplement imprimer (ou pouvoir l'utiliser comme) 11.4?

Était-ce utile?

La solution

Comme d'autres l'ont déjà mentionné, vous souhaiterez probablement utiliser BigDecimal , si vous voulez une représentation exacte de 11.4.

Maintenant, une petite explication de la raison pour laquelle cela se produit:

Les types float et double primitifs en Java sont des nombres à virgule flottante , où le nombre est stocké sous la forme d'une représentation binaire d'une fraction et d'un exposant.

Plus précisément, une valeur à virgule flottante double précision telle que le type byte est une valeur 64 bits, où:

  • 1 bit désigne le signe (positif ou négatif).
  • 11 bits pour l'exposant.
  • 52 bits pour les chiffres significatifs (la partie décimale sous forme binaire).

Ces parties sont combinées pour produire une char représentation d'une valeur.

(Source: Wikipedia: double précision )

Pour une description détaillée de la gestion des valeurs en virgule flottante en Java, voir Section 4.2.3: Types, formats et valeurs à virgule flottante de la spécification du langage Java.

Les types int, long, 11.399999999999, 5.6 + 5.8 sont corrigés point , qui sont des représentations exactes des nombres. Contrairement aux nombres à virgule fixe, les nombres à virgule flottante seront parfois (sans risque de supposer & "La plupart du temps &";) Ne pas être en mesure de retourner une représentation exacte d'un nombre. C’est la raison pour laquelle vous vous retrouvez avec <=> comme résultat de <=>.

Lorsque vous avez besoin d'une valeur exacte, telle que 1.5 ou 150.1005, vous voudrez utiliser l'un des types à virgule fixe, qui pourra représenter le nombre exactement.

Comme cela a déjà été mentionné à plusieurs reprises, Java a un <=> classe qui traitera de très grands nombres et de très petits nombres.

D'après les références de l'API Java pour la <=> classe:

  

immuable,   décimal signé à précision arbitraire   Nombres. Un BigDecimal consiste en un   entier de précision arbitraire non mis à l'échelle   valeur et une échelle entière de 32 bits. Si   zéro ou positif, l'échelle est la   nombre de chiffres à droite de la   virgule. Si négatif, le   valeur non mise à l'échelle du nombre est   multiplié par dix à la puissance de la   négation de la balance. La valeur de   le nombre représenté par le   BigDecimal est donc (unscaledValue   & # 215; 10 ^ échelle).

Il y a eu beaucoup de questions sur le dépassement de pile concernant la question des nombres en virgule flottante et sa précision. Voici une liste de questions connexes pouvant vous intéresser:

Si vous voulez vraiment en savoir plus sur les nombres à virgule flottante, consultez Ce que tout informaticien devrait savoir sur l’arithmétique en virgule flottante .

Autres conseils

Lorsque vous entrez un nombre double, par exemple 33.33333333333333, la valeur que vous obtenez est en fait la valeur double précision représentable la plus proche, qui correspond exactement à:

33.3333333333333285963817615993320941925048828125

En divisant cela par 100, on obtient:

0.333333333333333285963817615993320941925048828125

qui n'est pas non plus représentable sous forme de nombre double précision, il est donc arrondi à la valeur représentable la plus proche, qui est exactement:

0.3333333333333332593184650249895639717578887939453125

Lorsque vous imprimez cette valeur, elle est arrondie à nouveau à 17 chiffres décimaux, ce qui donne:

0.33333333333333326

Si vous souhaitez simplement traiter les valeurs sous forme de fractions, vous pouvez créer une classe de fractions contenant un champ de numérateur et de dénominateur.

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

EDIT: mise en oeuvre rapide,

public class Fraction {

private int numerator;
private int denominator;

public Fraction(int n, int d){
    numerator = n;
    denominator = d;
}

public double toDouble(){
    return ((double)numerator)/((double)denominator);
}


public static Fraction add(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop + bTop, a.denominator * b.denominator);
    }
    else{
        return new Fraction(a.numerator + b.numerator, a.denominator);
    }
}

public static Fraction divide(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.denominator, a.denominator * b.numerator);
}

public static Fraction multiply(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.numerator, a.denominator * b.denominator);
}

public static Fraction subtract(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop-bTop, a.denominator*b.denominator);
    }
    else{
        return new Fraction(a.numerator - b.numerator, a.denominator);
    }
}

}

Notez que vous auriez le même problème si vous utilisiez l'arithmétique décimale à précision limitée et que vous souhaitiez traiter avec 1/3: 0.333333333 * 3 égal à 0.999999999 et non à 1.00000000.

Malheureusement, 5.6, 5.8 et 11.4 ne sont tout simplement pas des nombres ronds en binaire, car ils impliquent des cinquièmes. Donc, leur représentation flottante n’est pas exacte, tout comme 0.3333 ne correspond pas exactement à 1/3.

Si tous les nombres que vous utilisez sont des décimales non récurrentes et que vous voulez des résultats exacts, utilisez BigDecimal. Ou, comme d’autres l’ont déjà dit, si vos valeurs ressemblent à de l’argent en ce sens qu’elles sont toutes un multiple de 0,01, ou de 0,001, ou quelque chose du genre, multipliez le tout par une puissance fixe de 10 et utilisez int ou long (addition et soustraction sont trivial: attention à la multiplication).

Cependant, si vous êtes satisfait du binaire pour le calcul, mais que vous voulez simplement imprimer les choses dans un format légèrement plus convivial, essayez java.util.Formatter ou String.format. Dans la chaîne de formatage, spécifiez une précision inférieure à la précision complète d'un double. Par exemple, 11,399999999999 est égal à 11,4 pour 10 chiffres significatifs, de sorte que le résultat sera presque aussi précis et lisible par l'homme dans les cas où le résultat binaire est très proche d'une valeur ne nécessitant que quelques décimales.

La précision à spécifier dépend un peu du calcul que vous avez fait avec vos nombres - en général, plus vous en faites, plus l'erreur s'accumule, mais certains algorithmes l'accumulent beaucoup plus rapidement que d'autres (ils sont appelés < !> "; instable &"; par opposition à & "stable &"; en ce qui concerne les erreurs d’arrondi). Si vous ne faites que l'ajout de quelques valeurs, alors j'imagine que le fait de supprimer une précision d'une décimale suffit à régler le problème. Expérience.

Si vous avez vraiment besoin de calculs de précision, vous pouvez utiliser la classe java.math.BigDecimal de java. Voici un bon article d'Oracle / Sun sur le argument de BigDecimal . Bien que vous ne puissiez jamais représenter un tiers comme mentionné par quelqu'un, vous pouvez avoir le pouvoir de décider avec précision du résultat que vous souhaitez obtenir. setScale () est votre ami ..:)

Ok, car il me reste trop de temps, voici un exemple de code correspondant à 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 langage favori, Groovy, voici un meilleur 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

Je suis sûr que vous auriez pu en faire un exemple à trois lignes. :)

Si vous voulez une précision exacte, utilisez BigDecimal. Sinon, vous pouvez utiliser des entiers multipliés par 10, quelle que soit la précision souhaitée.

Comme d'autres l'ont noté, toutes les valeurs décimales ne peuvent pas être représentées sous forme binaire, car le nombre décimal est basé sur des puissances de 10 et que les valeurs binaires sont basées sur des puissances de deux.

Si la précision compte, utilisez BigDecimal, mais si vous souhaitez simplement une sortie conviviale:

System.out.printf("%.2f\n", total);

vous donnera:

11.40

Vous vous heurtez à la limite de précision du type double.

Java.Math dispose de fonctionnalités arithmétiques de précision arbitraire.

Vous ne pouvez pas, car 7.3 n’a pas de représentation finie en binaire. 2054767329987789/2 ** 48 = 7,3 + 1/1407374883553280.

Jetez un coup d’œil à http://docs.python.org/tutorial/floatingpoint.html pour une explication supplémentaire. (C’est sur le site Web de Python, mais Java et C ++ ont le même & Quot; problème & Quot;.)

La solution dépend de la nature exacte de votre problème:

  • Si vous n'aimez pas voir tous ces chiffres parasites, corrigez le formatage de votre chaîne. N'affichez pas plus de 15 chiffres significatifs (ou 7 pour le caractère flottant).
  • Si c’est l’inexactitude de vos chiffres qui casse des choses comme & "if &"; vous devez écrire if (abs (x - 7.3) < TOLERANCE) au lieu de if (x == 7.3).
  • Si vous travaillez avec de l'argent, vous voudrez probablement un point fixe décimal. Stockez un nombre entier de centimes ou la plus petite unité de votre devise.
  • (TRES ANCIENNEMENT) Si vous avez besoin de plus de 53 bits de précision (15 à 16 chiffres significatifs) de précision, utilisez un type à virgule flottante de haute précision, comme BigDecimal.
private void getRound() {
    // this is very simple and interesting 
    double a = 5, b = 3, c;
    c = a / b;
    System.out.println(" round  val is " + c);

    //  round  val is  :  1.6666666666666667
    // if you want to only two precision point with double we 
            //  can use formate option in String 
           // which takes 2 parameters one is formte specifier which 
           // shows dicimal places another double value 
    String s = String.format("%.2f", c);
    double val = Double.parseDouble(s);
    System.out.println(" val is :" + val);
    // now out put will be : val is :1.67
}

Utilisez java.math.BigDecimal

Les doubles sont des fractions binaires internes, de sorte qu'ils ne peuvent parfois pas représenter les fractions décimales avec une décimale exacte.

Multipliez le tout par 100 et stockez-le dans une valeur aussi longue que des centimes.

Les ordinateurs stockent les numéros en binaire et ne peuvent pas représenter des nombres tels que 33.333333333 ou 100.0 exactement. C'est l'une des choses les plus délicates à propos de l'utilisation des doubles. Vous devrez juste arrondir la réponse avant de la montrer à un utilisateur. Heureusement, dans la plupart des applications, vous n’avez de toute façon pas besoin de autant de décimales.

Les nombres en virgule flottante diffèrent des nombres réels en ce que, pour tout nombre en virgule flottante donné, il existe un nombre immédiatement supérieur. Identique à des entiers. Il n'y a pas d'entier entre 1 et 2.

Il n’est pas possible de représenter 1/3 en tant que float. Il y a un flotteur en dessous et un flotteur au-dessus, et il y a une certaine distance entre eux. Et 1/3 est dans cet espace.

Apfloat for Java prétend fonctionner avec des nombres à virgule flottante en précision arbitraire, mais je ne l’ai jamais utilisé. Ça vaut probablement le coup d'oeil. http://www.apfloat.org/apfloat_java/

Une question similaire a déjà été posée ici bibliothèque de haute précision en virgule flottante Java

Les

doubles sont des approximations des nombres décimaux dans votre source Java. Vous constatez la conséquence du décalage entre le double (qui est une valeur codée en binaire) et votre source (qui est codé en décimal).

Java produit l'approximation binaire la plus proche. Vous pouvez utiliser java.text.DecimalFormat pour afficher une valeur décimale plus esthétique.

Utilisez un BigDecimal. Il vous permet même de spécifier des règles d’arrondi (comme ROUND_HALF_EVEN, qui minimisera les erreurs statistiques en arrondissant au voisin pair si les deux sont à la même distance; c’est-à-dire que les deux 1,5 et 2,5 arrondissent à 2).

Découvrez BigDecimal, il gère les problèmes liés à l’arithmétique en virgule flottante de cette manière.

Le nouvel appel ressemblerait à ceci:

term[number].coefficient.add(co);

Utilisez setScale () pour définir le nombre de précision de la décimale à utiliser.

Pourquoi ne pas utiliser la méthode round () de la classe Math?

// The number of 0s determines how many digits you want after the floating point
// (here one digit)
total = (double)Math.round(total * 10) / 10;
System.out.println(total); // prints 11.4

Si vous n'avez pas d'autre choix que d'utiliser des valeurs doubles, vous pouvez utiliser le code ci-dessous.

public static double sumDouble(double value1, double value2) {
    double sum = 0.0;
    String value1Str = Double.toString(value1);
    int decimalIndex = value1Str.indexOf(".");
    int value1Precision = 0;
    if (decimalIndex != -1) {
        value1Precision = (value1Str.length() - 1) - decimalIndex;
    }

    String value2Str = Double.toString(value2);
    decimalIndex = value2Str.indexOf(".");
    int value2Precision = 0;
    if (decimalIndex != -1) {
        value2Precision = (value2Str.length() - 1) - decimalIndex;
    }

    int maxPrecision = value1Precision > value2Precision ? value1Precision : value2Precision;
    sum = value1 + value2;
    String s = String.format("%." + maxPrecision + "f", sum);
    sum = Double.parseDouble(s);
    return sum;
}

Ne perdez pas votre effort avec BigDecimal. Dans 99,99999% des cas, vous n'en avez pas besoin. java double est assez approximatif, mais dans la plupart des cas, il est suffisamment précis. Notez que vous avez une erreur au 14ème chiffre significatif. C'est vraiment négligeable!

Pour obtenir de bons résultats, utilisez:

System.out.printf("%.2f\n", total);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top