Double.Epsilon pour l'égalité, supérieure, inférieure, inférieur ou égal, supérieur ou égal à

StackOverflow https://stackoverflow.com/questions/2411392

  •  18-09-2019
  •  | 
  •  

Question

http://msdn.microsoft.com/en- nous / bibliothèque / system.double.epsilon.aspx

  

Si vous créez un algorithme personnalisé   détermine si deux virgule flottante   les chiffres peuvent être considérés comme égaux, vous   doit utiliser une valeur qui est supérieure à   la constante Epsilon pour établir la   marge absolue acceptable de   la différence des deux valeurs à   considérés comme égaux. (En règle générale, que   La marge de différence est plusieurs fois   supérieure à Epsilon).

Alors, est-ce pas vraiment un epsilon qui pourrait être utilisé pour les comparaisons? Je ne comprends pas vraiment le libellé MSDN.

Peut-il être utilisé comme epsilon dans les exemples ici? - Quel est le moyen le plus efficace pour float et double comparaison

Et enfin, cela semble vraiment important que je voudrais donc me assurer que j'ai une solide mise en œuvre pour l'égalité, supérieure, inférieure, inférieure ou égale et supérieure ou égale à.

Était-ce utile?

La solution

Je ne sais pas ce ils ont été de fumer quand ils ont écrit cela. Double.Epsilon est la plus petite valeur à virgule flottante non représentable denormal qui n'est pas 0. Tout ce que vous savez est que, s'il y a une erreur de troncature, il sera toujours plus que cette valeur. Beaucoup plus grande.

Le type de System.Double peut représenter des valeurs précises jusqu'à 15 chiffres. Donc, d'une simple première estimation de la commande si un x double valeur est égale à une constante d'utiliser un epsilon de constante * 1E-15

public static bool AboutEqual(double x, double y) {
    double epsilon = Math.Max(Math.Abs(x), Math.Abs(y)) * 1E-15;
    return Math.Abs(x - y) <= epsilon;
}

Vous devez faire attention cependant, les erreurs de troncature peuvent accumuler. Si les deux x et y sont calculées les valeurs alors vous devez augmenter la epsilon.

Autres conseils

  

Je voudrais vous assurer que j'ai une solide mise en œuvre pour l'égalité, supérieure, inférieure, inférieure ou égale et supérieure ou égale à.

Vous utilisez l'arithmétique binaire à virgule flottante.

arithmétique binaire à virgule flottante a été conçu pour représenter des quantités physiques comme la longueur, la masse, la charge, le temps, et ainsi de suite.

On peut supposer que vous utilisez l'arithmétique binaire en virgule flottante comme il a été conçu pour être utilisé. Pour effectuer des opérations arithmétiques sur les quantités physiques

Les mesures de grandeurs physiques ont toujours une précision particulière, en fonction de la précision du dispositif utilisé pour les mesurer.

Puisque vous êtes celui qui fournit les valeurs pour les quantités que vous manipulez, vous êtes celui qui sait ce que les « barres d'erreur » sont sur cette quantité. Par exemple, si vous fournissez la quantité « la hauteur du bâtiment est 123.56 mètres » alors vous savez que cela est exact au centimètre près, mais pas au micromètre.

Par conséquent, lorsque l'on compare deux grandeurs d'égalité, la sémantique désirée est-à-dire « sont ces deux quantités égales dans les barres d'erreur spécifiées par chaque mesure? »

Alors maintenant, nous avons une réponse à votre question. Ce que vous devez faire est de garder une trace de ce que l'erreur est sur chaque quantité; par exemple, la hauteur du bâtiment est « dans 0,01 de 123.56 mètres » parce que vous savez comment la mesure est précise. Si vous obtenez alors une autre mesure qui est 123,5587 et que vous voulez savoir si les deux mesures sont « égaux » dans les tolérances d'erreur, puis faites la soustraction et voir si elle tombe dans la tolérance d'erreur. Dans ce cas, il le fait. Si les mesures étaient en fait précis à l'micrométrique, ils ne sont pas égaux.

En bref: vous êtes la seule personne ici qui sait ce que les tolérances d'erreur sont sensibles, parce que vous êtes la seule personne qui sait où les chiffres que vous manipulez provenaient en premier lieu. Utilisez ce que la tolérance d'erreur est logique pour vos mesures compte tenu de la précision de l'équipement utilisé pour le produire.

Si vous avez deux valeurs doubles qui sont proches de 1,0, mais ils ne diffèrent que leurs bits les moins significatifs, la différence entre eux sera de plusieurs ordres de grandeur supérieure à Double.Epsilon. En fait, la différence est de 324 ordres décimaux de grandeur. Ceci est dû à l'effet de la partie exposant. Double.Epsilon a un grand exposant négatif sur elle, tandis que 1,0 a un exposant de zéro (après les biais sont retirés, bien sûr).

Si vous voulez comparer deux valeurs similaires pour l'égalité, vous devrez choisir une valeur epsilon personnalisée qui convient à l'ordre de grandeur taille des valeurs à comparer.

Si les doubles valeurs que vous comparez sont près de 1.0. Ensuite, la valeur du bit siginificant serait près ,0000000000000001. Si les doubles valeurs que vous comparez sont les quadrillions, la valeur du bit le moins significatif pourrait être autant que mille. Aucune valeur unique pour epsilon pourrait être utilisé pour des comparaisons d'égalité dans ces deux circonstances.

Je viens de faire cela -. Utilisant idée Kent Bogarts

private bool IsApproximatelyEqual(double x, double y, double acceptableVariance)
{
     double variance = x > y ? x - y : y - x;
     return variance < acceptableVariance;

     //or
     //return Math.Abs(x - y) < acceptableVariance;
}

Il pourrait être utilisé pour les comparaisons, en supposant que vous voulez vous assurer que les deux valeurs sont soit exactement égales, ou ont la plus petite différence représentable pour le type double. D'une manière générale, vous souhaitez utiliser un plus grand nombre de double.Epsilon pour vérifier si deux doubles sont à peu près égale.

Pourquoi le framework .NET ne définit pas quelque chose comme

bool IsApproximatelyEqual(double value, double permittedVariance);

est au-delà de moi.

Je pense que les bits pertinents dans le lien MSDN vous avez publié sont les suivants:

  

Cependant, la propriété Epsilon n'est pas un   mesure générale de précision du   Type Double; il ne s'applique qu'aux Double   des cas qui ont une valeur de zéro.

     

Note: La valeur de l'Epsilon   la propriété ne correspond pas à la machine   epsilon, qui représente la partie supérieure   lié de l'erreur relative due à   arrondi en arithmétique à virgule flottante.

     

Cette valeur est pas définie comme le plus petit   nombre positif x, de telle sorte que x + 1,0   est pas égal à 1,0, de sorte Double.Epsilon   ne peut pas être utilisé pour « presque égalité ».   Il existe pas constant dans la   cadre dont la valeur est la plus petite   nombre positif x, de telle sorte que x + 1,0   est pas égal à 1,0.

Je dois dire, ça me surprend. Moi aussi, je l'avais supposé que Double.Epsilon était l'équivalent de DBL_EPSILON en c / c ++ - clairement pas!

D'après ce que je peux lire de ce lien, il semble dire « vous devez comprendre une valeur décente pour vous-même des comparaisons » qui est assez surprenant de dire le moins.
Peut-être quelqu'un peut plus knowledgable préciser:)

J'utilise les éléments suivants

public static class MathUtil {
    /// <summary>
    /// smallest such that 1.0+EpsilonF != 1.0
    /// </summary>
    public const float EpsilonF = 1.192092896e-07F;

    /// <summary>
    /// smallest such that 1.0+EpsilonD != 1.0
    /// </summary>
    public const double EpsilonD = 2.2204460492503131e-016;

    [MethodImpl( MethodImplOptions.AggressiveInlining )]
    public static bool IsZero( this double value ) {
        return value < EpsilonD && value > -EpsilonD;
    }

    [MethodImpl( MethodImplOptions.AggressiveInlining )]
    public static int Sign( this double value ) {
        if ( value < -EpsilonD ) {
            return -1;
        }
        if ( value > EpsilonD )
            return 1;
        return 0;
    }

et si vous voulez vérifier l'égalité de deux doubles a 'et « b », vous pouvez utiliser

(a-b).IsZero();

et si vous voulez obtenir le résultat de la comparaison, utilisez

(a-b).Sign();

Le problème est que l'on compare double lorsque vous faites une comparaison entre deux résultats mathématiques différents qui sont égaux, mais qui, en raison d'erreurs d'arrondi, ne sont pas l'évaluation à la même valeur, ils auront une certaine différence ... qui est plus grand que epsilon, à l'exception des cas de pointe. Et en utilisant une valeur epsilon fiable est également difficile. Certaines personnes considèrent que deux doubles égaux si la différence entre eux est inférieure à une valeur de pourcentage, puisque l'utilisation d'un epsilon de différence minimale statique peut signifier vos différences sont trop petites ou grandes lorsque la double lui-même est élevé ou faible.

Voici un code qui inclus deux fois dans le Silverlight Control Toolkit:

    public static bool AreClose(double value1, double value2)
    {
        //in case they are Infinities (then epsilon check does not work)
        if(value1 == value2) return true;
        // This computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON
        double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON;
        double delta = value1 - value2;
        return(-eps < delta) && (eps > delta);
    }

Dans un endroit où ils utilisent 1e-6 pour epsilon; dans un autre, ils utilisent 1.192093E-07. Vous voulez choisir votre propre epsilon.

Il n'y a pas d'autre choix que vous devez calculer vous-même ou définir votre propre constante.

double calculateMachineEpsilon() {
    double result = 1.0;
    double one = 1.0/256;

    while(one + result/2.0 != 1.0) {
        result/=2.0;
    }
    return result;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top