Les opérations en virgule flottante C#/.NET diffèrent-elles en précision entre le mode débogage et le mode déverrouillage?Float/double précision dans les modes débogage/déverrouillage
Répondre
Ils peuvent en effet être différent. Selon la spécification ECMA CLR:
emplacements de stockage pour virgule flottante nombres (statique, éléments de tableau, et domaines de classes) sont de taille fixe. Les tailles de stockage prises en charge sont float32 et float64. Partout ailleurs (sur la pile d'évaluation, en tant qu'arguments , en tant que types de retour, et en tant que variables locales ) les nombres en virgule flottante sont représentés en utilisant un type à virgule flottante interne . Dans chaque exemple , le type nominal de la variable ou expression est R4 ou R8, mais sa valeur peut être représentée en interne avec plage supplémentaire et/ou précision. La taille de la représentation interne à virgule flottante dépend de l'implémentation, peut varier, et doit avoir une précision au moins égale à comme celle de l'expression variable ou étant représentée. Une conversion d'élargissement implicite à la représentation interne de float32 ou float64 est effectuée lorsque ces types sont chargés depuis le stockage. La représentation interne est généralement la taille native pour le matériel, ou comme requis pour la mise en œuvre efficace d'une opération.
Ce que cela signifie essentiellement est que la comparaison suivante peut ou peut ne pas être égale:
class Foo
{
double _v = ...;
void Bar()
{
double v = _v;
if(v == _v)
{
// Code may or may not execute here.
// _v is 64-bit.
// v could be either 64-bit (debug) or 80-bit (release) or something else (future?).
}
}
}
message à emporter: ne jamais vérifier les valeurs flottantes pour l'égalité.
Cela n'a rien à voir avec les configurations de construction DEBUG vs RELEASE ... –
L'IL généré sera le même ... mais le JITter est moins agressif lorsqu'il s'agit d'un assemblage marqué comme débogage. Les versions release ont tendance à déplacer plus de valeurs flottantes dans des registres de 80 bits; Les versions de débogage ont tendance à lire directement à partir du stockage de mémoire 64 bits. – stusmith
L'IL générée peut ne pas être la même chose. Le mode débogage insère des sauts dans des endroits pour s'assurer qu'un point d'arrêt est possible, il peut également délibérément maintenir une variable temporaire que le mode de libération juge inutile. – ShuggyCoUk
Ils devraient être identiques. Les nombres à virgule flottante sont basés sur IEEE_754 standard.
En fait, ils peuvent différer si le mode de débogage utilise la FPU x87 et le mode de libération utilise SSE pour les opérations flottantes.
Avez-vous une référence ou une démonstration faisant autorité? –
En réponse à la demande de Frank Krueger ci-dessus (dans les commentaires) pour une démonstration d'une différence:
Compile ce code dans gcc sans optimisations et -mfpmath = 387 (je n'ai aucune raison de penser que ce ne serait pas travailler sur d'autres compilateurs, mais je ne l'ai pas essayé.) Puis le compiler sans optimisations et -msse -mfpmath = sse.
La sortie sera différente.
#include <stdio.h>
int main()
{
float e = 0.000000001;
float f[3] = {33810340466158.90625,276553805316035.1875,10413022032824338432.0};
f[0] = pow(f[0],2-e); f[1] = pow(f[1],2+e); f[2] = pow(f[2],-2-e);
printf("%s\n",f);
return 0;
}
La question portait sur C# /. Net; Votre exemple est pour C++/code natif. –
D'une manière ou d'une autre, je doute que la précision de SSE vs x87 FPU diffère en fonction de la langue que vous l'appelez! –
Une traduction directe en C# présente également des résultats différents pour les x86 et x64 dans Visual Studio 2013. Notez que le CLR x86 utilise x87 FPU alors que le CLR x64 utilise SSE. – Asik
Merci les gars j'ai trouvé quelques articles ce que dit ce qui en fait le comportement des flotteurs sera différent en mode release
http://blogs.msdn.com/davidnotario/archive/2005/08/08/449092.aspx
C'est une question intéressante, j'ai donc fait un peu d'expérimentation.J'ai utilisé ce code:
static void Main (string [] args)
{
float
a = float.MaxValue/3.0f,
b = a * a;
if (a * a < b)
{
Console.WriteLine ("Less");
}
else
{
Console.WriteLine ("GreaterEqual");
}
}
utilisant DevStudio 2005 et .Net 2. Je compilé à la fois comme le débogage et la libération et la sortie du examinai du compilateur:
Release Debug
static void Main (string [] args) static void Main (string [] args)
{ {
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,3Ch
00000009 xor eax,eax
0000000b mov dword ptr [ebp-10h],eax
0000000e xor eax,eax
00000010 mov dword ptr [ebp-1Ch],eax
00000013 mov dword ptr [ebp-3Ch],ecx
00000016 cmp dword ptr ds:[00A2853Ch],0
0000001d je 00000024
0000001f call 793B716F
00000024 fldz
00000026 fstp dword ptr [ebp-40h]
00000029 fldz
0000002b fstp dword ptr [ebp-44h]
0000002e xor esi,esi
00000030 nop
float float
a = float.MaxValue/3.0f, a = float.MaxValue/3.0f,
00000000 sub esp,0Ch 00000031 mov dword ptr [ebp-40h],7EAAAAAAh
00000003 mov dword ptr [esp],ecx
00000006 cmp dword ptr ds:[00A2853Ch],0
0000000d je 00000014
0000000f call 793B716F
00000014 fldz
00000016 fstp dword ptr [esp+4]
0000001a fldz
0000001c fstp dword ptr [esp+8]
00000020 mov dword ptr [esp+4],7EAAAAAAh
b = a * a; b = a * a;
00000028 fld dword ptr [esp+4] 00000038 fld dword ptr [ebp-40h]
0000002c fmul st,st(0) 0000003b fmul st,st(0)
0000002e fstp dword ptr [esp+8] 0000003d fstp dword ptr [ebp-44h]
if (a * a < b) if (a * a < b)
00000032 fld dword ptr [esp+4] 00000040 fld dword ptr [ebp-40h]
00000036 fmul st,st(0) 00000043 fmul st,st(0)
00000038 fld dword ptr [esp+8] 00000045 fld dword ptr [ebp-44h]
0000003c fcomip st,st(1) 00000048 fcomip st,st(1)
0000003e fstp st(0) 0000004a fstp st(0)
00000040 jp 00000054 0000004c jp 00000052
00000042 jbe 00000054 0000004e ja 00000056
00000050 jmp 00000052
00000052 xor eax,eax
00000054 jmp 0000005B
00000056 mov eax,1
0000005b test eax,eax
0000005d sete al
00000060 movzx eax,al
00000063 mov esi,eax
00000065 test esi,esi
00000067 jne 0000007A
{ {
Console.WriteLine ("Less"); 00000069 nop
00000044 mov ecx,dword ptr ds:[0239307Ch] Console.WriteLine ("Less");
0000004a call 78678B7C 0000006a mov ecx,dword ptr ds:[0239307Ch]
0000004f nop 00000070 call 78678B7C
00000050 add esp,0Ch 00000075 nop
00000053 ret }
} 00000076 nop
else 00000077 nop
{ 00000078 jmp 00000088
Console.WriteLine ("GreaterEqual"); else
00000054 mov ecx,dword ptr ds:[02393080h] {
0000005a call 78678B7C 0000007a nop
} Console.WriteLine ("GreaterEqual");
} 0000007b mov ecx,dword ptr ds:[02393080h]
00000081 call 78678B7C
00000086 nop
}
Ce que les spectacles ci-dessus est que le flottant Le code de point est le même pour le débogage et la publication, le compilateur choisit la cohérence plutôt que l'optimisation. Bien que le programme produise le mauvais résultat (a * a n'est pas inférieur à b), il est le même quel que soit le mode de débogage/relâchement.
Maintenant, Intel IA32 FPU dispose de huit registres à virgule flottante, on pourrait penser que le compilateur utiliserait les registres pour stocker des valeurs lors de l'optimisation plutôt que d'écrire à la mémoire, améliorant ainsi la performance, quelque chose le long des lignes de:
fld dword ptr [a] ; precomputed value stored in ram == float.MaxValue/3.0f
fmul st,st(0) ; b = a * a
; no store to ram, keep b in FPU
fld dword ptr [a]
fmul st,st(0)
fcomi st,st(0) ; a*a compared to b
mais cela s'exécuterait différemment à la version de débogage (dans ce cas, afficher le résultat correct). Cependant, changer le comportement du programme en fonction des options de compilation est une très mauvaise chose.
Le code FPU est l'un des domaines où l'élaboration manuelle du code peut surpasser de manière significative le compilateur, mais vous avez besoin de comprendre le fonctionnement du FPU.
- 1. Que signifient les modes de fusion dans pygame?
- 2. Accolade électrique intelligente dans les modes cc (C#, Java, etc.)
- 3. Un modèle XSL peut-il correspondre dans les modes * ALL *?
- 4. Précision maintenant() dans VBScript
- 5. Quels sont les différents modes de remplissage et modes de chiffrement dans IPhone pour le chiffrement AES?
- 6. Différences entre les modes Visual Studio (Général, Web Dev, C#)?
- 7. Comment lister les modes vidéo disponibles en utilisant C#?
- 8. Quelle est la précision de la précision CLLocation?
- 9. Adresse de recherche inversée de l'API Google Maps Précision Précision
- 10. Opérations mathématiques à simple précision dans .NET?
- 11. Précision des résultats TextRenderer.MeasureText
- 12. Python: haute précision time.sleep
- 13. précision à virgule flottante
- 14. Précision de mtime stat dans Windows
- 15. Poignée différence de précision dans Oracle
- 16. Différents modes de disposition pour WindowsForms
- 17. gcc bogue de précision?
- 18. rails précision et échelle décimales
- 19. Pourcentage avec une précision variable
- 20. Précision de ZHEEV et ZHEEVD
- 21. SQL Server apporte une précision supplémentaire pour les flottants?
- 22. wpf - afficher, mettre à jour, insérer des modes
- 23. Gestion d'un projet d'application Web avec plusieurs modes de visualisation
- 24. Websphere 6.1 - Précision des fichiers jsp
- 25. ASP.NET MVC: meilleur moyen d'activer différents modes d'authentification?
- 26. Comment modifier la précision d'une colonne décimale dans Sql Server?
- 27. Quelle est la précision de scheduleAtFixedRate?
- 28. Comment faire pour horodater les journaux de requête avec une précision d'une milliseconde dans Apache 2.0
- 29. Datetime avec millisecondes dans SAS: nombres de précision les plus élevés de nulle part
- 30. Visual Studio: raccourci clavier pour basculer entre les modes Debug et Release
Pourquoi pensez-vous qu'ils diffèrent? –
Oui, je suis intéressé à découvrir votre processus de pensée aussi. –
La question concerne la différence entre le débogage et la libération. On pourrait penser que la version de sortie utiliserait des registres plutôt que de la RAM qui serait plus précise: FPU = 80bit, double = 64bit, float = 32bit. – Skizz