2008-09-18 22 views
12

क्या सी #/.NET फ्लोटिंग पॉइंट ऑपरेशंस डीबग मोड और रिलीज़ मोड के बीच सटीकता में भिन्न है?डीबग/रिलीज मोड में फ्लोट/डबल परिशुद्धता

+0

आपको क्यों लगता है कि वे भिन्न हैं? –

+0

हां, मुझे आपकी विचार प्रक्रिया को भी ढूंढने में दिलचस्पी है। –

+0

प्रश्न डीबग और रिलीज के बीच के अंतर के बारे में है। आपको लगता है कि रिलीज संस्करण रैम के बजाए रजिस्टरों का उपयोग करेगा जो उच्च परिशुद्धता होगा: एफपीयू = 80 बिट, डबल = 64 बिट, फ्लोट = 32 बिट। – Skizz

उत्तर

21

वे वास्तव में अलग हो सकता है में अलग होगा कहते हैं लेख की एक जोड़ी मिल गया। CLR ECMA विनिर्देश के अनुसार: फ्लोटिंग प्वाइंट संख्या के लिए

भंडारण स्थानों (स्टैटिक्स, सरणी तत्वों, और वर्गों के क्षेत्रों) निश्चित आकार के हैं। समर्थित स्टोरेज आकार float32 और float64 हैं। हर जगह (मूल्यांकन स्टैक पर, तर्क, प्रकार के रूप में, और स्थानीय चर के रूप में) फ़्लोटिंग-पॉइंट संख्याओं को आंतरिक फ़्लोटिंग-पॉइंट प्रकार का उपयोग करके दर्शाया जाता है। प्रत्येक इस तरह के उदाहरण में, नाममात्र या अभिव्यक्ति का नाममात्र प्रकार या तो R4 या R8 है, लेकिन इसके मान को आंतरिक रूप से और/या परिशुद्धता के साथ आंतरिक रूप से प्रदर्शित किया जा सकता है। आंतरिक फ़्लोटिंग-पॉइंट प्रतिनिधित्व कार्यान्वयन-निर्भर है, भिन्न हो सकता है और कम से कम वैरिएबल या अभिव्यक्ति का प्रतिनिधित्व करने के रूप में सटीक होगा। फ्लोर 32 या फ्लोट 64 से आंतरिक प्रतिनिधित्व प्रकारों से भंडारण से लोड होने पर आंतरिक अंतर्निहित रूपांतरण में अंतर्निहित विस्तृत रूपांतरण किया जाता है। आंतरिक प्रतिनिधित्व आमतौर पर हार्डवेयर के मूल आकार, या कुशल ऑपरेशन के लिए कार्यान्वयन के लिए आवश्यक है।

क्या यह मूल रूप से इसका मतलब है कि निम्नलिखित तुलना या बराबर नहीं हो सकता है:

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?). 
    } 
    } 
} 

टेक-घर संदेश: समानता के लिए चल मूल्यों की जाँच कभी नहीं।

+0

डेबग बनाम रिलीज कॉन्फ़िगरेशन के साथ ऐसा करने के लिए कुछ भी नहीं है ... –

+2

आईएल जेनरेट किया गया वही होगा ... लेकिन डीबग के रूप में चिह्नित असेंबली से निपटने पर जिटर कम आक्रामक है। रिलीज बिल्ड में 80-बिट रजिस्टरों में अधिक फ़्लोटिंग मानों को स्थानांतरित करना होता है; डिबग बिल्ड 64-बिट मेमोरी स्टोरेज से सीधे पढ़ते हैं। – stusmith

+0

उत्पन्न आईएल एक जैसा नहीं हो सकता है। डीबग मोड स्थानों को एक ब्रेकपॉइंट सुनिश्चित करने के लिए जगहों पर रोकता है, यह जानबूझकर अस्थायी चर को बनाए रख सकता है कि रिलीज मोड अनावश्यक मानता है। टेक-होम संदेश के लिए – ShuggyCoUk

0

वे वही होना चाहिए। फ़्लोटिंग पॉइंट नंबर IEEE_754 standard पर आधारित हैं।

2

वास्तव में, यदि डीबग मोड x87 एफपीयू का उपयोग करता है और रिलीज मोड फ्लोट-ऑप्स के लिए एसएसई का उपयोग करता है तो वे भिन्न हो सकते हैं।

+1

क्या आपके पास आधिकारिक संदर्भ या प्रदर्शन है? –

0

एक अंतर का एक प्रदर्शन के लिए ऊपर (टिप्पणी में) फ्रैंक ईद्भूजर के अनुरोध के जवाब में:

कोई अनुकूलन के साथ जीसीसी में इस कोड को संकलित करें और -mfpmath = 387 (मैं इसे सोचने के लिए कोई कारण नहीं है नहीं होगा अन्य कंपाइलर्स पर काम करें, लेकिन मैंने कोशिश नहीं की है।) फिर इसे अनुकूलन के साथ संकलित करें और -msse -mfpmath = sse।

आउटपुट अलग-अलग होगा।

#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; 
} 
+1

प्रश्न सी #/नेट के बारे में था; आपका उदाहरण सी ++/मूल कोड के लिए है। –

+1

किसी भी तरह मुझे संदेह है कि एसएसई बनाम x87 एफपीयू की सटीकता उस भाषा के आधार पर अलग है जिसे आप इसे कहते हैं! –

+0

सी # के लिए सीधा अनुवाद विजुअल स्टूडियो 2013 में x86 और x64 के लिए अलग-अलग परिणाम दिखाता है। ध्यान दें कि x86 सीएलआर x87 एफपीयू का उपयोग करता है जबकि x64 CLR एसएसई का उपयोग करता है। – Asik

11

यह एक दिलचस्प सवाल है, इसलिए मैंने थोड़ा प्रयोग किया।

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"); 
    } 
} 

DevStudio 2005 और नेट 2. मैं का उपयोग कर दोनों डिबग के रूप में संकलित और जारी करने और संकलक के उत्पादन की जांच की:: मैं इस कोड का इस्तेमाल किया

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    
                   } 

क्या ऊपर से पता चलता है कि अस्थायी है पॉइंट कोड डीबग और रिलीज दोनों के लिए समान है, संकलक ऑप्टिमाइज़ेशन पर स्थिरता चुन रहा है। हालांकि कार्यक्रम गलत परिणाम उत्पन्न करता है (ए * ए बी से कम नहीं है) यह डीबग/रिलीज मोड के बावजूद समान है।

अब, इंटेल IA32 एफपीयू आठ चल बिन्दु रजिस्टरों है, तो आपको लगता होगा कि संकलक जब बजाय के अनुकूलन स्मृति के लिए लिख, इस प्रकार के प्रदर्शन, की तर्ज पर कुछ सुधार लाने की दुकान मूल्यों के रजिस्टरों का प्रयोग करेंगे:

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 

लेकिन यह डीबग संस्करण के लिए अलग-अलग निष्पादित होगा (इस मामले में, सही परिणाम प्रदर्शित करें)। हालांकि, निर्माण विकल्पों के आधार पर कार्यक्रम के व्यवहार को बदलना एक बहुत ही बुरी चीज है।

एफपीयू कोड एक ऐसा क्षेत्र है जहां कोड को क्राफ्ट करने से हाथ कंप्रेसर को काफी हद तक निष्पादित कर सकता है, लेकिन आपको एफपीयू काम करने के तरीके के आसपास अपना सिर प्राप्त करने की आवश्यकता है।

संबंधित मुद्दे