9

मैं इस सरल कोड लाइन है:फ्लोट वैरिएबल क्यों अजीब तरीके से बिंदुओं के बाद अंकों को काटकर मूल्य बचाता है?

float val = 123456.123456; 

जब मैं इस वैल प्रिंट या दायरे में देखो, यह संग्रहीत करता है मूल्य 123456,13

ठीक है, यह ठीक है, यह समय के बाद उन सभी अंक संग्रहीत नहीं कर सकता बस 4 बाइट्स में, लेकिन यह बिंदु के बाद 13 क्यों बनाता है? यह 12 नहीं होना चाहिए?

(Win32 पर कुलपति ++ 2010 एक्सप्रेस का उपयोग करते हुए)

+0

उत्तर के लिए सभी को धन्यवाद। अब मैं समझ गया। मैं बस इसे गोल करने के बजाय बिंदु के बाद असीमित अंक छोड़ना चाहिए। – Kosmos

उत्तर

7

जब एक फ्लोट के रूप में प्रतिनिधित्व किया जाता है, तो आपके नंबर में 16 का एक्सपोनेंट होता है (यानी मान इसका मंथिस समय 2^16, या 65536 है)। mantisse तो हो जाता है

123456.123456/65536 = 1.8837909462890625 

आदेश एक 32-बिट नाव में फिट करने के लिए, mantisse 23 बिट तक छोटा कर दिया गया है, इसलिए अब यह 1.883791 हो जाता है। जब 65536 द्वारा वापस गुणा किया गया, तो यह 123456.125 बन जाता है।

दशमलव बिंदु के बाद तीसरी स्थिति में 5 पर ध्यान दें: सी ++ की आउटपुट रूटीन जिसे आपने गोल किया है, जिससे आपका अंतिम नंबर 123456.13 जैसा दिखता है। द्विआधारी रूपांतरण के लिए (रिक रेगन की टिप्पणी)

पूर्णांकन (24 बिट के लिए) बाइनरी में पहली बार होता है, दशमलव में, और फिर दशमलव के लिए, printf में: राउंडिंग के

संपादित स्पष्टीकरण। संग्रहीत मूल्य 1.1110001001000000001 x 2^16 = 1.8837909698486328125 x 2^16 = 123456.125 है। यह 123456.13 के रूप में प्रिंट करता है, लेकिन केवल इसलिए कि विज़ुअल सी ++ "गोल से आधा दूर" गोलिंग का उपयोग करता है।

रिक में outstanding article on the subject भी है।

यदि आप अन्य नंबरों और उनके फ्लोट प्रस्तुतियों के साथ खेलना चाहते हैं, तो यहां एक very useful IEEE-754 calculator है।

+0

क्या आप कृपया थोड़ा और समझ सकते हैं .. मैं विशेष रूप से इस पंक्ति को समझने में सक्षम नहीं था "जब फ्लोट के रूप में प्रतिनिधित्व किया जाता है, तो आपके नंबर में 16 का एक्सपोनेंट होता है" । इसकी आवश्यकता क्यों है? –

+0

@RasmiRanjanNayak 32-बिट फ्लोट को 23 बिट मैंटिस, सात-बिट बाइनरी एक्सपोनेंट और एक साइन बिट के रूप में दर्शाया गया है। तर्कसंगत रूप से, आप अपने मूल संख्या को दो से विभाजित करते हैं और एक्सपोनेंट को बढ़ाते हैं जब तक कि दशमलव बिंदु के सामने केवल शेष अंक '1' न हो। '123456.123456' के लिए, 16 डिवीजनों की आवश्यकता है। – dasblinkenlight

+3

@dasblinkenlight सबसे अच्छा यह विवरण भ्रामक है। गोलाकार द्विआधारी (24 बिट्स) में, दशमलव में बाइनरी रूपांतरण के लिए, और फिर दशमलव में, printf में होता है। संग्रहीत मूल्य 1.1110001001000000001 x 2^16 = 1.8837909698486328125 x 2^16 = 123456.125 है। यह 123456.13 के रूप में प्रिंट करता है, लेकिन केवल इसलिए कि विज़ुअल सी ++ "शून्य से राउंड आधा दूर" राउंडिंग का उपयोग करता है (मेरा आलेख देखें http://www.exploringbinary.com/inconsistent-rounding-of-printed-floating-point-numbers/।) –

2

std::numeric_limits<float>::digits10 का मूल्य मुद्रण का प्रयास करें। यह मोटे तौर पर बोल रहा है कि आधार 10 में कितनी सटीकता है। आप इसे पार करने की कोशिश कर रहे हैं, इसलिए आप परिशुद्धता का नुकसान अनुभव कर रहे हैं (जिसका अर्थ है कि महत्वपूर्ण लोगों से परे अंक वास्तव में सार्थक नहीं हैं)।

उदा। देखें What is the meaning of numeric_limits<double>::digits10

2

यह पूरी तरह से संकलक निर्भर है। इसे जीसीसी में देखें। यह xxx.12

+5

यदि आंतरिक रूप से उपयोग किया जाने वाला प्रारूप आईईईई -754 है तो यह संकलक-निर्भर नहीं होना चाहिए। –

+0

जांचें http://steve.hollasch.net/cgindex/coding/ieeefloat.html –

+0

मुझे लगता है कि हम "कंपाइलर-निर्भर" दो अलग-अलग अर्थ दे रहे हैं; मैं क्या - और दूसरों - समझ गया कि आप कह रहे हैं कि "यह सामान्य है कि यह कंपाइलर से कंपाइलर में भिन्न होता है"। क्या आप इसके बजाए कह रहे हैं कि यह एक * कंपाइलर-विशिष्ट बग * है? –

8

val में संग्रहीत मान 123456.125 के बराबर होना चाहिए। आप .13 हो रही है क्योंकि आप इसे गोलाई रहे हैं:

float val = 123456.123456; 
printf("%.4f %.2f\n", val, val); 

उत्पादन: 123456.1250 123456.13

आप इस मामले में डबल का उपयोग करना चाहिए काट-छांट से बचने के लिए। कंपाइलर को आपको चेतावनी भी देनी चाहिए: "चेतावनी C4305: 'प्रारंभ करना': 'डबल' से 'फ्लोट' तक छंटनी"

10

बाइनरी में, 123456.123456 11110001001000000.000111111001 ... (अनंत) है। यह 11110001001000000.001, या 123456.125 तक चलता है। मुद्रित होने पर राउंड 123456.13 तक।

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

  • कोई संबंधित समस्या नहीं^_^