सबसे पहले, अस्थायी बिंदु मान उनके व्यवहार में "यादृच्छिक" नहीं हैं। सटीक तुलना कर सकते हैं और वास्तविक दुनिया के उपयोग के बहुत सारे में समझ में आता है। लेकिन अगर आप फ़्लोटिंग पॉइंट का उपयोग करने जा रहे हैं, तो आपको यह जानने की ज़रूरत है कि यह कैसे काम करता है। फ्लोटिंग पॉइंट काम करने की ओर से वास्तविक संख्याओं की तरह काम करने से आपको कोड मिलेगा जो जल्दी टूट जाता है। फ़्लोटिंग पॉइंट परिणाम मानने के पक्ष में उनके साथ बड़े यादृच्छिक फ़ज़ हैं (जैसे कि यहां अधिकांश उत्तर सुझाते हैं) आपको कोड मिलेगा जो पहले काम करता है, लेकिन बड़े-परिमाण त्रुटियों और टूटे हुए कोने के मामलों को समाप्त करता है।
सबसे पहले, यदि आप फ्लोटिंग पॉइंट के साथ प्रोग्राम करना चाहते हैं, तो आपको इसे पढ़ना चाहिए:
फ्लोटिंग-पॉइंट अंकगणित के बारे में हर कंप्यूटर वैज्ञानिक को क्या जानना चाहिए
हाँ, यह सब पढ़ें। यदि यह बहुत अधिक बोझ है, तो आपको अपनी गणना के लिए पूर्णांक / निश्चित बिंदु का उपयोग करना चाहिए जब तक कि आपके पास इसे पढ़ने के लिए समय न हो। :-)
अब, कहा गया है कि, सटीक फ़्लोटिंग पॉइंट तुलना के साथ सबसे बड़े मुद्दे नीचे आते हैं:
तथ्य यह है कि बहुत सारे मूल्य आप स्रोत में लिख सकते हैं, या साथ पढ़ सकते हैं scanf
या strtod
, अस्थायी बिंदु मानों के रूप में मौजूद नहीं हैं और चुपचाप निकटतम सन्निकटन में परिवर्तित हो जाते हैं। यह वही है जो dem9733 के जवाब के बारे में बात कर रहा था।
तथ्य यह है कि वास्तविक परिणाम का प्रतिनिधित्व करने के लिए पर्याप्त सटीकता नहीं होने के कारण कई परिणाम गोल हो जाते हैं। एक आसान उदाहरण जहां आप देख सकते हैं कि यह जोड़ रहा है x = 0x1fffffe
और y = 1
तैरता है। यहां, x
मंटिसा (ओके) में 24 बिट्स की सटीकता है और y
सिर्फ 1 बिट है, लेकिन जब आप उन्हें जोड़ते हैं, तो उनके बिट्स ओवरलैपिंग स्थानों में नहीं होते हैं, और परिणाम में 25 बिट्स सटीक की आवश्यकता होती है। इसके बजाय, यह गोल हो जाता है ( 0x2000000
डिफ़ॉल्ट राउंडिंग मोड में)।
तथ्य यह है कि कई परिणाम सही मूल्य के लिए असीम रूप से कई स्थानों की आवश्यकता के कारण गोल हो जाते हैं। इसमें 1/3 (जैसे कि आप दशमलव से परिचित हैं, जहां यह कई स्थानों पर होता है) जैसे दोनों तर्कसंगत परिणाम शामिल हैं, लेकिन यह भी 1/10 (जो कि बाइनरी में भी कई जगह लेता है, क्योंकि 5 में 2 की शक्ति नहीं है) किसी भी वर्ग के मूल की तरह तर्कहीन परिणाम जैसे कि एक पूर्ण वर्ग नहीं है।
दोहरा गोलाई। कुछ प्रणालियों (विशेष रूप से x86) पर, अस्थायी बिंदु अभिव्यक्तियों का मूल्यांकन उनके नाममात्र प्रकारों की तुलना में उच्च परिशुद्धता में किया जाता है। इसका मतलब यह है कि जब उपरोक्त प्रकार के राउंडिंग में से एक होता है, तो आपको दो राउंडिंग चरण मिलेंगे, पहले परिणाम का एक राउंडिंग उच्च-सटीक प्रकार, फिर अंतिम प्रकार के लिए एक राउंडिंग। एक उदाहरण के रूप में, विचार करें कि दशमलव में क्या होता है यदि आप 1.49 पूर्णांक (1) के पास होते हैं, बनाम क्या होता है यदि आप इसे पहले एक दशमलव स्थान (1.5) पर गोल करते हैं तो उस परिणाम को पूर्णांक (2) के रूप में गोल करते हैं। यह वास्तव में फ्लोटिंग पॉइंट से निपटने के लिए सबसे निचले क्षेत्रों में से एक है, क्योंकि कंपाइलर का व्यवहार (विशेष रूप से छोटी गाड़ी के लिए, जीसीसी जैसी गैर-अनुरूपता वाले कंपाइलर) अप्रत्याशित है।
ट्रान्सेंडैंटल कार्य ( trig
, exp
, log
, आदि) सही ढंग से गोल परिणाम के लिए निर्दिष्ट नहीं हैं; परिणाम केवल सटीक के अंतिम स्थान में एक इकाई के भीतर सही होने के लिए निर्दिष्ट है (आमतौर पर 1ulp के रूप में संदर्भित )।
जब आप फ़्लोटिंग पॉइंट कोड लिख रहे हों, तो आपको यह ध्यान रखना होगा कि आप उन नंबरों के साथ क्या कर रहे हैं जो परिणाम को अक्षम कर सकते हैं और तदनुसार तुलना कर सकते हैं। अक्सर बार यह एक "एप्सिलॉन" के साथ तुलना करने के लिए समझ में आता है, लेकिन यह एप्सिलॉन उन संख्याओं के परिमाण पर आधारित होना चाहिए जो आप तुलना कर रहे हैं , न कि निरपेक्ष स्थिर। (ऐसे मामलों में जहां निरपेक्ष स्थिर एप्सिलॉन काम करेगा, यह दृढ़ता से संकेत देता है कि फिक्स्ड पॉइंट, फ़्लोटिंग पॉइंट नहीं, नौकरी के लिए सही उपकरण है!)
संपादित करें: विशेष रूप से, परिमाण-सापेक्ष एप्सिलॉन जांच कुछ इस तरह दिखनी चाहिए:
if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y))
कहाँ FLT_EPSILON
से स्थिर है float.h
(के साथ बदलने DBL_EPSILON
के लिए double
या LDBL_EPSILON
के लिए long double
) और K
एक निरंतर आप इस तरह है कि आपके संगणना के संचित त्रुटि निश्चित रूप से से घिरा है चुनें है K
अंतिम स्थान पर इकाइयों (और यदि आप सुनिश्चित नहीं हैं कि आप त्रुटि मिली बाध्य गणना सही है, K
जो आपकी गणना कहती है उससे कुछ गुना बड़ा करें)।
अंत में, ध्यान दें कि यदि आप इसका उपयोग करते हैं, तो शून्य के पास कुछ विशेष देखभाल की आवश्यकता हो सकती है, क्योंकि FLT_EPSILON
denormals के लिए कोई मतलब नहीं है। इसे बनाने के लिए एक त्वरित सुधार होगा:
if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y) || fabs(x-y) < FLT_MIN)
और इसी तरह DBL_MIN
डबल्स का उपयोग करने पर विकल्प ।
fabs(x+y)
समस्याग्रस्त है अगर (x
औरy
) अलग संकेत हो सकता है। फिर भी, कार्गो-पंथ की तुलना के ज्वार के खिलाफ एक अच्छा जवाब।