Pourquoi ne l'ajout de 0,1 à plusieurs reprises restent sans perte?
Je sais que le 0.1
nombre décimal ne peut pas être représenté exactement avec un nombre fini de nombres binaires (explication), de sorte double n = 0.1
perd un peu de précision et ne sera pas exactement 0.1
. D'autre part 0.5
peut être représenté exactement parce que c'est 0.5 = 1/2 = 0.1b
.
Cela dit, il est compréhensible que l'ajout de 0.1
trois fois ne donnera pas exactement 0.3
donc le code suivant imprime false
:
double sum = 0, d = 0.1;
for (int i = 0; i < 3; i++)
sum += d;
System.out.println(sum == 0.3); //Prints false, OK
Mais alors, comment est-ce que l'ajout de 0.1
cinq fois donneront exactement 0.5
? Le code suivant imprime true
:
double sum = 0, d = 0.1;
for (int i = 0; i < 5; i++)
sum += d;
System.out.println(sum == 0.5); //Prints true, WHY?
Si 0.1
ne peut pas être représenté exactement, comment est-ce que l'ajout de 5 fois donne exactement 0.5
qui peut être représenté précisément?
Vous pensez à ce sujet dans une mathy. Virgule flottante aritmetics n'est pas des maths en aucune façon.
c'est très beaucoup de la mauvaise attitude à avoir.
même si elle a été optimisé de loin, ce ne serait qu'une optimisation valide si
sum
avait la même valeur, c'est comme si la boucle était réellement exécutées. Dans la norme C++ ce qui est appelé le "comme-si la règle" ou "même les comportements observables".pas vrai du tout. L'arithmétique en virgule flottante est rigoureusement définis, avec un bon traitement mathématique de l'erreur de limites et de ces. C'est juste que beaucoup de programmeurs ne sont pas prêts à le suivre à travers sur l'analyse, ou qu'ils croient, à tort, que "floating-point est inexact" est tout ce qu'il faut savoir et que l'analyse n'est pas la peine de s'embêter avec.
OriginalL'auteur icza | 2014-09-30
Vous devez vous connecter pour publier un commentaire.
L'erreur d'arrondi est pas le fruit du hasard et de la façon dont il est mis en œuvre, il tente de minimiser l'erreur. Cela signifie que, parfois, l'erreur n'est pas visible, ou il n'y a pas d'erreur.
Par exemple
0.1
n'est pas exactement0.1
c'est à direnew BigDecimal("0.1") < new BigDecimal(0.1)
mais0.5
est exactement1.0/2
Ce programme vous montre les vraies valeurs impliquées.
imprime
Remarque: que
0.3
est légèrement décalé, mais quand vous arrivez à0.4
les bits ont à passer de l'un à l'ajustement dans le 53 bits limite et l'erreur est supprimée. Encore une fois, une erreur se glisse en arrière pour la0.6
et0.7
mais pour0.8
à1.0
l'erreur est ignorée.La raison, il ya une erreur est due à la précision limitée. j'.e 53 bits. Cela signifie que le nombre utilise plus de bits qu'il deviennent de plus en plus, les bits doivent être déposés à la fin. Cela provoque arrondissement qui dans ce cas est en votre faveur.
Vous pouvez obtenir l'effet inverse lors de l'obtention d'un plus petit nombre par exemple
0.1-0.0999
=>1.0000000000000286E-4
et vous voyez plus d'erreur qu'avant.
Un exemple de ce est pourquoi, dans la version 6 de Java Pourquoi les Mathématiques.round(0.49999999999999994) return 1 Dans ce cas, la perte d'un bit dans les résultats de calcul dans une grande différence pour la réponse.
Le CPU suit la norme IEEE-754. Java vous permet d'accéder aux sous-jacent instructions du PROCESSEUR et de ne pas s'impliquer. en.wikipedia.org/wiki/IEEE_floating_point
Pas nécessairement de la CPU. Sur une machine sans virgule flottante dans le CPU (et pas de FPU), IEEE arithmétique sera effectué par le logiciel. Et si le PROCESSEUR de l'hôte a virgule flottante, mais il n'est pas conforme aux exigences de l'IEEE, je pense que Java est mise en œuvre pour que le CPU serait dans l'obligation d'utiliser des float trop...
dans ce cas, je ne sais pas ce qui se passerait si vous avez utilisé
strictfp
de Temps pour examiner du point fixe entiers, je pense. (ou BigDecimal)la clé du problème est le peu de valeurs à virgule flottante peut représenter. Cette limitation peut entraîner une perte d'information et le nombre augmente d'une perte de l'erreur. Il utilise les arrondis mais dans ce cas, les tournées vers le bas de sorte à ce qu'aurait été un certain nombre qui est un peu trop grand que de 0,1 est légèrement trop grand, se transforme en la valeur correcte. Exactement 0,5
OriginalL'auteur Peter Lawrey
D'interdiction de dépassement, en virgule flottante,
x + x + x
est exactement le correctement arrondies (c'est à dire la plus proche) nombre à virgule flottante le réel 3*x
,x + x + x + x
est exactement 4*x
, etx + x + x + x + x
est de nouveau correctement arrondi virgule flottante approximation pour les 5*x
.Le premier résultat, pour
x + x + x
, provient du fait quex + x
est exacte.x + x + x
est donc le résultat d'un seul arrondissement.Le deuxième résultat est plus difficile, une démonstration de ce qui est discuté ici (et Stephen Canon fait allusion à une autre preuve par l'analyse de cas sur les 3 derniers chiffres de
x
). Pour résumer, soit 3*x
est dans le même binade 2*x
ou il est dans le même binade 4*x
, et dans chaque cas, il est possible d'en déduire que l'erreur sur la troisième plus annule l'erreur sur la deuxième plus (le premier ajout est exact, comme nous l'avons déjà dit).Le troisième résultat, “
x + x + x + x + x
est arrondie”, dérive de l'autre, de la même manière que la première découle de l'exactitude dex + x
.La deuxième raison qui explique pourquoi
0.1 + 0.1 + 0.1 + 0.1
est exactement le nombre à virgule flottante0.4
: les nombres rationnels 1/10 et 4/10 obtenir rapprochait de la même manière, avec la même erreur relative, une fois la conversion en virgule flottante. Ces nombres à virgule flottante ont un ratio d'exactement 4 d'entre eux. La première et la troisième résultat montrent que0.1 + 0.1 + 0.1
et0.1 + 0.1 + 0.1 + 0.1 + 0.1
peut s'attendre à avoir moins d'erreurs que pourrait être déduit par naïve de l'analyse des erreurs, mais, en eux-mêmes, ils ne concernent que les résultats de respectivement3 * 0.1
et5 * 0.1
, qui devrait être proche, mais pas nécessairement identiques à0.3
et0.5
.Si vous continuez à ajouter des
0.1
après le quatrième plus, vous allez enfin observer les erreurs d'arrondi qui font “0.1
ajouté à lui-même n fois” divergent à partir den * 0.1
, et de s'écarter encore plus de n/10. Si vous deviez tracer les valeurs de “0.1 ajouté à lui-même n fois comme une fonction de n, vous observez les lignes de pente constante par binades (dès que le résultat de la n-ième plus est destiné à tomber dans un particulier binade, les propriétés de l'addition devrait être similaire à la précédente ajouts qui a produit un résultat dans la même binade). Au sein d'une même binade, l'erreur va croître ou décroître. Si vous regardez la séquence des pistes de binade à binade, vous permettrait de reconnaître la répétition des chiffres de0.1
en binaire pour un certain temps. Après cela, l'absorption serait de commencer à prendre place, et la courbe devrait aller à plat.Je dis que
x + x + x
est exactement le correctement arrondi nombre à virgule flottante le réel 3*x
. “arrondie” signifie “le plus proche” dans ce contexte.+1 Cela devrait être accepté de répondre. Il propose en fait des explications/la preuve de ce qu'il se passe sur plutôt que seulement de vagues généralités.
de ce qui est prévu par la question). Mais ce que cette réponse explique est comment les erreurs fortuite d'annuler plutôt que de les ajouter dans le pire des cas de la mode.
0.1 0 x 1.999999999999999999999...p-4 en hexadécimal (une suite infinie de chiffres). Il est approximée en double précision que 0x1.99999ap-4. 0.2 est 0x1.999999999999999999999...p-3 en hexadécimal. Pour la même raison que de 0,1 est approchée comme 0x1.99999ap-4, de 0,2 est approchée comme 0x1.99999ap-3. Pendant ce temps, 0x1.99999ap-3 est aussi exactement 0x1.99999ap-4+0x1.99999ap-4.
OriginalL'auteur Pascal Cuoq
Virgule flottante systèmes divers de la magie, y compris d'avoir un peu plus de bits de précision de l'arrondi. Ainsi, le très petit d'erreur en raison de l'imprécision de la représentation de 0,1 finit par obtenir un arrondi à 0,5.
Penser à virgule flottante comme un grand, mais INEXACT façon de représenter les nombres. Pas tous les nombres possibles sont facilement représentés dans un ordinateur. Les nombres irrationnels comme PI. Ou comme SQRT(2). (Symbolique mathématique des systèmes en mesure de les représenter, mais j'ai dit "facilement".)
La valeur à virgule flottante peut être très proche, mais elle n'est pas exacte. Il peut être aussi près que vous pouvez naviguer à Pluton et de millimètres. Mais toujours pas d'exact dans un sens mathématique.
Ne pas utiliser de virgule flottante lorsque vous en avez besoin pour être exact, plutôt que de façon approximative. Par exemple, les applications de comptabilité voulez garder exacte de la piste d'un certain nombre de pièces de monnaie dans un compte. Les entiers sont bons pour que parce qu'ils sont exacts. Le principal problème que vous devez regarder pour avec des entiers est dépassement de.
À l'aide de BigDecimal de la monnaie fonctionne bien parce que la représentation sous-jacente est un entier, mais un gros.
Reconnaissant que des nombres à virgule flottante sont inexactes, ils ont encore un grand nombre d'utilisations. Systèmes de coordonnées pour la navigation ou les coordonnées dans les systèmes graphiques. Astronomique valeurs. Valeurs scientifiques. (Vous avez probablement ne peut pas savoir la masse exacte d'une balle de baseball à l'intérieur d'une masse d'un électron de toute façon, donc inexactitude n'a pas vraiment d'importance.)
Pour les applications de comptage (y compris la comptabilité) utilisez entier. Pour compter le nombre de gens qui passent par une porte, utiliser des int ou long.
strictfp
). Juste parce que vous avez renoncé à comprendre quelque chose ne signifie pas qu'il est insondable, ni que d'autres devraient renoncer à comprendre. Voir stackoverflow.com/questions/18496560 comme un exemple des longueurs implémentations Java va aller afin de mettre en œuvre la définition du langage (qui ne comprend pas de dispositions pour plus de précision bits ni, avecstrictfp
, pour toute exp supplémentaire bits)OriginalL'auteur DannyB