2009-12-08 18 views
2

Folks,Comparer les doublons dans Visual Studio - un moyen standard pour attraper cela?

Même les programmeurs expérimentés écrivent du code C# comme celui-ci parfois:

double x = 2.5; 
double y = 3; 
if (x + 0.5 == 3) { 
    // this will never be executed 
} 

Fondamentalement, il est de notoriété publique que deux doubles (ou flotteurs) ne peuvent jamais être exactement égale à l'autre, à cause de la manière l'ordinateur gère l'arithmétique à virgule flottante. Le problème, c'est que tout le monde le sait, mais le code comme celui-ci est toujours partout. C'est tellement facile à oublier.

Questions pour vous:

  • Comment avez-vous traité dans votre organisation de développement?
  • Est-ce une chose si commune que le compilateur devrait vérifier que nous devrions tous crier vraiment fort pour VS2010 d'inclure un avertissement de compilation si quelqu'un compare deux doubles/flotteurs?

MISE À JOUR: Folks, merci pour les commentaires. Je tiens à préciser que je comprends très certainement que le code ci-dessus est incorrect. Oui, vous ne voulez jamais == comparer les doubles et les flotteurs. Au lieu de cela, vous devez utiliser la comparaison basée sur epsilon. Cela est évident. La vraie question ici est «comment cerner le problème» et non «comment résoudre le problème technique».

+1

Vous avez choisi * un autre * mauvais exemple. Encore une fois, cela sera toujours exécuté. Je suggère que lorsque vous choisissez votre prochain exemple, vous l'essayiez avant de poster ... –

+1

(Et vous pourriez vouloir supprimer l'affirmation erronée que "deux doubles ne peuvent jamais être exactement égaux les uns aux autres" aussi. prétendre que quelque chose est "de notoriété publique" et prétendre que vous comprenez réellement tout cela, il vaudrait la peine de vérifier tout ce que vous écrivez pour vous assurer qu'il est exact. " –

+1

En effet, si les nombres à virgule flottante ne peuvent JAMAIS être exactement égaux, il serait probablement plus facile parce que tous les développeurs seraient au courant du problème –

Répondre

3

valeurs à virgule flottante certainement peuvent être égaux entre eux, et dans le cas où vous avez donné ils ont toujours seront égaux. Vous devriez presque ne jamais comparer pour l'égalité en utilisant des égaux, mais vous devez comprendre pourquoi - et pourquoi l'exemple que vous avez montré n'est pas approprié.

Je ne pense pas que ce soit quelque chose que le compilateur devrait nécessairement mettre en garde, mais vous voudrez peut-être voir si c'est quelque chose que FxCop peut saisir. Je ne peux pas le voir dans le warning list, mais il peut être là quelque part ...

Personnellement, je suis raisonnablement confiant que les développeurs compétents seraient en mesure de repérer cela dans l'examen du code, mais cela dépend de vous avoir un révision de code en place pour commencer. Elle repose également sur vos développeurs de savoir quand utiliser double et quand utiliser decimal, ce qui est quelque chose que j'ai trouvé est souvent le cas ...

+1

Je voudrais +1 pour le point (sans jeu de mots) sur la décimale - mais j'ai upvoted :-) – philsquared

+0

Il y avait une règle dans FxCop appelée " Évitez de tester l'égalité en virgule flottante ", mais il a été supprimé il y a un moment. http://social.msdn.microsoft.com/Forums/is/vstscode/thread/339dc258-2928-476f-92ba-784cb04b7863 – kristianp

2
static int _yes = 0; 
static int _no = 0; 

static void Main(string[] args) 
{ 
    for (int i = 0; i < 1000000; i++) 
    { 
     double x = 1; 
     double y = 2; 
     if (y - 1 == x) 
     { 
      _yes++; 
     } 
     else 
     { 
      _no++; 
     } 
    } 
    Console.WriteLine("Yes: " + _yes); 
    Console.WriteLine("No: " + _no); 
    Console.Read(); 
} 

Sortie

Oui: 1000000

No: 0

+0

LOL :) 15 caractères – Amarghosh

+0

Fine, fine, fine. Le point reste. Je vais éditer mon code. –

2

Dans notre organisation nous avons beaucoup de calculs financiers et nous n'utilisons pas float et double pour ces tâches. Nous utilisons Decimal dans .NET, BigDecimal dans Java et Numeric dans MSSQL pour éviter les erreurs d'arrondi.

Cet article décrit le problème: What Every CS Should Know About floating-Point Arithmetic

+0

Je suis bien conscient de la solution au problème. Ce que je demande, c'est "comment mieux le repérer", pas "comment le résoudre". –

+0

OK. J'ai réécrit ma réponse. –

1

Si FxCop ou similaire (comme Jon l'indique) ne fonctionne pas pour vous une approche plus lourde main pourrait être prendre une copie du code - remplacer tous instances de float ou double avec une classe que vous avez écrit qui est quelque peu similaire à System.Double, sauf que vous surchargez le == operator pour générer un avertissement!

Je ne sais pas si cela est possible dans la pratique que je ne l'ai pas essayé - mais laissez-nous savoir si vous essayez :-)

0

Mono Gendarme est un outil de semblable FxCop. Il a une règle appelée AvoidFloatingPointEqualityRule dans la catégorie Correctness. Vous pouvez essayer de trouver des occurrences de cette erreur dans votre code. Je ne l'ai pas utilisé, mais il devrait analyser régulièrement. NET dll. La règle FxCop avec le même nom a été supprimée il y a longtemps.