2009-09-08 10 views
5

मैं से Brainteasers:सी # में 15 अंकों की डबल टाइप परिशुद्धता नहीं थी?

 double d1 = 1.000001; 

     double d2 = 0.000001; 

     Console.WriteLine((d1 - d2) == 1.0); 

इस कोड का परीक्षण किया गया था और परिणाम "गलत" है। जब मैं डेटा प्रकार बदलता हूं:

 decimal d1 = 1.000001M; 

     decimal d2 = 0.000001M; 

     decimal d3 = d1-d2; 

     Console.WriteLine(d3 == 1); 

प्रोग्राम सही उत्तर लिखता है: "सत्य"।

यह समस्या केवल फ़्लोटिंग पॉइंट के बाद 6 अंकों का उपयोग करती है। 15 अंकों की परिशुद्धता के साथ क्या हुआ?

उत्तर

28

इसका सटीकता से कोई लेना-देना नहीं है - इसे प्रतिनिधित्वकारी गोल त्रुटियों के साथ करना है।

System.Decimal बड़े फ़्लोटिंग पॉइंट नंबरों का प्रतिनिधित्व करने में सक्षम है, जो कि आप देख रहे किसी भी गोलिंग त्रुटियों को करने में काफी कम जोखिम के साथ सक्षम हैं। System.Single और System.Double इस में सक्षम नहीं हैं और इन नंबरों को बंद कर देंगे और आपके उदाहरण में जो कुछ आप देख रहे हैं उसे बनाएं।

System.Decimal, दशमलव स्थान इस प्रकार दिया फ्लोटिंग प्वाइंट संख्या का सही प्रतिनिधित्व के लिए अनुमति देने का पद सँभालने जबकि System.Single और System.Double केवल अपने मूल्य के रूप में सबसे अच्छा वे कर सकते हैं अनुमानित एक स्केलिंग कारक उपयोग करता है।

अधिक जानकारी के लिए कृपया System.Double देखें:

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

  • दो फ्लोटिंग प्वाइंट संख्या है कि एक विशेष परिशुद्धता के लिए समान दिखाई देते हैं की तुलना नहीं कर सकता बराबर क्योंकि उनके कम से कम महत्वपूर्ण अंक अलग हैं।

  • एक गणितीय या तुलना आपरेशन एक फ्लोटिंग प्वाइंट संख्या एक ही परिणाम अगर एक दशमलव संख्या प्रयोग किया जाता है क्योंकि फ्लोटिंग प्वाइंट नंबर बिल्कुल दशमलव संख्या का अनुमान नहीं हो सकता है उपज नहीं हो सकता है का उपयोग करता है।

+0

http://msdn.microsoft.com/en-us/library/system.decimal.aspx "दशमलव प्रकार गोल करने की आवश्यकता को खत्म नहीं करता है। बल्कि, यह गोल करने के कारण त्रुटियों को कम करता है। उदाहरण के लिए, निम्नलिखित कोड 1 99 के बजाय 0.9 99 99 99 99 99 99 99 99 99 99 99 99 999 का परिणाम उत्पन्न करता है " –

+0

@quant_dev: काफी उचित है, मैंने अपना जवाब संपादित करने के लिए संपादित किया है :) –

+0

"सिस्टम। डेसिमल दशमलव स्थान की स्थिति को पकड़ने के लिए एक स्केलिंग कारक का उपयोग करता है, इस प्रकार किसी दिए गए फ़्लोटिंग-पॉइंट नंबर के सटीक प्रतिनिधित्व के लिए अनुमति देता है" - यह सच नहीं है; उदाहरण के लिए, 1/3 को न तो दोगुनी (जो बाइनरी बेस का उपयोग करते हैं) न ही दशमलव (जो दशमलव आधार का उपयोग करते हैं) द्वारा प्रदर्शित नहीं किया जा रहा है। वास्तव में, डबल और दशमलव के बीच एकमात्र अंतर आधार है, एक्सपोनेंट और महत्व के लिए आरक्षित बिट्स की संख्या, और क्या एक्सपोनेंट साइन बदल सकता है (हां के लिए हां, दशमलव के लिए नहीं)। इसके अलावा, वे समान हैं। सिस्टम। डेसिमल में मनमाने ढंग से सटीकता नहीं है! –

3

चल बिन्दु संख्या के विचार है कि वे अंक की एक विशेष नंबर के लिए सटीक नहीं हैं। यदि आप उस तरह की कार्यक्षमता चाहते हैं, तो आपको decimal डेटा प्रकार देखना चाहिए।

2

फ़्लोटिंग पॉइंट नंबरों के लिए समानता पर तुलना से बचें।

3

सटीक पूर्ण नहीं है, क्योंकि दशमलव और बाइनरी संख्याओं के बीच वास्तव में परिवर्तित करना संभव नहीं है।

इस मामले में, 1 दशमलव बाइनरी में प्रतिनिधित्व के लिए हमेशा के लिए दोहराना। यह .000110011001100110011 में परिवर्तित हो जाता है ... और हमेशा के लिए दोहराता है। परिशुद्धता की कोई मात्रा बिल्कुल स्टोर नहीं करेगी। कि डेटाप्रकार के लिए (एप्सिलॉन कहा जाता है)

8

आम तौर पर, फ्लोटिंग प्वाइंट मूल्यों की समानता के लिए जाँच करने के लिए जिस तरह से -equality के पास, जैसे कि, के लिए जाँच एक अंतर यह है कि सबसे छोटा मान के करीब है की जांच करने के लिए है। उदाहरण के लिए,

if (Math.Abs(d1 - d2) <= Double.Epsilon) ... 

यह देखें कि क्या d1 और d2 एक ही सा पैटर्न का प्रतिनिधित्व कर रहे दे या कम से कम महत्वपूर्ण बिट लेने के लिए परीक्षण करती है।

सुधार(जोड़ा गया 2 मार्च 2015)

आगे की जांच करने पर, कोड होना चाहिए इस तरह अधिक:

// Assumes that d1 and d2 are not both zero 
if (Math.Abs(d1 - d2)/Math.Max(Math.Abs(d1), Math.Abs(d2)) <= Double.Epsilon) ... 

दूसरे शब्दों में, d1 और d2 के बीच पूर्ण अंतर ले , उसके बाद इसे d1 और d2, और के बाद सबसे बड़े पैमाने पर स्केल करें, इसकी तुलना Epsilon से करें।

संदर्भ
http://msdn.microsoft.com/en-us/library/system.double.epsilon.aspx
http://msdn.microsoft.com/en-us/library/system.double.aspx#Precision

+0

था, अपने लिंक में, आप पढ़ सकते हैं कि ईपीएसलॉन सबसे छोटा सकारात्मक डबल है और यह मशीन ईपीएसलॉन के बराबर नहीं है, जो रिश्तेदार की ऊपरी सीमा का प्रतिनिधित्व करता है फ़्लोटिंग-पॉइंट अंकगणित में गोल करने के कारण त्रुटि। तो आपके द्वारा पोस्ट किए गए लिंक के साथ आपका उत्तर विरोधाभास क्यों है? – Nicolas

4

दशमलव प्रकार लागू दशमलव चल बिन्दु जबकि डबल द्विआधारी चल बिंदु है।

दशमलव का लाभ यह है कि यह गोल करने के संबंध में मानव के रूप में व्यवहार करता है, और यदि आप इसे दशमलव मान के साथ प्रारंभ करते हैं, तो उस मान को ठीक जैसा निर्दिष्ट किया गया है, संग्रहीत किया जाता है। यह केवल सीमित लंबाई की दशमलव संख्या के लिए और प्रतिनिधित्व योग्य सीमा और परिशुद्धता के भीतर सच है। यदि आपने इसे 1.0 एम/3.0 एम के साथ शुरू किया है, तो यह ठीक से संग्रहीत नहीं किया जाएगा जैसा कि आप पेपर पर 0.33333-आवर्ती लिखेंगे।

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

दशमलव प्रकार का प्राथमिक उद्देश्य नेट कार्यान्वयन यह भी डबल की तुलना में कहीं अधिक सटीक है में, वित्तीय अनुप्रयोगों लागू करने के लिए है, लेकिन द्विआधारी एफपी सीधे हार्डवेयर द्वारा समर्थित है तो दशमलव एफपी की तुलना में काफी तेजी से होता है संचालन।

ध्यान दें कि डबल लगभग 15 महत्वपूर्ण अंक नहीं 15 दशमलव स्थान है।d1 7 महत्वपूर्ण अंक मान 6 के साथ शुरू किया गया है, जबकि d2 केवल 1 महत्वपूर्ण अंक है। तथ्य यह है कि वे काफी भिन्न परिमाण के हैं या तो मदद नहीं करते हैं।

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