Comment correctement et correctement comparer les flotteurs?
Chaque fois que je commence un nouveau projet et j'ai besoin de comparer certains type float ou double variables-je écrire le code comme celui-ci:
if (fabs(prev.min[i] - cur->min[i]) < 0.000001 &&
fabs(prev.max[i] - cur->max[i]) < 0.000001) {
continue;
}
Puis je veux me débarrasser de ces magie variables 0.000001(et 0.00000000001 pour le double) et fab, j'ai donc écrire une fonction en ligne et certains définit:
#define FLOAT_TOL 0.000001
Donc je me demande si il n'y a aucune méthode de faire cela? Peut-être certains d'en-tête standard de fichier?
Il serait également agréable d'avoir float et double limites(valeurs min et max)
- Regardez cette stackoverflow.com/questions/17333/...
- Dépend du cas d'utilisation, mais ce que sur de très petits nombres? Votre code de comparer
1e-10
et1e-15
et-1e-10
comme tous égaux. Il n'y a pas une seule "bonne" façon de comparer des nombres à virgule flottante "proximité". - Pourquoi les #define? Vous pouvez simplement utiliser un static const float pour ce but.
- Je parie que vous avez oublié de le comparer avec 0? 🙂
Vous devez vous connecter pour publier un commentaire.
De La Virgule Flottante Guide:
Le problème avec le "nombre magique" n'est pas ici que c'est codé en dur, mais que c'est "magique": vous n'avez pas vraiment avoir une raison pour le choix de 0.000001 sur 0.000005 ou 0.0000000000001, avez-vous? Notez que
float
peut représenter approximativement la dernière et la plus petite des valeurs - c'est à peu près 7 décimales de précision après le premier chiffre différent de zéro!Si vous allez utiliser un fixe epsilon, vous devriez vraiment choisir en fonction des exigences de la pièce, en particulier, de code où vous l'utilisez. L'alternative est d'utiliser une relative marge d'erreur (voir le lien en haut pour les détails) ou, encore mieux, ou comparer les chars comme des entiers.
La Norme fournit une valeur epsilon. C'est dans
<limits>
et vous pouvez accéder à la valeur parstd::numeric_limits<float>::epsilon
etstd::numeric_limits<double>::epsilon
. Il y a d'autres valeurs, mais je n'ai pas vérifier ce qu'est exactement.epsilon
n'est pas un droit de remplacement pour la constante de la tolérance utilisée par l'interlocuteur. Il représente out-par-1 dans le bit le moins significatif de la valeur 1.0, donc, si vos valeurs sont environ 2, il est alors trop faible pour fournir aucune tolérance. Il est assez difficile d'utiliser efficacement.Vous devez être conscient que si vous êtes à la comparaison de deux flotteurs pour l'égalité, vous
sont intrinsèquement de faire la mauvaise chose. L'ajout d'un retraité facteur de la comparaison
n'est pas assez bon.
Vous pouvez utiliser
std::nextafter
pour le test de deuxdouble
avec le plus petit epsilon sur une valeur (ou un facteur de la plus petite epsilon).Merci pour vos réponses, elles m'ont beaucoup aidé. J'ai lu ces documents:première et deuxième
La réponse est d'utiliser mon propre fonction pour comparaison:
C'est la solution la plus adaptée à mes besoins. Cependant j'ai écrit quelques essais et d'autres méthodes de comparaison. J'espère que ce sera utile à quelqu'un. areEqualRel passe ces tests, d'autres ne le font pas.
Vous devez utiliser la norme de définir dans flotter.h:
ou la numeric_limits classe:
[EDIT: il est juste un peu plus lisible.]
Mais en outre, il dépend de ce que vous êtes après.
DBL_EPSILON
. blog.frama-c.com/index.php?post/2013/05/09/FLT_EPSILONIci est un c++11 de la mise en œuvre de @geotavros 's solution. Il fait usage de la nouvelle
std::numeric_limits<T>::epsilon()
fonction et le fait questd::fabs()
etstd::fmax()
maintenant ont des surcharges pourfloat
,double
etlong float
.Ce post a une explication détaillée de comment comparer des nombres à virgule flottante:
http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/
Extrait: