Question

Ce code fonctionne (C # 3)

double d;
if(d == (double)(int)d) ...;
  1. Y a-t-il une meilleure façon de faire cela?
  2. Pour des raisons étrangères, je souhaite éviter le double casting de manière; Quelles bonnes manières existent-elles? (même s'ils ne sont pas aussi bons)

Remarque: Plusieurs personnes ont souligné le point (important) selon lequel == est souvent problématique pour le reclassement de la virgule flottante. Dans ce cas, je m'attends à des valeurs comprises entre 0 et quelques centaines et qui sont supposées être des entiers (les erreurs non-ententes sont des erreurs), donc si ces points & "Ne devraient pas &"; être un problème pour moi.

Était-ce utile?

La solution

d == Math.Floor(d)

fait la même chose en d'autres termes.

NB: J'espère que vous êtes conscient du fait que vous devez faire très attention lorsque vous faites ce genre de chose. floats / doubles accumulera très facilement des erreurs minuscules qui font que les comparaisons exactes (comme celle-ci) échouent sans raison évidente.

Autres conseils

Si votre double est le résultat d'un autre calcul, vous voulez probablement quelque chose comme:

d == Math.Floor(d + 0.00001);

Ainsi, s'il y a eu une légère erreur d'arrondi, elle sera toujours identique.

Cela fonctionnerait je pense:

if (d % 1 == 0) {
  //...
}

Je ne peux pas répondre à la partie de la question concernant le C #, mais je dois souligner que vous manquez probablement un problème générique lié aux nombres à virgule flottante.

En règle générale, l’intégrité n’est pas bien définie sur les flotteurs. Pour la même raison, l'égalité n'est pas bien définie sur les flotteurs. Les calculs en virgule flottante incluent normalement les erreurs d'arrondi et de représentation.

Par exemple, 1.1 + 0.6 != 1.7.

Oui, c'est juste la façon dont fonctionnent les nombres en virgule flottante.

Ici, 1.1 + 0.6 - 1.7 == 2.2204460492503131e-16.

À proprement parler, la comparaison la plus proche de l’égalité que vous pouvez faire avec des flottants est de les comparer à la précision choisie .

Si cela ne suffit pas, vous devez travailler avec une représentation en nombre décimal, avec une représentation en nombre à virgule flottante avec plage d'erreur intégrée ou avec des calculs symboliques.

Si vous voulez simplement le convertir, la réponse de Mike F / Khoth est bonne, mais ne répond pas tout à fait à votre question. Si vous voulez réellement tester, et c'est en fait important, je vous recommande d'implémenter quelque chose qui inclut une marge d'erreur.

Par exemple, si vous envisagez de dépenser de l'argent et que vous souhaitez tester des montants uniformes, vous pourriez dire (selon le modèle de Khoth):

if( Math.abs(d - Math.Floor(d + 0.001)) < 0.001)

En d’autres termes, prenez la valeur absolue de la différence entre la valeur et sa représentation sous forme d’entier et assurez-vous qu’elle est petite.

Vous n’avez pas besoin d’un extra (double). Cela fonctionne:

if (d == (int)d) {
 //...
}

Utilisez Math.Truncate ()

Mathématiquement, un test simple tel que 'x == floor (x)' fonctionne correctement, pour tout numéro de PF à précision fixe.

Tous les encodages de FP de précision fixe légaux représentent des nombres réels distincts. Ainsi, pour chaque entier x, il existe au plus un encodage de FP de précision fixe qui lui correspond exactement.

Par conséquent, pour chaque entier x pouvant être représenté ainsi, nous avons nécessairement x == floor (x), car floor (x) renvoie par définition le plus grand nombre FP y tel que y < = x et y représentent un entier; donc floor (x) doit renvoyer x.

Cela vous permettra de choisir la précision que vous recherchez, plus ou moins un demi-trait, pour tenir compte de la dérive en virgule flottante. La comparaison fait également partie intégrante, ce qui est agréable.

static void Main(string[] args)
{
    const int precision = 10000;

    foreach (var d in new[] { 2, 2.9, 2.001, 1.999, 1.99999999, 2.00000001 })
    {
        if ((int) (d*precision + .5)%precision == 0)
        {
            Console.WriteLine("{0} is an int", d);
        }
    }
}

et la sortie est

2 is an int
1.99999999 is an int
2.00000001 is an int

Quelque chose comme ça

double d = 4.0;
int i = 4;

bool equal = d.CompareTo(i) == 0; // true

Pourriez-vous utiliser ceci

    bool IsInt(double x)
    {
        try
        {
            int y = Int16.Parse(x.ToString());
            return true;
        }
        catch 
        {
            return false;
        }
    }

Pour gérer la précision du double ...

Math.Abs(d - Math.Floor(d)) <= double.Epsilon

Prenons le cas suivant où une valeur inférieure à double.Epsilon ne peut pas être comparée à zéro.

// number of possible rounds
const int rounds = 1;

// precision causes rounding up to double.Epsilon
double d = double.Epsilon*.75;

// due to the rounding this comparison fails
Console.WriteLine(d == Math.Floor(d));

// this comparison succeeds by accounting for the rounding
Console.WriteLine(Math.Abs(d - Math.Floor(d)) <= rounds*double.Epsilon);

// The difference is double.Epsilon, 4.940656458412465E-324
Console.WriteLine(Math.Abs(d - Math.Floor(d)).ToString("E15"));
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top