2010-06-24 26 views
4

DBL_EPSILON/std :: numeric_limits :: epsilon me donnera la plus petite valeur qui fera la différence lors de l'ajout d'un seul.Quand utiliser DBL_EPSILON/epsilon

J'ai de la difficulté à comprendre comment appliquer ces connaissances à quelque chose d'utile.

L'epsilon est beaucoup plus grand que la plus petite valeur que l'ordinateur peut gérer, donc il semblerait comme une supposition correcte qu'il est sûr d'utiliser des valeurs plus petites que epsilon?

Le rapport entre les valeurs avec lesquelles je travaille doit-il être inférieur à 1/epsilon?

Répondre

4

La définition de DBL_EPSILON n'est pas cela. C'est la différence entre le nombre représentable suivant après 1 et 1 (votre définition suppose que le mode d'arrondi est réglé sur "vers 0" ou "vers moins l'infini", ce n'est pas toujours vrai).

C'est quelque chose d'utile si vous en savez assez sur l'analyse numérique. Mais je crains que cet endroit ne soit pas le meilleur pour en apprendre davantage à ce sujet. À titre d'exemple, vous pouvez l'utiliser dans la construction d'une fonction de comparaison qui dira si deux nombres à virgule flottante sont approximativement égales comme celui-ci

bool approximatively_equal(double x, double y, int ulp) 
{ 
    return fabs(x-y) <= ulp*DBL_EPSILON*max(fabs(x), fabs(y)); 
} 

(mais sans savoir comment déterminer ULP, vous serez perdu, et ce fonction a probablement des problèmes si les résultats intermédiaires sont dénormalisés; calcul fp est compliqué à fabriquer robuste)

+0

'approximately_equal' ne fonctionnera pas correctement pour de très grandes valeurs, puisque la taille de l'intervalle entre la valeur représentable actuelle et la plus proche suivante dans un double change avec l'amplitude (parce que l'exposant change). Pour ce faire, il faudrait recalculer un epsilon contextuellement précis en fonction de la valeur comparée. – numist

+0

@numist, en multipliant epsilon par 'max (fabs)' devrait donner la bonne grandeur, et l'argument ulp permet de donner des informations contextuelles sur l'erreur relative déjà accumulée. Si vous pensez toujours qu'il y a un problème, pourriez-vous en préciser la source? – AProgrammer

+0

Epsilon n'est pas proportionnel de façon continue. Avec le codage IEEE, epsilon est proportionnel à une valeur de manière discrète sur la base 2. http://stackoverflow.com/questions/5064377/c-comparing-two-floating-point-values/35536839#35536839 –

1

la différence entre X et la valeur suivante de XX varie en fonction.
DBL_EPSILON est seulement la différence entre 1 et la valeur suivante de 1.

Vous pouvez utiliser std::nextafter pour tester deux double avec une différence de epsilon:

bool nearly_equal(double a, double b) 
{ 
    return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b 
&& std::nextafter(a, std::numeric_limits<double>::max()) >= b; 
} 

Si vous souhaitez tester deux double avec une différence de facteur * epsilon, vous pouvez utiliser:

bool nearly_equal(double a, double b, int factor /* a factor of epsilon */) 
{ 
    double min_a = a - (a - std::nextafter(a, std::numeric_limits<double>::lowest())) * factor; 
    double max_a = a + (std::nextafter(a, std::numeric_limits<double>::max()) - a) * factor; 

    return min_a <= b && max_a >= b; 
}