2012-05-23 15 views
8

निम्नलिखित कोड में, foo1, foo2 और foo3 फ़ंक्शन समकक्ष होने का इरादा रखते हैं। हालांकि जब foo3 को लूप से समाप्त नहीं किया जाता है, तो क्या ऐसा कोई कारण है?आईईईई -754 फ्लोटिंग पॉइंट कंप्यूटेशंस, समानता और संकुचित

template <typename T> 
T foo1() 
{ 
    T x = T(1); 
    T y = T(0); 
    for (;;) 
    { 
     if (x == y) break; 
     y = x; 
     ++x; 
    } 
    return x; 
} 

template <typename T> 
T foo2() 
{ 
    T x = T(0); 
    for (;;) 
    { 
     T y = x + T(1); 
     if (!(x != y)) break; 
     ++x; 
    } 
    return x; 
} 

template <typename T> 
T foo3() 
{ 
    T x = T(0); 
    while (x != (x + T(1))) ++x; 
    return x; 
} 

int main() 
{ 
    printf("1 float: %20.5f\n", foo1<float>()); 
    printf("2 float: %20.5f\n", foo2<float>()); 
    printf("3 float: %20.5f\n", foo3<float>()); 
    return 0; 
} 

नोट: यह/fp रिलीज़ मोड में सटीक के साथ VS2010 का उपयोग कर संकलित किया गया। सुनिश्चित नहीं है कि जीसीसी आदि इस कोड का इलाज कैसे करेंगे, कोई भी जानकारी बहुत अच्छी होगी। क्या यह एक मुद्दा हो सकता है जहां foo3 में, x और x + 1 मान किसी भी तरह NaN बन जाते हैं?

+3

दिलचस्प मुद्दा। सभी तीन कार्य जीसीसी 4.2.1 पर अपेक्षित के रूप में समाप्त हो जाते हैं। मैं इसे वीएस में एक बग कहने का लुत्फ उठा रहा हूं। – ComicSansMS

+3

हम्म। मेरे लिए एक अति उत्साही अनुकूलन (यानी, एक कंपाइलर बग) की तरह बदबू आ रही है। –

+2

@ मार्क डिकिंसन: वीएस -2010 –

उत्तर

13

निम्न होने की संभावना सबसे अधिक होती है। X86 आर्क पर, मध्यवर्ती गणना 80 बिट परिशुद्धता के साथ की जा सकती है (लंबी डबल संबंधित सी/सी ++ प्रकार है)। कंपाइलर (+1) ऑपरेशन के लिए और (! =) ऑपरेशन के लिए सभी 80 बिट्स का उपयोग करता है, लेकिन स्टोरेज से पहले परिणामों को छोटा करता है।

तो क्या अपने संकलक वास्तव में करता है यह है:

while ((long double)(x) != ((long double)(x) + (long double)(1))) { 
    x = (float)((long double)(x) + (long double)(1)); 
} 

यह बिल्कुल गैर आईईईई-अनुरूप है और हर किसी के लिए अंतहीन सिर दर्द का कारण बनता है, लेकिन इस MSVC के लिए डिफ़ॉल्ट है। इस व्यवहार को अक्षम करने के लिए /fp:strict कंपाइलर ध्वज का उपयोग करें।

यह लगभग 10 साल पहले की समस्या का मेरी याद है इसलिए कृपया मुझे माफ़ कर दो अगर यह किसी भी तरह से पूरी तरह से सही नहीं है। See this for the official Microsoft documentation

संपादित मैं बहुत कि जी ++ डिफ़ॉल्ट प्रदर्शन बिल्कुल वैसा ही व्यवहार से जानने के लिए हैरान था (i386 लिनक्स पर है, लेकिन साथ जैसे -mfpmath = SSE नहीं)।

+4

+1। 'लंबी डबल' की बजाय 'डबल' का उपयोग करना यहां समस्याएं पैदा करने के लिए पर्याप्त होगा, लेकिन आईआईआरसी एमएस अभी भी 64-बिट बिल्डों के लिए x87 एफपीयू का उपयोग करना पसंद करता है, इसलिए 'लंबी डबल' अधिक संभावना है। –

+1

उत्कृष्ट जवाब! धन्यवाद। –

+1

महान जानकार उत्तर लेकिन मुझे पता है कि VS2008 पर भी '/ fp: सख्त' foo3() के साथ अभी भी समाप्त नहीं होता है? – acraig5075

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