Équilibre des points flottants et tolérances
De la comparaison de deux nombre à virgule flottante par quelque chose comme a_float == b_float
est à la recherche d'ennuis depuis a_float /3.0 * 3.0
pourrait ne pas être égale à a_float
due à l'arrondi erreur.
Ce que l'on fait normalement c'est quelque chose comme fabs(a_float - b_float) < tol
.
Comment peut-on calculer tol
?
Idéalement, la tolérance doit être juste un peu plus grande que la valeur de l'une ou des deux, le moins de chiffres significatifs. Donc, si le seul nombre à virgule flottante est d'utiliser tol = 10E-6
devrait être sujet de droit. Toutefois, cela ne fonctionne pas bien pour le cas général où a_float
pourrait être très petite ou peut-être très grande.
Comment peut-on calculer tol
correctement pour tous les cas? Je suis intéressé en C ou C++ cas particulier.
source d'informationauteur doron | 2013-07-01
Vous devez vous connecter pour publier un commentaire.
Ce blog contient un exemple, assez infaillible de la mise en œuvre et détaillée de la théorie derrière elle
http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
il est également l'un d'une série, de sorte que vous pouvez toujours lire plus.
En bref: l'utilisation de pratiques de travail déloyales pour la plupart des numéros, utilisez epsilon pour les numéros de près de zéro, mais il y a encore des mises en garde. Si vous voulez être sur de votre calcul en virgule flottante, je recommande la lecture de l'ensemble de la série.
Autant que je sache, on n'a pas.
Il n'existe pas de "bonne réponse", car il peut dépendre de l'application de l'exigence de précision.
Par exemple, un 2D simulation physique de travail dans l'écran de pixels peut décider que 1/4 de pixel est assez bon, bien qu'un système de CAO 3D utilisé pour la conception de la centrale nucléaire internes ne pourrait pas.
Je ne peut pas voir un moyen de faire le décider de l'extérieur.
Le fichier en-tête C
<float.h>
vous donne les constantesFLT_EPSILON
etDBL_EPSILON
qui est la différence entre le 1.0 et le plus petit nombre de plus de 1,0 qu'un float/double peut représenter. Vous pouvez mettre à l'échelle par la taille de vos numéros et de l'erreur d'arrondi que vous souhaitez tolérer:Bienvenue dans le monde de pièges, collets et des lacunes. Comme mentionné ailleurs, un objectif général de solution pour virgule flottante de l'égalité et de tolérances ne pas existent. Compte tenu de cela, il existe des outils et des axiomes qu'un programmeur peut utiliser dans certains cas.
fabs(a_float - b_float) < tol
a l'inconvénient OP mentionné: "ne fonctionne pas bien dans le cas général où a_float pourrait être très petite ou peut-être très grande."fabs(a_float - ref_float) <= fabs(ref_float * tol)
face à la variante varie beaucoup mieux.OP "en virgule flottante simple précision nombre est d'utiliser tol = 10E-6" est un peu inquiétant pour le C et le C++ donc facilement en faire la promotion
float
de l'arithmétique à ladouble
et puis c'est la "tolérance" dedouble
pasfloat
qui entre en jeu. Envisagerfloat f = 1.0; printf("%.20f\n", f/7.0);
beaucoup de nouveaux programmeurs ne se rendent pas compte que le7.0
causé undouble
précision de calcul. Vous recommandons d'utiliserdouble
si votre code, sauf le cas de grandes quantités de données ont besoin de lafloat
de plus petite taille.C99 fournit
nextafter()
qui peut être une aide utile à la jauge de la "tolérance". En l'utilisant, on peut déterminer la prochaine nombre représentable. Cela va aider à l'OP "... le nombre de chiffres significatifs pour le type de stockage de moins ... pour permettre l'erreur d'arrondi."if ((nextafter(x, -INF) <= y && (y <= nextafter(x, +INF))) ...
La genre de
tol
ou de "tolérance" utilisé est souvent le cœur de la question. Le plus souvent (à mon humble avis) un relative tolérance est important. e. g. "Sont x et y dans le de 0,0001%"? Parfois, un absolue tolérance est nécessaire. par exemple, "Sont x et y dans le 0.0001"?La valeur de la tolérance est souvent discutable pour la meilleure valeur est souvent dépendant de la situation. La comparaison de 0,01 peuvent travailler pour une application financière de Dollars, mais pas de Yens. (Astuce: assurez-vous d'utiliser un style de codage qui permet de faciliter les mises à jour.)
Erreur d'arrondi varie selon les valeurs utilisées pour les opérations.
Au lieu d'un fixe, de la tolérance, vous pouvez probablement utiliser un facteur de epsilon comme:
Bien que la valeur de la tolérance dépend de la situation, si vous êtes à la recherche de la précision de comparasion vous pouvait être utilisée comme la tolérance de la machine valeur epsilon, numeric_limits::epsilon() (Bibliothèque des limites). La fonction renvoie la différence entre la 1 et la plus petite valeur supérieure à 1, qui est représentable pour le type de données.
http://msdn.microsoft.com/en-us/library/6x7575x3.aspx
La valeur de epsilon diffère si vous comparez des flotteurs ou doubles. Par exemple, dans mon ordinateur, si la comparaison des flotteurs de la valeur de epsilon est 1.1920929 e-007 et si la comparaison de doubler la valeur de epsilon est 2.2204460492503131 e-016.
Pour une comparaison relative entre x et y, qui multiplient les epsilon par le maximum de la valeur absolue de x et y.
Le résultat ci-dessus pourrait être multiplié par le ptd (unités dans la dernière place) qui vous permet de jouer avec la précision.
Quand j'ai besoin de comparer les chars, j'ai utiliser le code comme ceci