Je vois quelque chose d'étrange de stocker des doubles dans un dictionnaire et je suis confus pourquoi.
Voici le code: p> La seconde si la déclaration fonctionne comme attendu; 1.0 n'est pas inférieur à 1,0. Maintenant, la première instruction si la déclaration est évaluée comme vraie. La chose très étrange est que lorsque je survole sur le si, l'IntelliSense me dit faux, mais le code se déplace joyeusement à la console.writeline. P> Ceci est pour C # 3.5 dans Visual Studio 2008. P > est-ce un problème de précision de point flottant? Alors pourquoi la seconde si la déclaration fonctionne-t-elle? Je pense que je manque quelque chose de très fondamental ici. P> Toute perspicacité est appréciée. P> Je peux accepter le problème de précision des mathématiques, mais ma question est la suivante: pourquoi la survolte-t-elle à l'évaluation correctement? Ceci est également vrai de la fenêtre immédiate. Je colle le code de la première instruction IF dans la fenêtre immédiate et qu'il évalue false. P> update strong> p> Tout d'abord pour tous les De grandes réponses. p> J'ai aussi des problèmes de recréer cela dans un autre projet sur la même machine. En regardant les paramètres du projet, je ne vois aucune différence. En regardant l'IL entre les projets, je ne vois aucune différence. En regardant le démontage, je ne vois aucune différence apparente (en plus des adresses de mémoire). Pourtant, quand j'ai débogué le projet d'origine, je vois:
La fenêtre immédiate me dit que le cas échéant est faux, mais le code tombe dans le conditionnel. P> En tout cas, la meilleure réponse, je pense, est de préparer l'arithmétique à virgule flottante dans ces situations. La raison pour laquelle je ne pouvais pas laisser cela aller a plus à voir avec les calculs du débogueur différant de l'heure d'exécution. Donc, merci beaucoup à Brian Gideon et Stephentyrone pour des commentaires très perspicaces. P> P>
p>
4 Réponses :
C'est un problème de précision flottant.
Deuxième instruction fonctionne car le compilateur compte l'expression 1e-3 * 1e3 avant d'émettre le .exe. p>
Regarde-le dans l'ildasme / réflecteur, il émettra quelque chose comme p>
Étrange. La deuxième déclaration est complètement optimisée par le compilateur pour moi. Je ne suis pas encore convaincu que ceci est une question de précision de points flottant de toute façon. Voir ma réponse.
+1. D'accord, je ne peux pas reproduire le problème qu'aucun "torte" n'est écrit à la console.
Vs indique même que le contenu du second s'il est inaccessible.
umm ... étrange. Je ne suis pas capable de reproduire votre problème. J'utilise également C # 3.5 et Visual Studio 2008. J'ai tapé dans votre exemple exactement em> comme il a été posté et je ne vois pas non plus En outre, la deuxième instruction s'ils sont optimisées par le compilateur. Lorsque j'examine les bâtiments de débogage et de libération dans l'ildas / réflecteur, je ne vois aucune preuve de celui-ci. Cela fait depuis que je reçois un avertissement de compilateur indiquant que le code inaccessible a été détecté dessus. P>
Enfin, je ne vois pas comment cela pourrait être un problème de précision de point flottant de toute façon. Pourquoi le compilateur C # évaluerait-il statiquement deux doubles différemment que le CLR au fil de l'exécution? Si c'était vraiment le cas, alors on pourrait faire l'argument selon lequel le compilateur C # a un bogue. P>
EDIT: strong> Après avoir donné cela un peu plus pensé, je suis encore plus convaincu que ceci est console.writeline code> instruction exécutée. P>
Merci beaucoup Brian pour l'entrée; Mon collègue dans la salle voit la même chose sur sa machine. Windows XP sur Dell Optuplex 320, Pentium D 3.4 GHz.
Quelle version de vs avez-vous? La boîte de dialogue À propos indique 9.0.30729.1 pour moi. J'utilise également .NET Framework 3.5 avec SP 1. Aussi, vérifiez également que vous ciblez le cadre 3.5 lors de la construction de l'application. Il semble que quelque chose d'inhabituel se produise certainement.
Le problème ici est assez subtil. Le compilateur C # n'émet pas (toujours) code émetteur qui fait le calcul en double, même lorsque c'est le type que vous avez spécifié. En particulier, il émet un code qui effectue le calcul de la précision "étendue" à l'aide des instructions x87, sans arrondir les résultats intermédiaires au double. P>
Selon si 1E-3 est évalué sous forme de double ou de double double, et si la multiplication est calculée en double ou long double, il est possible d'obtenir l'un des trois résultats suivants: p>
Clairement, la première comparaison, celle qui ne doit pas satisfaire à vos attentes est en cours d'évaluation de la manière décrite dans le troisième scénario que j'ai énuméré. 1e-3 est arrondi pour doubler soit parce que vous le stockez et que vous le chargez à nouveau, ce qui oblige l'arrondi, ou parce que c # reconnaît 1E-3 comme littéral à double précision et le traite de cette façon. La multiplication est en cours d'évaluation en double double parce que C # a un modèle numérique mort-mort Strike> C'est la façon dont le compilateur génère le code. P>
La multiplication de la deuxième comparaison est soit évaluée à l'aide de l'une des deux autres méthodes (vous pouvez déterminer qui en essayant "1> 1e-3 * 1e3"), ou le compilateur arrondit le résultat de la multiplication Avant de le comparer avec 1,0 lorsqu'il évalue l'expression au moment de la compilation. P>
Il est probablement possible de dire au compilateur de ne pas utiliser de précision étendue sans que vous le disiez via un paramètre de construction; L'activation de CodeGen à SSE2 peut également fonctionner. P>
Perspective intéressante. Je ne vois aucun paramètre de compilation qui concerne cette question, je n'ai découvert aucun que je pouvais changer cela m'a permis de reproduire le problème. Si tel est vraiment le problème, il semblerait que ce soit dans le compilateur JIT car c'est ce qui émet des instructions de la machine. Mais, si tel est le cas, c'est sûrement un bug. Après, avoir un programme dont l'exécution est nondeterminalistique par conception est terriblement dérangeant.
C'est (malheureusement) l'un des modes d'évaluation autorisés pour le point flottant par la norme C99. Je ne sais pas si la spécification C # épine la sémantique de manière plus attentive, mais je serais surpris. Sur une machine X86 qui ne met pas en œuvre les instructions SSE2, c'est le seul moyen performant de faire des calculs à double précision (la variante consiste à stocker les résultats après chaque étape du calcul, qui détruit absolument la performance). Je ne sais pas si l'OP a une telle machine, ou si c # soutient de telles machines, mais c'est certainement une possibilité
Yup, c'est autorisé en C # aussi; La référence de MS dit: "Les opérations à virgule flottante peuvent être effectuées avec une précision plus élevée que le type de résultat de l'opération. Par exemple, certaines architectures matérielles prennent en charge un type de point flottant" étendu "ou" long double "avec une plus grande plage et une plus grande précision que le Double type et exécutent implicitement toutes les opérations de point flottant en utilisant ce type de précision plus élevé. "
Très intéressant en effet! C'est certainement un bon plomb. Je dois admettre que si cela s'avère être la cause de l'échantillon de l'OP exécutant différemment sur différentes architectures de la CPU, je vais être choqués. Mais j'ai vu des choses étranges alors qui sait!
+1. Excellente réponse. Cela pourrait expliquer pourquoi les autres ont été incapables de reproduire le problème.
"1E3" est-il une constante de flottante ou une double constante?
Si vous pouvez accepter le problème de précision des mathématiques, pourquoi vous demandez-vous toujours? Le problème est que 1E-3 ne peut pas être représenté avec précision, et donc 1E3 * 1e-3 n'est pas 1,0, c'est quelque chose de fermeture, mais pas tout à fait, ce qui signifie qu'il échoue.
"1E3" est compilé comme un double parce que je vois l'instruction LDC.R8 dans ma sortie IL.
@Lasse: j'accepte pourquoi cela se passe pendant l'exécution; Je me demande pourquoi mon débogueur (la fenêtre intermédiaire et intermédiaire) me donne des réponses différentes que le temps d'exécution.
@John: Quand je survole sur le 1E3, il dit que c'est un double.
WOW, belle capture d'écran du problème. C'est vraiment bizarre.