2012-06-05 21 views
10

कुछ सी-कोड और एफ # की तुलना में मैं इसे बदलने की कोशिश कर रहा हूं, मैंने देखा कि अंतिम परिणाम में कुछ अंतर थे।क्या सी डबल्स .NET युगल से अलग हैं?

कोड का बैक अप लेना, मैंने पाया कि यहां तक ​​कि अंतर भी थे - हालांकि छोटे थे।

कोड फ़ाइल से डेटा में पढ़कर शुरू होता है। और पहला नंबर अलग-अलग आता है। उदाहरण के लिए, एफ # में (स्क्रिप्ट के लिए आसान):

let a = 71.9497985840 
printfn "%.20f" a 

मैं (मेरे लिए) उत्पादन 71.94979858400000000000 उम्मीद मिलता है।

लेकिन सी में:

a = 71.9497985840; 
fprintf (stderr, "%.20f\n", a); 

प्रिंट बाहर 71.94979858400000700000

वह 7 कहां से आया है?

अंतर केवल छोटा है, लेकिन यह मुझे परेशान करता है क्योंकि मुझे नहीं पता कि क्यों। (यह मुझे परेशान करता है क्योंकि यह ट्रैक करने के लिए और अधिक कठिन बनाता है जहां कोड के मेरे दो संस्करण अलग हो रहे हैं)

+0

क्या आप सुनिश्चित हैं कि दोनों मान दोगुना हैं? क्या आप वाकई प्रिंटिंग में त्रुटि नहीं कर रहे हैं? – Euphoric

+1

.net में अस्थायी बिंदु अंकगणित एक अच्छी तरह से परिभाषित सटीक परिणाम नहीं है। यह केवल एक अनुमान है। निचले अंक कंपाइलर और जेआईटीर की चोटी पर बदल सकते हैं, और उन्हें 'printfn' जैसे कुछ के साथ देखकर उन्हें प्रभावित कर सकते हैं। – CodesInChaos

+0

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

उत्तर

7

प्रिंटिंग में यह एक अंतर है। एक IEEE754 double है कि मूल्य परिवर्तित पैदावार

Prelude Text.FShow.RealFloat> FD 71.9497985840 
71.94979858400000694018672220408916473388671875 

लेकिन प्रतिनिधित्व 71.949798584 अपने पड़ोसियों से संख्या भेद करने के लिए पर्याप्त है। सी, जब दशमलव बिंदु के बाद 20 अंकों की परिशुद्धता के साथ मुद्रित करने के लिए कहा जाता है तो अंकों को वांछित संख्याओं के आधार पर सही ढंग से गोल किया जाता है, जाहिर है कि एफ # सबसे कम विशिष्ट निर्धारण प्रतिनिधित्व का उपयोग करता है और इसे 0 की वांछित संख्या के साथ पैड करता है, जैसे हास्केल करता है ।

+0

तो यदि मैं इन संख्याओं की सूचियों पर एकाधिक संचालन करता हूं, तो क्या ये अंतर महत्वपूर्ण होने जा रहे हैं? मैं यह देखने की कोशिश कर रहा हूं कि मैं यह देखने के लिए कैसे परीक्षण कर सकता हूं कि यह मामला है या नहीं ... – Benjol

+0

यह निर्भर करता है। मुझे लगता है कि .NET JITter को थोड़ा सा छूट देता है, इसलिए परिणाम .NET कोड के विभिन्न रनों में पुन: उत्पन्न नहीं होंगे। यदि सी कार्यान्वयन आईईसी 605 9 5 का पालन करने का दावा नहीं करता है, तो इसमें बहुत सी छूट भी है। सवाल यह है कि क्या सी और .NET एक ही इनपुट के समान कार्यों के समान परिणाम उत्पन्न करते हैं। यदि वे करते हैं, तो आप केवल स्ट्रिंग प्रस्तुति के अंतर का निरीक्षण करेंगे, जो केवल 'डबल' मान निर्धारित करने के लिए आवश्यक भाग के पीछे दिखाई देता है, कुछ भी जमा नहीं हो सकता है। यदि वे परिणामों में 1 या 2 यूएलपी के अंतर नहीं करते हैं ... –

+0

जमा हो सकता है। लेकिन जब तक आप ** ** ** संचालन के कुछ ** (या कुछ बुरी तरह से परिचालित परिचालन) नहीं करते हैं, तो अंतर कम रहेगा। –

3

यह सिर्फ अलग दौर है। संख्या में एक ही (CPython के अनुसार, कम से कम) कर रहे हैं:

>>> '%.44f' % 71.94979858400000000000 
'71.94979858400000694018672220408916473388671875' 
>>> '%.44f' % 71.94979858400000700000 
'71.94979858400000694018672220408916473388671875' 
0

अन्य उत्तर पर्याप्त रूप से समस्या (डबल परिशुद्धता और गोलाई) के स्रोत की व्याख्या।

यदि आपकी संख्या आमतौर पर मध्यम परिमाण और दशमलव परिशुद्धता के बहुत महत्वपूर्ण है (गणना की गति से मोरसो) तो शायद .NET decimal प्रारूप का उपयोग करने पर विचार करें। यह आपको डबलस की तरह fractional बाइनरी दौर त्रुटियों के बिना सटीकता के 28-29 सटीक दशमलव स्थानों देता है। प्रतिबंध यह है कि सीमा छोटी है (कोई बड़ा घाता नहीं है!)।

http://msdn.microsoft.com/en-us/library/364x0z75%28v=vs.100%29.aspx

3

इसमें .NET System.Double.ToString() विधि है कि अंतर है, विधि है कि एक स्ट्रिंग के लिए एक डबल धर्मान्तरित है। आप एसएससीएलआई 20 में प्रदान किए गए सीएलआर स्रोत को डाउनलोड करके प्रासंगिक कोड पर एक नज़र डाल सकते हैं। रूपांतरण clr/src/vm/comnumber.cpp, COMNumber :: FormatDouble() फ़ंक्शन द्वारा किया जाता है। कौन सा like this लग रहा है, कोड में टिप्पणी क्या हो रहा है के सबसे वर्णनात्मक है:

//In order to give numbers that are both friendly to display and round-trippable, 
//we parse the number using 15 digits and then determine if it round trips to the same 
//value. If it does, we convert that NUMBER to a string, otherwise we reparse using 17 digits 
//and display that. 

सी क्रम पुस्तकालय है कि सुविधा नहीं है।

+0

धन्यवाद हंस, यह एक काफी निर्णायक उत्तर है। मुझे निश्चित रूप से संचयी त्रुटियां मिल रही हैं क्योंकि मैं अपने एल्गोरिदम के माध्यम से आगे बढ़ता हूं, अब मुझे अभी कोशिश करना और ट्रैक करना है कि वास्तव में कहां और क्यों ... वर्तमान में यह काम नहीं कर सकता है अगर यह फ़्लोटिंग-पॉइंट सामग्री है, या मेरे में सादे त्रुटियां हैं कोड। – Benjol

0

इस पर ठोकर खाने के लिए और जानकारी।

here कोड के बिट्स का उपयोग करके, मैंने पुष्टि की है (मुझे विश्वास है) अंतर्निहित द्विआधारी प्रतिनिधित्व (कम से कम इस विशेष संख्या के लिए) समान है।

यहां कोड नमूने हैं - नकारात्मक शून्य को खत्म करने के लिए 'शून्य से शून्य गुणा' पर ध्यान दें - जो लंबे समय तक परिवर्तित होने पर बदसूरत है।

//(C# this time) 
var d = 71.9497985840; //or other incoming double value 
if(d == 0) d = d * d; //for negative zero 
var longval = System.BitConverter.DoubleToInt64Bits(d); // = 4634763433907061836 

सी में:

double d; 
long long a; 
d = 71.9497985840;  //or other incoming double value 
if(d == 0) d = d * d; //for negative zero 
a = *(long long*)&d; //= 4634763433907061836 

अद्यतन - मैं के माध्यम से पीछा किया, और पता चला कि विसंगति मैट्रिक्स उलट दौरान शुरू किया जा रहा था, क्योंकि प्रत्येक प्रणाली एक अलग पुस्तकालय के लिए बाहर बुलाया, में उलट को लागू करने एक अलग तरीका ...