2016-03-22 2 views
-5

Ni 0.1d, 0.2d ou 0.3d ne peuvent être représentés exactement en binaire.Je savais que 0.1D + 0.2D == 0.30000000000000004D - pourquoi 0.1D + 0.1D = 0.2D?

Pourquoi 0.1D + 0.1D == 0.2D est-il vrai en Java?

le nombre binaire de 64 bits est comment devenir 0.1.0.2,0.3 ????? Où est le code?

+1

Ce n'est pas vraiment un double - l'op semble déjà savoir que tous les nombres décimaux peuvent être représentés exactement par un double ... – assylias

+1

closest_float (x) + nearest_float (x) = nearest_float (2 * x) est toujours vrai dans IEEE 754 quelle que soit la langue. Nous ne pouvons pas expliquer pourquoi dans un commentaire ... Peut-être que la question a été fermée prématurément. –

+0

@ aka.nice rouvert si vous voulez ajouter une réponse. – assylias

Répondre

1

Si vous exécutez:

System.out.println(new BigDecimal(0.1d + 0.1d)); 
System.out.println(new BigDecimal(0.2d)); 
System.out.println(0.1d + 0.1d == 0.2d); //true 

vous verrez que les deux déclarations imprimer 0.200000000000000011102230246251565404236316680908203125.

En d'autres termes, 0.1d + 0.1d == 0.2d est vrai mais aucun n'est strictement égal au nombre décimal 0,2.

D'autre part, les deux premières lignes ci-dessous ne s'impriment pas le même nombre et 0.1d + 0.1d + 0.1d == 0.3d est faux:

System.out.println(new BigDecimal(0.1d + 0.1d + 0.1d)); 
System.out.println(new BigDecimal(0.3d)); 
System.out.println(0.1d + 0.1d + 0.1d == 0.3d); //false 
+0

le nombre binaire 64 bits est de savoir comment devenir 0.1,0.2,0.3 ????? Où est le code? – pppp

2

Supposons que x est la décimale exacte.
nearest_float(x) est la conversion en virgule flottante.
Il arrondit à la valeur du point flottant représentable le plus proche, égal à pair.
ulp(nearest_float(x)) est l'unité de moindre précision de la valeur en virgule flottante (c'est-à-dire la valeur du plus petit bit de significande).
x + y indique l'opération arithmétique exacte, même chose pour - * /.
nearest_float(x)+nearest_float(y) est la somme exacte des approximations flottantes.
nearest_float(nearest_float(x)+nearest_float(y)) est l'opération en virgule flottante.

Opération nearest_float(x)+nearest_float(x) est strictement équivalent à nearest_float(x)*2, et l'opération nearest_float(x)*2 est exacte, sauf les rares cas de flotter trop-plein de points: il est juste un changement de l'exposant, nearest_float(2*nearest_float(x))=2*nearest_float(x) ..

Nous avons cette propriété: abs(nearest_float(x)-x) <= ulp(nearest_float(x))/2.

Nous pouvons multiplier les deux côtés de l'inégalité par 2: abs(2*nearest_float(x)-2*x) <= ulp(2*nearest_float(x))/2. Le plus souvent, il y a une seule valeur dans cet intervalle, exceptionnellement deux valeurs en cas d'égalité exacte, mais l'égalité exacte sera résolue comme dans le cas de x (seul l'exposant a changé, pas le significand). Près des limites de binade, il peut y avoir deux flotteurs dans l'intervalle ci-dessus aussi, mais la résolution sera aussi au même significand.
Ainsi cela signifie que 2*nearest_float(x) est le bon candidat pour nearest_float(2*x)

Ainsi, dans une langue basée sur IEEE 754 à virgule flottante, avec arrondi au plus proche, cravate au même mode d'arrondi (le mode par défaut), et correctement arrondies valeurs littérales (ce qui signifie que 0,1 retournera effectivement le flottant le plus proche à 1/10) vous aurez la propriété 0.3 + 0.3 == 0.6, 0.07 + 0.07 == 0.14, 3.14 + 3.14 == 6.28, x + x == 2 * x la valeur de x.

Plus surprisignly, vous avez encore plus drôles propriétés comme celui-ci Is 3*x+x always exact?

+0

le nombre binaire 64 bits est de savoir comment devenir 0.1,0.2,0.3 ????? Où est le code? – pppp

+0

pourquoi je définis double d = 0,2, et la valeur que je vois est de 0,2, pas 0,200000000000000011102230246251565404236316680908203125. – pppp

+0

Vous voyez 0.2 parce que Double.toString "arrondit" le double. Pour voir la valeur exacte, utilisez un BigDecimal comme dans mon exemple. – assylias