2009-03-30 13 views
7

निम्नलिखित सी # कोड पर विचार करें में कई युगल जोड़ने राउंडिंग प्रभावित करता है? बात यह है, यह नहीं है। परिणाम 1 3.3 है और परिणाम 2 3.3000000000000003 है। केवल अंतर ही स्थिरांक का क्रम है।क्यों आदेश जब सी #

मुझे पता है कि युगल इस तरह से लागू किए गए हैं कि गोल करने वाले मुद्दे हो सकते हैं। मुझे पता है कि अगर मुझे पूर्ण परिशुद्धता की आवश्यकता है तो मैं decimals का उपयोग कर सकते हैं। या मैं अपने अगर कथन में Math.Round() का उपयोग कर सकता हूं। मैं सिर्फ एक बेवकूफ़ हूं जो समझना चाहता हूं कि सी # कंपाइलर क्या कर रहा है। क्या कोई मुझे बता सकता है?

संपादित करें:

हर किसी के लिए धन्यवाद है जो अब तक चल बिन्दु गणित पर पढ़ने का सुझाव दिया और/या की कैसे सीपीयू युगल संभालती निहित अशुद्धि के बारे में बात की थी। लेकिन मुझे लगता है कि मेरे प्रश्न का मुख्य जोर अभी भी अनुत्तरित है। इसे सही तरीके से phrasing नहीं करने के लिए मेरी गलती कौन सा है। मुझे इसे इस तरह रखते हैं:

नीचे से ऊपर कोड को तोड़ने, मैं उम्मीद करेंगे निम्न कार्रवाई हो रहा हो रहे हैं:

double r1 = 1.1 + 1.2; 
double r2 = 1.0 + r1 
double r3 = 1.0 + 1.1 
double r4 = 1.2 + r3 

मान लेते हैं कि ऊपर अतिरिक्त में से प्रत्येक के एक गोलाई त्रुटि (गिने E1 था करते हैं। ।ई 4)। तो आर 1 में गोलाकार त्रुटि ई 1 है, आर 2 में गोलाकार त्रुटियां शामिल हैं ई 1 + ई 2, आर 3 में ई 3 और आर 4 में ई 3 + ई 4 शामिल है।

अब, मुझे नहीं पता कि राउंडिंग त्रुटियां कैसा चलती हैं लेकिन मैं ई 1 + ई 2 के बराबर ई 3 + ई 4 की अपेक्षा करता। स्पष्ट रूप से यह नहीं है, लेकिन ऐसा लगता है कि यह मेरे लिए गलत है। एक और बात यह है कि जब मैं उपरोक्त कोड चलाता हूं, तो मुझे कोई गोल करने वाली त्रुटियां नहीं मिलती हैं। यही कारण है कि मुझे लगता है कि यह सी # कंपाइलर है जो सीपीयू की बजाय अजीब कुछ कर रहा है।

मुझे पता है कि मैं बहुत कुछ पूछ रहा हूं और शायद सबसे अच्छा जवाब देने वाला कोई भी सीपीयू डिज़ाइन में पीएचडी करना है, लेकिन मैंने सोचा कि मैं पूछूंगा।

संपादित 2

अपने मूल कोड नमूने से आईएल को देखते हुए, यह स्पष्ट है कि यह संकलक सीपीयू नहीं कि ऐसा है:

.method private hidebysig static void Main(string[] args) cil managed 
{ 
.entrypoint 
    .maxstack 1 
    .locals init (
     [0] float64 result1, 
     [1] float64 result2) 
    L_0000: nop 
    L_0001: ldc.r8 3.3 
    L_000a: stloc.0 
    L_000b: ldc.r8 3.3000000000000003 
    L_0014: stloc.1 
    L_0015: ret 
} 

संकलक के लिए संख्या को जोड़कर किया जाता है मुझे!

उत्तर

10

मैं बराबर E3 + E4 को ई 1 + e2 अपेक्षा की होगी।

floor(5/3) + floor(2/3 + 1) 

उम्मीद

floor(5/3 + 2/3) + floor(1) 

बराबर करने के लिए छोड़कर आप मंजिल लेने से पहले 2^53 से गुणा कर रहे हैं के विपरीत पूरी तरह से नहीं है यही कारण है कि।

12 बिट परिशुद्धता चल बिन्दु और काट-छांट अपने मूल्यों के साथ उपयोग करना:

 
1.0   = 1.00000000000 
1.1   = 1.00011001100 
1.2   = 1.00110011001 

1.0 + 1.1  = 10.00011001100 // extended during sum 
r1 = 1.0 + 1.1 = 10.0001100110 // truncated to 12 bit 
r1 + 1.2  = 11.01001100101 // extended during sum 
r2 = r1 + 1.2 = 11.0100110010 // truncated to 12 bit 

1.1 + 1.2  = 10.01001100110 // extended during sum 
r3 = 1.1 + 1.2 = 10.0100110011 // truncated to 12 bit 
r3 + 1.0  = 11.01001100110 // extended during sum 
r4 = r3 + 1.0 = 11.0100110011 // truncated to 12 bit 

तो आपरेशन के आदेश को बदलने/truncations त्रुटि बदलने के लिए कारण बनता है, और r4 = r2!। यदि आप इस प्रणाली में 1.1 और 1.2 जोड़ते हैं, तो अंतिम बिट होता है, इसलिए छंटनी पर खो नहीं जाता है। यदि आप 1.1 से 1.1 जोड़ते हैं, तो 1.1 का अंतिम बिट खो गया है और इसलिए परिणाम समान नहीं है।

एक क्रम में, गोलाकार (छिड़काव) पीछे पीछे 1 हटा देता है।

दूसरे क्रम में, गोलाकार 0 दोनों बार पीछे हटता है।

कोई शून्य के बराबर नहीं है; इसलिए त्रुटियां समान नहीं हैं।

डबल्स में परिशुद्धता के कई और बिट हैं, और सी # संभवतः छंटनी के बजाए गोल करने का उपयोग करता है, लेकिन उम्मीद है कि यह सरल मॉडल आपको दिखाता है कि एक ही मूल्य के विभिन्न क्रमों के साथ अलग-अलग त्रुटियां हो सकती हैं।

एफपी और गणित के बीच का अंतर यह है कि + जोड़ने के बजाय 'जोड़ने के बाद राउंड' के लिए शॉर्टेंड है।

+0

+1 अच्छा ठोस उदाहरण – bobince

+0

उदाहरण अच्छा है, लेकिन आपने मूल कोड की तुलना में संचालन के क्रम को बदल दिया है। ओपी ने पहले संपादन में वही किया था। –

2

फ़्लोटिंग पॉइंट ऑपरेशंस का आदेश महत्वपूर्ण है। सीधे आपके प्रश्न का उत्तर नहीं देता है, लेकिन आपको हमेशा फ़्लोटिंग पॉइंट नंबरों की तुलना में सावधान रहना चाहिए।

double epsilon = 0.0000001; 
if (abs(result1 - result2) <= epsilon) 
{ 
    ... 
} 

इस रुचि का हो सकता: What Every Computer Scientist Should Know About Floating-Point Arithmetic

6

सी # संकलक कुछ नहीं कर रहा है यह एक सहिष्णुता शामिल करने के लिए सामान्य है। सीपीयू है।

यदि आप एक सीपीयू रजिस्टर में एक है, और आप तो बी जोड़ने के लिए, नतीजा यह है कि रजिस्टर में संग्रहीत ए + बी है, चल परिशुद्धता

इस्तेमाल किया आप तो सी जोड़ देते हैं तो करने के लिए अनुमानित, त्रुटि कहते हैं । यह त्रुटि जोड़ एक संक्रमणकारी ऑपरेशन नहीं है, इस प्रकार अंतिम अंतर है।

+0

लेकिन यदि ए + बी एक गोल करने वाली त्रुटि उत्पन्न करता है और ए + सी नहीं करता है, तो क्या नहीं होगा (ए + सी) + बी में अभी भी ए + बी के समान दौर त्रुटि है? मुझे लगता है कि गोल करने वाली त्रुटियां बढ़ती हैं, मैं पूछ रहा हूं कि ऑर्डर महत्वपूर्ण क्यों है। – d4nt

+0

नहीं, ए + बी एक त्रुटि ई 1 उत्पन्न करता है, और फिर ए + बी + सी एक और त्रुटि ई 2 उत्पन्न करता है, इसलिए अंतिम त्रुटि ई 1 + ई 2 है। यदि ए + सी कोई त्रुटि प्रदान नहीं करता है, तो ए + सी + बी एक त्रुटि ई 3 प्रदान करता है, जिसके पास ई 1 + ई 2 से मेल खाने का कोई कारण नहीं है। अधिक जानकारी के लिए आपको फ़्लोटिंग पॉइंट अंकगणितीय के लिए Google होना चाहिए। – Brann

+0

मुझे लगता है कि मैं खुद को स्पष्ट नहीं कर रहा हूं, मुझे दोबारा दोहराएं "अगर ए + बी ई 1 बनाता है, (ए + बी) + सी ई 2 बनाता है, ए + सी ई 3 बनाता है और (ए + सी) + बी ई 4 बनाता है, क्यों e1 + e2 बराबर ई 3 + ई 4 नहीं है? अब तक, आपने मुझे बताया है कि ऐसा नहीं है लेकिन ऐसा क्यों नहीं करता है। " – d4nt

1

परिणाम 1 हमेशा परिणामके बराबर होना चाहिए?

गलत। यह गणित में सच है, लेकिन floating-point arithmetics में नहीं।

आपको कुछ Numerical Analysis primer पढ़ने की आवश्यकता होगी।

0

आप वास्तव में एक ही मान का उपयोग नहीं कर रहे हैं, क्योंकि मध्यवर्ती परिणाम अलग हैं:

double result1 = 2.1 + 1.2; 
double result2 = 2.2 + 1.1; 

क्योंकि युगल दशमलव मूल्यों का प्रतिनिधित्व नहीं कर सकते हैं वास्तव में आप अलग अलग परिणाम प्राप्त।

4

इस विषय पर the classic paper (What every computer scientist should know about floating-point arithmetic) देखें। इस तरह की चीजें फ्लोटिंग पॉइंट अंकगणित के साथ होती है। यह एक कंप्यूटर वैज्ञानिक लेता है आपको बताना है कि 1/3 + 1/3 + 1/3 बराबर is'nt 1 करने के लिए ...

+0

मैं मानता हूं कि फ्लोटिंग पॉइंट अंकगणित मुझे डराता है। अंगूठे के नियम के रूप में, जब तक मुझे जरूरी नहीं है, तब तक मैं इसका उपयोग करने से इंकार कर देता हूं। उपयोगी होने पर –

+0

उनका उपयोग करें: जहां अनुमान ठीक हैं। शारीरिक सिमुलेशन, बाहरी रूप से अधिग्रहित माप, ग्राफिक लेआउट (अनुमत अनुमान के विभिन्न स्तरों के लिए)। धन - इतना नहीं! कोई उपकरण इतना आसान नहीं है कि आप इसे अपने साथ चोट नहीं पहुंचा सकते ... (एचएम, घातक tweezer दुर्घटनाएं?)। –

1

ऑर्डर के आधार पर त्रुटियां समान नहीं हैं, एक अलग उदाहरण के साथ समझाया जा सकता है।

मान लें कि 10 से नीचे की संख्या के लिए, यह सभी संख्याओं को स्टोर कर सकता है, इसलिए यह 1, 2, 3, और इतने पर स्टोर कर सकता है और 10 सहित, लेकिन 10 के बाद, यह केवल हर दूसरे नंबर को स्टोर कर सकता है, परिशुद्धता के आंतरिक नुकसान की वजह से, दूसरे शब्दों में, यह केवल 10, 12, 14, आदि

स्टोर कर सकते हैं अब, यह उदाहरण के साथ, आप देखेंगे क्यों निम्नलिखित अलग परिणाम का उत्पादन:

1 + 1 + 1 + 10 = 12 (or 14, depending on rounding) 
10 + 1 + 1 + 1 = 10 

फ़्लोटिंग पॉइंट नंबरों की समस्या यह है कि उन्हें सटीक रूप से प्रदर्शित नहीं किया जा सकता है, और त्रुटि हमेशा एक ही तरह से नहीं जाती है, इसलिए ऑर्डर मायने रखता है।

उदाहरण के लिए, ३.००००००००००३ + ३.००००००००००३ ६.००००००००००५ (नोटिस नहीं 6 अंत में), लेकिन ३.००००००००००३ + २.९९९९९९९९९९७ जा रहा है खत्म हो सकता है ६.००००००००००१ जा रहा है खत्म हो सकता है, और उस के साथ:

step 1: 3.00000000003 + 3.00000000003 = 6.00000000005 
step 2: 6.00000000005 + 2.99999999997 = 9.00000000002 

लेकिन, आदेश को बदल :

step 1: 3.00000000003 + 2.99999999997 = 6.00000000001 
step 2: 6.00000000001 + 3.00000000003 = 9.00000000004 

तो इससे कोई फर्क नहीं पड़ता।

अब, आप भाग्यशाली हो सकते हैं कि उपर्युक्त उदाहरण एक दूसरे को संतुलित करते हैं, जिसमें पहले .xxx1 और दूसरे द्वारा .xxx1 द्वारा स्विंग होगा, आपको दोनों में .xxx3 दे रहा है, लेकिन वहां कोई गारंटी नहीं।

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