2010-10-18 25 views
6
void main() 
{ 
    float f = 0.98; 
    if(f <= 0.98) 
     printf("hi"); 
    else 
     printf("hello"); 
    getch(); 
} 

मुझे यह समस्या यहां मिल रही है। F के विभिन्न फ़्लोटिंग पॉइंट मानों का उपयोग करके मुझे अलग-अलग परिणाम मिल रहे हैं। यह क्यों हो रहा है?फ्लोटिंग पॉइंट तुलना में समस्याएं

+0

सामान्य नियम: क्या आप कभी भी 'सटीक' फैशन में फ़्लोटिंग-पॉइंट नंबरों की तुलना नहीं करते हैं। यह सिर्फ समझ में नहीं आता है। हमेशा कुछ 'ईपीएसलॉन' – valdo

+4

@ वाल्डो का उपयोग करें: यह अधिक व्यापक विश्लेषण के बिना आम तौर पर बुरी सलाह है। –

+0

'शून्य मुख्य()' गलत है। 'int मुख्य (शून्य)' सही है। –

उत्तर

3

ऐसा इसलिए है क्योंकि फ़्लोटिंग पॉइंट मान संख्या के सटीक प्रतिनिधित्व नहीं हैं। सभी आधार दस संख्याओं को कंप्यूटर पर आधार 2 संख्याओं के रूप में प्रदर्शित करने की आवश्यकता है। यह इस रूपांतरण में है कि परिशुद्धता गुम हो गई है।

एक एकल परिशुद्धता चल बिन्दु संख्या हम की जरूरत करने के लिए संख्या 1.1 परिवर्तित करने के लिए (मेरे VB6 दिनों में इस समस्या का सामना से) http://en.wikipedia.org/wiki/Floating_point


एक उदाहरण पर इस बारे में अधिक पढ़ें इसे बाइनरी में परिवर्तित करें। 32 बिट्स बनाए जाने की आवश्यकता है।

बिट 1 संकेत सा है (है यह नकारात्मक [1] या स्थिति [0]) बिट्स 2-9 अपूर्णांश लिए कर रहे हैं (उर्फ significand, मूल रूप से के गुणांक प्रतिपादक मूल्य बिट्स 10-32 के लिए कर रहे हैं वैज्ञानिक नोटेशन)

तो 1.1 के लिए एकल फ़्लोटिंग पॉइंट मान निम्नानुसार संग्रहीत किया जाता है (यह छोटा मूल्य है, संकलक दृश्यों के पीछे कम से कम महत्वपूर्ण बिट को गोल कर सकता है, लेकिन मैं जो कुछ करता हूं उसे छोटा कर देता है, जो थोड़ा कम सटीक है लेकिन इस उदाहरण के परिणाम नहीं बदलते हैं):

s --exp--- -------mantissa-------- 
0 01111111 00011001100110011001100 

यदि आप नहीं मंटिसा में बर्फ दोहराव पैटर्न 0011 है। बाइनरी में 1/10 दशमलव में 1/3 की तरह है। यह हमेशा के लिए चला जाता है। तो 32-बिट एकल परिशुद्धता फ़्लोटिंग पॉइंट मान से मूल्यों को पुनर्प्राप्त करने के लिए हमें पहले एक्सपोनेंट और मंटिसा को दशमलव संख्या में परिवर्तित करना होगा ताकि हम उनका उपयोग कर सकें। 01111111 = 127

अपूर्णांश: 00011001100110011001100 = 838,860

अपूर्णांश हम इसे एक दशमलव मान को बदलने की आवश्यकता के साथ

संकेत = 0 एक सकारात्मक संख्या

प्रतिपादक =। कारण यह है कि द्विआधारी संख्या (यानी 1.00011001100110011001100) से पहले एक अंतर्निहित पूर्णांक है। अंतर्निहित संख्या इसलिए है क्योंकि मंथिसा वैज्ञानिक संकेत में उपयोग किए जाने वाले सामान्यीकृत मान का प्रतिनिधित्व करता है: 1.0001100110011 .... * 2^(x-127)।

838860 से दशमलव मान प्राप्त करने के लिए हम बस 2^-23 से विभाजित होते हैं क्योंकि मंटिसा में 23 बिट्स हैं। यह हमें 0.0 99 999904632568359375 देता है। मंटिसा में उल्लिखित 1 जोड़ें हमें 1.0 99 999904632568359375 देता है। एक्सपोनेंट 127 है लेकिन सूत्र 2^(x-127) के लिए कॉल करता है।

(1 + 099999904632568359375) * 2^(127-127)

1,099999904632568359375 * 1 = 1,099999904632568359375

आप 1.1 देख सकते हैं वास्तव में में जमा नहीं किया जाता है:

तो यहाँ

गणित है 1.1 के रूप में एकल फ्लोटिंग बिंदु मान।

21

ffloat परिशुद्धता का उपयोग कर रहा है, लेकिन 0।98 double डिफ़ॉल्ट रूप से परिशुद्धता में है, इसलिए f <= 0.98 कथन double परिशुद्धता का उपयोग करके तुलना की जाती है।

f इसलिए तुलना में double में परिवर्तित किया गया है, लेकिन परिणाम 0.98 से थोड़ा बड़ा हो सकता है।

उपयोग

if(f <= 0.98f) 

या f बजाय के लिए एक double का उपयोग करें।


विस्तार में ... float संभालने IEEE single-precision और doubleIEEE double-precision है।

इस प्रकार के फ्लोटिंग पॉइंट नंबर बेस -2 प्रतिनिधित्व के साथ संग्रहीत किए जाते हैं। में आधार-2 के लिए इस नंबर एक अनंत परिशुद्धता की जरूरत है, क्योंकि यह एक दोहराया दशमलव है प्रतिनिधित्व करने के लिए:

0.98 = 0.1111101011100001010001111010111000010100011110101110000101000... 

एक float केवल महत्वपूर्ण आंकड़े के 24 बिट स्टोर कर सकते हैं

 0.111110101110000101000111_101... 
           ^round off here 
    = 0.111110101110000101001000 

    = 16441672/2^24 

    = 0.98000001907... 

एक double 53 स्टोर कर सकते हैं, यानी signficant आंकड़े के टुकड़े, इसलिए

 0.11111010111000010100011110101110000101000111101011100_00101000... 
                  ^round off here 
    = 0.11111010111000010100011110101110000101000111101011100 

    = 8827055269646172/2^53 

    = 0.97999999999999998224... 

तो 0.98 से थोड़ा 0,123,411 में float में बड़े और छोटे बन जाएगा।

+1

+1 अच्छा बिंदु, मेरे उत्तर से जो पूछ रहा है उसके करीब हो सकता है। – egrunin

+0

आपने मुझे इसे हराया! +1 – slezica

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