2009-12-03 16 views
11

आज सुबह मेरे पास एक छोटा डब्ल्यूटीएफ क्षण था। चौथाई WTF इस के साथ संक्षेप किया जा सकता है:फ्लोट अतिरिक्त डबल को बढ़ावा दिया?

float x = 0.2f; 
float y = 0.1f; 
float z = x + y; 
assert(z == x + y); //This assert is triggered! (Atleast with visual studio 2008) 

कारण है कि अभिव्यक्ति x + y दोगुना करने के लिए प्रोत्साहित किया और z में छोटा संस्करण के साथ तुलना की जाती है लगता है। (यदि मैं z से double बदलता हूं तो जोर ट्रिगर नहीं किया जाता है)।

मैं देख सकता हूं कि सटीक कारणों से यह परिणाम को एक परिशुद्धता में परिवर्तित करने से पहले डबल परिशुद्धता में सभी फ़्लोटिंग पॉइंट अंकगणित करने के लिए समझ में आता है। मुझे मानक में निम्नलिखित पैराग्राफ मिला (जो मुझे लगता है कि मुझे पहले से ही पता था, लेकिन इस संदर्भ में नहीं):

4.6.1। "प्रकार float का एक rvalue प्रकार double के एक rvalue करने के लिए परिवर्तित किया जा सकता है। मूल्य अपरिवर्तित है"

मेरा प्रश्न है, x + y गारंटी है दोगुना करने के लिए बढ़ावा दिया जा करने के लिए या संकलक के विवेक पर है?

अद्यतन: कई लोगों ने दावा किया है के बाद से है कि एक चल बिन्दु के लिए == उपयोग नहीं करना चाहिए, मैं सिर्फ राज्य के लिए कि विशेष मामले के साथ मैं काम कर रहा हूँ में, एक सटीक तुलना उचित है चाहता था।

फ़्लोटिंग पॉइंट तुलना मुश्किल है, इस विषय पर एक दिलचस्प link है जो मुझे लगता है कि उल्लेख नहीं किया गया है।

+0

तुम भी कोशिश कर सकते हैं "सिर्फ मनोरंजन के लिए" द्वारा एफपीयू पर एक सटीक गणना के लिए मजबूर करने कॉलिंग: _controlfp (_PC_24, MCW_PC); – MaR

उत्तर

14

आप आम तौर पर यह नहीं मान सकते कि == फ्लोटिंग पॉइंट प्रकारों के लिए अपेक्षित काम करेगा। गोलाकार मूल्यों की तुलना करें या इसके बजाय abs(a-b) < tolerance जैसी संरचनाओं का उपयोग करें।

प्रचार पूरी तरह से संकलक के विवेकाधिकार पर है (और लक्ष्य हार्डवेयर, अनुकूलन स्तर, आदि पर निर्भर करेगा)।

इस विशेष मामले में क्या चल रहा है यह निश्चित रूप से निश्चित रूप से है कि एफपीयू रजिस्टरों में मूल्य स्मृति की तुलना में उच्च परिशुद्धता पर संग्रहीत होते हैं - सामान्य रूप से, आधुनिक एफपीयू हार्डवेयर आंतरिक या डबल परिशुद्धता के साथ आंतरिक रूप से काम करता है जो प्रोग्रामर के लिए जो भी सटीकता मांगता है मानकों को स्मृति में संग्रहीत करते समय उचित रूपांतरण करने के लिए संकलक उत्पन्न कोड; एक अप्रत्याशित निर्माण में, x+y का परिणाम अभी भी एक रजिस्टर में है, लेकिन तुलना में z को स्मृति में संग्रहीत किया जाएगा और वापस लाया जाएगा, और इस प्रकार परिशुद्धता को तैरने के लिए छोटा कर दिया जाएगा।

+2

सामान्य मामले में मैं या तो फ्लोट के लिए == का उपयोग नहीं करता, लेकिन वास्तविक मामले में मैं परेशानी में भाग गया था, मैं केवल एक बहुत ही विशिष्ट क्रम में जोड़ रहा हूं। अगर मैं कोड को फ्लोट (x + y) में बदलता हूं तो == ऑपरेटर के साथ कोई समस्या नहीं है। –

+0

8087 <- 80387 8087 से बहुत विकसित नहीं हुआ। – jsbueno

+1

@Andreas: हाँ, तो आप गोलाकार मूल्यों की तुलना कर रहे हैं :) – moonshadow

8

Working draft for the next standard C++0x खंड 5 बिंदु 11

चल ऑपरेंड और अस्थायी भाव के परिणामों के मूल्यों अधिक स्पष्टता और प्रकार के लिए आवश्यक है कि तुलना में रेंज में प्रस्तुत किया जा सकता कहते हैं; प्रकार

तो संकलक के विवेकाधिकार पर नहीं बदला जाता है।

0

मुझे लगता है कि यह कंपाइलर के विवेकाधिकार पर होगा, लेकिन अगर आप सोच रहे थे तो आप इसे हमेशा एक कलाकार के साथ मजबूर कर सकते थे?

1

जीसीसी 4.3.2 का उपयोग करना, अभिकथन नहीं शुरू हो रहा है, और वास्तव में, rvalue x + y से लौटे एक float बल्कि एक double से है।

तो यह संकलक पर निर्भर है। यही कारण है कि दो फ़्लोटिंग पॉइंट मानों के बीच सटीक समानता पर भरोसा करना कभी बुद्धिमान नहीं होता है।

-1

फिर भी एक और कारण फ्लोट की तुलना कभी नहीं करता है।

if (fabs(result - expectedResult) < 0.00001) 
1

यह समस्या है क्योंकि बाइनरी रूपांतरण के लिए फ्लोट संख्या सटीक सटीकता नहीं देती है।

और sizeof(float) बाइट्स के भीतर यह फ्लोट नंबर और अंकगणितीय संचालन के सटीक मूल्य को समायोजित नहीं कर सकता है, जिससे अनुमान लगाया जा सकता है और इसलिए समानता विफल हो जाती है।

नीचे देखें उदा।

float x = 0.25f; //both fits within 4 bytes with precision 
float y = 0.50f; 
float z = x + y; 
assert(z == x + y); // it would work fine and no assert 
संबंधित मुद्दे