2013-03-01 33 views
5

में फ़्लोटिंग पॉइंट स्थिरांक का कॉम्पैक्ट लापरवाही प्रतिनिधित्व मेरे पास सी ++ में लिखा गया एक प्रोग्राम है जो गणितीय गणनाओं के लिए सी स्रोत कोड उत्पन्न कर रहा है। मैंने देखा है कि स्थिरांक जेनरेट कोड में बहुत अधिक जगह लेते हैं और अधिक कॉम्पैक्ट प्रतिनिधित्व की तलाश में हैं।सी/सी ++

स्थिरांक उत्पन्न करने के लिए, मैं अब उपयोग कर रहा हूँ:

double v = ... 
cfile << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1) << v; 

मैं बहुत यकीन है कि यह एक दोषरहित प्रतिनिधित्व है कर रहा हूँ, लेकिन यह भी बहुत फूला हुआ है। उदाहरण के लिए शून्य और एक को 0.0000000000000000e + 00 और 1.0000000000000000e + 00 जैसे कुछ के रूप में दर्शाया जाएगा। और "0." या "1." उतनी ही जानकारी लेती है।

क्या कॉम्पैंट को अधिक कॉम्पैक्ट में फ़ाइल करने के लिए प्रिंट करने का कोई तरीका है, लेकिन अभी भी लापरवाह तरीका है? इसे मानव पाठक के लिए अच्छा दिखने की आवश्यकता नहीं है, केवल सादे सी कोड में मौजूद होने पर संकलित करें (यदि सी 99, तो मैं यह भी पसंद करूंगा कि यह वैध सी ++ भी है)। पोर्टेबल होने पर हेक्साडेसिमल ठीक हो सकता है।

संपादित करें: कोड स्निपेट में std::fixed हटाया गया।

+0

यह थोड़ी देर हो गया है, लेकिन [यहां] देखें (http://en.wikipedia.org/wiki/Huffman_coding), हफमैन-एन्कोडिंग आपको अनुकूल कर सकती है। –

+3

शायद मुझे गलत समझा, लेकिन पिछला शून्य हटाने का समाधान समाधान नहीं होगा? – jogojapan

+0

संबंधित: http://stackoverflow.com/questions/4738768/printing-double-without-losing-precision – jogojapan

उत्तर

3

यह प्रतिनिधित्व, भाषा या मानक पुस्तकालय लेकिन एल्गोरिदम की समस्या नहीं है। यदि आपके पास कोड जनरेटर है तो ... आप क्यों नहीं उत्पन्न किए गए कोड को सर्वोत्तम (= आवश्यक सटीकता के साथ सबसे छोटा) प्रतिनिधित्व करने के लिए बदलें? जब आप हाथ से कोड लिखते हैं तो यह वही होता है।

काल्पनिक put_constant(double value) दिनचर्या आप जाँच कर सकते हैं क्या मूल्य तुम हो लिखने के लिए है में:

  • यह एक पूर्णांक है? std::fixed और set_precision के साथ कोड को न दबाएं, बस पूर्णांक पर डालें और एक बिंदु जोड़ें।
  • इसे डिफ़ॉल्ट सेटिंग्स के साथ स्ट्रिंग में बदलने की कोशिश करें, फिर इसे वापस double में परिवर्तित करें, अगर कुछ भी नहीं बदला गया तो डिफ़ॉल्ट (छोटा) प्रतिनिधित्व पर्याप्त है।
  • इसे अपने वास्तविक कार्यान्वयन के साथ स्ट्रिंग में कनवर्ट करें, और इसकी लंबाई जांचें। यदि यह एन से अधिक है (बाद में देखें) एक और प्रतिनिधित्व का उपयोग करें अन्यथा इसे लिखें।

चल बिन्दु संख्या जब वे अंक की एक बहुत कुछ उनके स्मृति प्रतिनिधित्व उपयोग करने के लिए है के लिए एक संभावित (छोटी) प्रतिनिधित्व। इसके साथ आपके पास एक सुंदर निश्चित ओवरहेड है और लंबाई कभी भी नहीं बदलेगी, इसलिए आपको इसे केवल बहुत लंबी संख्या के लिए लागू करना चाहिए। एक अनुभवहीन उदाहरण दिखाने के लिए कि यह कैसे काम कर सकते हैं:

#define USE_L2D __int64 ___tmp = 0; 
#define L2D(x) (double&)(___tmp=x) 

int main(int argc, char* argv[]) 
{ 
    // 2.2 = in memory it is 0x400199999999999A 

    USE_L2D 
    double f1 = L2D(0x400199999999999A); 
    double f2 = 123456.1234567891234567; 

    return 0; 
} 
+1

मैंने इसे अपने उत्तर के रूप में स्वीकार कर लिया। अलग-अलग प्रिंटआउट का परीक्षण करना और सबसे अच्छा चुनना शायद आपके सुझाव के अनुसार जाने का सबसे अच्छा तरीका है। धन्यवाद! – Joel

-4

मुझे यकीन नहीं है कि आप इस तरह लापता बिंदुओं को फ़्लोटिंग पॉइंट पास कर सकते हैं। फ़्लोटिंग अंक जरूरी रूप से हानिकारक हैं। हालांकि वे मूल्यों के सबसेट का प्रतिनिधित्व कर सकते हैं, ठीक है आप सभी महत्वपूर्ण आंकड़े शामिल नहीं कर सकते हैं - विभिन्न हार्डवेयर के अलग-अलग प्रतिनिधित्व हो सकते हैं ताकि आप जानकारी की कोई हानि की गारंटी न दें। भले ही आप इसे पार कर सकें क्योंकि मूल्य प्राप्त करने वाले हार्डवेयर द्वारा मूल्यवान नहीं हो सकता है।

एक सादा ऑफ़स्ट्रीम :: ऑपरेटर < < आवश्यकतानुसार कई अंकों को मुद्रित करेगा, हालांकि, मामलों को जटिल करने की वास्तव में आवश्यकता नहीं है।

+0

मुझे नहीं लगता कि अंतिम कथन सही है। डिफ़ॉल्ट परिशुद्धता आंतरिक रूप से प्रतिनिधित्व किए जा सकने वाले कई अंकों को मुद्रित नहीं करती है। – jogojapan

+0

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

+0

"हालांकि वे मूल्यों के सबसेट का प्रतिनिधित्व कर सकते हैं, ठीक है आप सभी महत्वपूर्ण आंकड़े शामिल नहीं कर सकते" हां आप कर सकते हैं। आप क्यों नहीं कर पाएंगे? और आपको सभी महत्वपूर्ण अंकों को पारित करने की आवश्यकता नहीं है, केवल इतना स्पष्ट करने के लिए पर्याप्त है कि फ़्लोटिंग-पॉइंट नंबर का मतलब है। "विभिन्न हार्डवेयर में अलग-अलग प्रतिनिधित्व हो सकते हैं ताकि आप जानकारी की कोई हानि की गारंटी नहीं दे सकें" यही कारण है कि आईईईई 754 मानक प्रकाशित किया गया था, ** 1 9 85 में **: ताकि हम सभी कंप्यूटरों पर समान प्रतिनिधित्व कर सकें। जिस समस्या का आप उल्लेख करते हैं वह 20 साल पहले उस मानक के प्रकाशन द्वारा हल किया गया था। –

1

सबसे पहले, आप अपने आप को खंडन कर रहे हैं जब आप पहली बार std::scientific, और फिर std::fixed का कहना है।और दूसरा, आप शायद या तो नहीं चाहते हैं। डिफ़ॉल्ट प्रारूप आमतौर पर यह सर्वोत्तम करने के लिए डिज़ाइन किया गया है। डिफ़ॉल्ट प्रारूप नहीं है एक नाम, और न ही एक जोड़तोड़ है, लेकिन क्या आप अगर कोई अन्य प्रारूप निर्दिष्ट किया गया है मिलता है, और सेट किया जा सकता (मामले अन्य कोड में एक अलग स्वरूप की स्थापना की है) का उपयोग करते हुए:

cfile.setf(std::ios_base::fmtflags(), std::ios_base::floatfield); 

मैं इसका उपयोग कर पुनः प्रतिक्रिया दूंगा। (आपको अभी भी पाठ्यक्रम की परिशुद्धता की आवश्यकता है।)

+0

स्ट्रिंग में रूपांतरण में अधिकतम सटीकता को संरक्षित करने के लिए हेक्स नोटेशन में प्रिंट करने के लिए वह std :: fixed and std :: वैज्ञानिक का उपयोग करता है। –

+0

@Adriano यह नहीं है कि यह क्या करता है। आखिरी व्यक्ति की प्राथमिकता है (जब तक कि उसका कार्यान्वयन गंभीर रूप से टूटा न हो)। –

+0

आप सही हैं, मैंने उनमें से एक संयोजन देखा लेकिन यह सिर्फ मेरे (थके हुए) दिमाग में था! –

9

आप हेक्साडेसिमल फ़्लोटिंग पॉइंट (The format specifier %a for printf() in C) का उपयोग कर सकते हैं; यह परिशुद्धता के सभी बिट्स (सी 11, 7.21.6.1p8, a,A विनिर्देशकों) को संरक्षित करने के लिए परिभाषित किया गया है।

cfile << std::hexfloat << v; 

अपने संकलक/मानक पुस्तकालय hexfloat का समर्थन नहीं करता, तो आप C99 %a printf विनिर्देशक (में निर्दिष्ट सी ++ 11 मेज 88 अनुभाग 22.4.2.2.2 के तहत के रूप में इस के बराबर है,) का उपयोग कर सकते हैं:

printf("%a", v); 

उदाहरण के लिए, निम्नलिखित कार्यक्रम वैध C99 है:

#include <stdio.h> 
int main() { 
    double v = 0x1.8p+1; 
    printf("%a\n", v); 
} 

आपका उत्पन्न स्रोत फ़ाइल नहीं होगा मान्य सी ++ 11 के रूप में नहीं बल्कि मूर्खता से सी ++ 11 n करता है ओटी समर्थन हेक्साडेसिमल फ्लोटिंग पॉइंट अक्षर। हालांकि कई सी ++ 11 कंपाइलर एक विस्तार के रूप में सी 99 हेक्साडेसिमल फ्लोटिंग पॉइंट अक्षर का समर्थन करते हैं।

+1

यह कोड जनरेटर का दिनचर्या है, यह ** ** ** सर्वोत्तम (= संक्षिप्त) प्रतिनिधित्व का निर्णय लेने के लिए लिखने के लिए मूल्य की जांच कर सकता है! –

+0

@ecatmur इस सूचक के लिए धन्यवाद और विशेष रूप से यह इंगित करने के लिए कि यह मान्य C++ 11 नहीं है। इस वजह से मैं शायद इस नोटेशन से बचूंगा क्योंकि यह महत्वपूर्ण है कि मेरा जनरेटर सी ++ 11 (और अधिमानतः सी ++ 03, जो मेरे कुछ उपयोगकर्ताओं के पास है) के साथ संकलित हो। – Joel

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