प्रिन्टिंग चौड़ाई निर्दिष्ट फ़्लोटिंग-पॉइंट वैल्यू की शुद्धता बनाए रखने के लिए


103

क्या कोई printfचौड़ाई निर्दिष्ट है जो एक फ्लोटिंग पॉइंट स्पेसियर पर लागू की जा सकती है जो कि आउटपुट को स्वचालित रूप से महत्वपूर्ण अंकों की आवश्यक संख्या में प्रारूपित करेगी जैसे कि स्ट्रिंग को वापस स्कैन करते समय, मूल फ्लोटिंग पॉइंट वैल्यू का अधिग्रहण किया जाता है?

उदाहरण के लिए, मान लें कि मैं दशमलव स्थानों floatकी शुद्धता के लिए प्रिंट करता हूं 2:

float foobar = 0.9375;
printf("%.2f", foobar);    // prints out 0.94

जब मैं आउटपुट स्कैन करता 0.94हूं, तो मेरे पास कोई मानक-अनुपालन गारंटी नहीं है कि मुझे मूल 0.9375फ़्लोटिंग-पॉइंट मान वापस मिलेगा (इस उदाहरण में, मैं शायद नहीं करूँगा)।

मैं यह बताने के printfलिए कि स्वचालित रूप से फ़्लोटिंग-पॉइंट वैल्यू को महत्वपूर्ण अंकों की आवश्यक संख्या तक प्रिंट करने का एक तरीका है, यह सुनिश्चित करने के लिए कि इसे पास किए गए मूल मूल्य पर वापस स्कैन किया जा सकता है printf

मैं पास करने के लिए अधिकतम चौड़ाई प्राप्तfloat.h करने के लिए मैक्रोज़ के कुछ का उपयोग कर सकता हूं , लेकिन क्या पहले से ही महत्वपूर्ण अंकों की आवश्यक संख्या के लिए स्वचालित रूप से प्रिंट करने के लिए एक निर्दिष्टकर्ता है - या कम से कम अधिकतम चौड़ाई के लिए?printf


4
@ बोबोबोबो तो आप सिर्फ यह सलाह

1
@ H2CO3 नहीं, मैं "हवा से बाहर एक धारणा" का उपयोग करने की सिफारिश नहीं करूंगा, मैं सुझाव दूंगा printf( "%f", val );कि वह पहले से ही पोर्टेबल, कुशल और डिफ़ॉल्ट है।
बोब्बोबो

2
@bobobobo ताकि मैं इसे उत्तरों में जोड़ सकूं, क्या आप C99 मानक में खंड का हवाला दे पाएंगे जो बताता है कि प्रिंटफ स्टेटमेंट डिफ़ॉल्ट रूप से फ्लोट प्रकार को अधिकतम परिशुद्धता पर आउटपुट करेगा यदि कोई सटीक निर्दिष्ट नहीं है?
विलहेम ग्रे

1
@VilhelmGray @ @ के रूप में अच्छी तरह से हो जाता है, अपने विशेष के लिए वास्तविक परिशुद्धता के रूप में कुछ बहुत जटिल गणित है double। जैसा कि आपका doubleबहुत बड़ा हो जाता है (1.0 से बहुत दूर), यह वास्तव में दशमलव भाग में कम सटीक होता है (मान भाग 1.0 से कम)। इसलिए आपके पास वास्तव में यहाँ कोई संतोषजनक उत्तर नहीं हो सकता है, क्योंकि आपके प्रश्न में एक गलत धारणा है (अर्थात सभी floats / doubles समान बनाए गए हैं)
bobobobo

2
@ विल्हेम ग्रे C11dr 5.2.4.2.2 "... दशमलव अंकों की संख्या, n, जैसे कि p मूलांक b अंक वाले किसी भी फ्लोटिंग-पॉइंट नंबर को एक दशमलव-एन अंकों के साथ फ़्लोटिंग-पॉइंट नंबर पर गोल किया जा सकता है और फिर से बदलाव के साथ वापस किया जा सकता है। मान के लिए, p log10 bb 10 +1 + p log10 b FL की शक्ति है अन्यथा FLT_DECIMAL_DIG 6 DBL_DECIMAL_DIG 10 LDBL_DECIMAL_DIG 10 ... 6,10,10 न्यूनतम मान हैं।
chux -

जवाबों:


92

मैं @Jens Gustedt हेक्साडेसिमल समाधान सुझाता हूं:% a का उपयोग करें।

ओपी चाहता है कि "अधिकतम सटीकता के साथ प्रिंट करें (या कम से कम सबसे महत्वपूर्ण दशमलव)"।

एक सरल उदाहरण के रूप में एक सातवें प्रिंट होगा:

#include <float.h>
int Digs = DECIMAL_DIG;
double OneSeventh = 1.0/7.0;
printf("%.*e\n", Digs, OneSeventh);
// 1.428571428571428492127e-01

लेकिन चलो गहरी खुदाई करें ...

गणितीय रूप से, उत्तर "0.142857 142857 142857 ..." है, लेकिन हम परिमित सटीक फ़्लोटिंग पॉइंट संख्याओं का उपयोग कर रहे हैं। आइए मान लें कि IEEE 754 डबल-सटीक बाइनरी । तो OneSeventh = 1.0/7.0नीचे दिए गए मूल्य में परिणाम। यह भी दर्शाया गया है कि पूर्ववर्ती और निम्नलिखित प्रतिनिधित्व योग्य doubleफ्लोटिंग संख्याएँ हैं।

OneSeventh before = 0.1428571428571428 214571170656199683435261249542236328125
OneSeventh        = 0.1428571428571428 49212692681248881854116916656494140625
OneSeventh after  = 0.1428571428571428 769682682968777953647077083587646484375

किसी सीमित उपयोग के सटीक दशमलव प्रतिनिधित्व को मुद्रित करना double

सी में मैक्रों के 2 परिवार हैं <float.h>जो हमारी मदद करेंगे।
पहला सेट दशमलव में एक स्ट्रिंग में प्रिंट करने के लिए महत्वपूर्ण अंकों की संख्या है इसलिए स्ट्रिंग को वापस स्कैन करते समय, हमें मूल फ़्लोटिंग पॉइंट मिलता है। सी कल्पना के न्यूनतम मूल्य और एक नमूना C11 संकलक के साथ दिखाए जाते हैं ।

FLT_DECIMAL_DIG   6,  9 (float)                           (C11)
DBL_DECIMAL_DIG  10, 17 (double)                          (C11)
LDBL_DECIMAL_DIG 10, 21 (long double)                     (C11)
DECIMAL_DIG      10, 21 (widest supported floating type)  (C99)

दूसरा सेट एक महत्वपूर्ण अंक की संख्या है जिसे एक स्ट्रिंग को एक फ़्लोटिंग पॉइंट में स्कैन किया जा सकता है और फिर एफपी मुद्रित किया जाता है, फिर भी उसी स्ट्रिंग प्रस्तुति को बनाए रखता है। सी कल्पना के न्यूनतम मूल्य और एक नमूना C11 संकलक के साथ दिखाए जाते हैं । मेरा मानना ​​है कि उपलब्ध पूर्व C99।

FLT_DIG   6, 6 (float)
DBL_DIG  10, 15 (double)
LDBL_DIG 10, 18 (long double)

मैक्रों का पहला सेट ओपी के महत्वपूर्ण अंकों के लक्ष्य को पूरा करता है । लेकिन वह स्थूल हमेशा उपलब्ध नहीं होता है।

#ifdef DBL_DECIMAL_DIG
  #define OP_DBL_Digs (DBL_DECIMAL_DIG)
#else  
  #ifdef DECIMAL_DIG
    #define OP_DBL_Digs (DECIMAL_DIG)
  #else  
    #define OP_DBL_Digs (DBL_DIG + 3)
  #endif
#endif

"+ 3" मेरे पिछले उत्तर की क्रूरता थी। इसका केंद्र इस बात पर केंद्रित है कि राउंड-ट्रिप रूपांतरण स्ट्रिंग-एफपी-स्ट्रिंग (सेट # 2 मैक्रो उपलब्ध C89) को जानने के बाद, कोई व्यक्ति एफपी-स्ट्रिंग-एफपी (सेट # 1 मैक्रोज़ उपलब्ध पोस्ट C89) के लिए अंक कैसे निर्धारित करेगा? सामान्य तौर पर, 3 जोड़ें परिणाम था।

अब प्रिंट करने के लिए कितने महत्वपूर्ण अंक ज्ञात और संचालित हैं <float.h>

एन महत्वपूर्ण दशमलव अंकों को मुद्रित करने के लिए विभिन्न स्वरूपों का उपयोग किया जा सकता है।

साथ "%e", सटीक क्षेत्र लीड अंक और दशमलव बिंदु के बाद अंकों की संख्या है । तो - 1क्रम में है। नोट: यह -1प्रारंभिक में नहीं हैint Digs = DECIMAL_DIG;

printf("%.*e\n", OP_DBL_Digs - 1, OneSeventh);
// 1.4285714285714285e-01

साथ "%f", परिशुद्धता क्षेत्र अंकों की संख्या है के बाद दशमलव बिंदु। जैसे संख्या के लिए OneSeventh/1000000.0, किसी को OP_DBL_Digs + 6सभी महत्वपूर्ण अंक देखने होंगे।

printf("%.*f\n", OP_DBL_Digs    , OneSeventh);
// 0.14285714285714285
printf("%.*f\n", OP_DBL_Digs + 6, OneSeventh/1000000.0);
// 0.00000014285714285714285

नोट: कई करने के लिए उपयोग कर रहे हैं "%f"। जो दशमलव बिंदु के बाद 6 अंक प्रदर्शित करता है; 6 डिस्प्ले डिफॉल्ट है, संख्या की शुद्धता नहीं।


1.428571428571428492127e-01 क्यों नहीं है और 1.428571428571428492127e-0 0 1, 'ई' के बाद अंकों की संख्या 3 होनी चाहिए?
user1024

12.12.5 फ्लोटिंग-पॉइंट कन्वर्सेशन कहता है कि इसके लिए डिफ़ॉल्ट सटीकता %f6. है
जिंगुओ याओ

1
@Jingguo याओ सहमत हैं कि संदर्भ कहता है "सटीक निर्दिष्ट करता है कि '% f" के लिए दशमलव-बिंदु वर्ण कितने अंकों का अनुसरण करता है। " "सटीक" शब्द का उपयोग गणितीय अर्थ में नहीं किया गया है, लेकिन दशमलव बिंदु के बाद अंकों की संख्या को परिभाषित करने के लिए किया जाता है। 1234567890.123, गणितीय रूप से सटीक या महत्वपूर्ण अंकों के 13 अंक हैं। 0.000000000123 में गणितीय सटीकता के 3 अंक हैं, न कि 13. फ्लोटिंग पॉइंट संख्याएं लघुगणकीय रूप से वितरित की जाती हैं। यह उत्तर महत्वपूर्ण अंकों और परिशुद्धता के गणितीय अर्थ का उपयोग करता है
chux -

1
@ स्लीप डी। थॉम्पसन "सी कल्पना के न्यूनतम मूल्य और एक नमूना C11 संकलक के साथ दिखाए गए हैं ।"
chux

1
वास्तव में आप सही हैं - मेरी चाल केवल 1.0 और 1.0eDBL_DIG के बीच के परिमाण वाले मूल्यों के लिए मान्य है, जो यकीनन "%f"पहली श्रेणी में मुद्रण के लिए उपयुक्त एकमात्र सीमा है। का प्रयोग "%e"के रूप में आप से पता चला की है बेशक एक बेहतर सर्वांगीण और प्रभावी ढंग से एक सभ्य जवाब (हालांकि शायद इसे प्रयोग के रूप में अच्छा के रूप में नहीं है दृष्टिकोण "%a"अगर यह उपलब्ध हो हो सकता है, और निश्चित रूप से "%a"उपलब्ध होना चाहिए और यदि `DBL_DECIMAL_DIG है)। मैंने हमेशा एक प्रारूप निर्दिष्टकर्ता के लिए कामना की है जो हमेशा अधिकतम सटीकता (हार्ड-कोडित 6 दशमलव स्थानों के बजाय) के लिए बिल्कुल गोल होगा।
ग्रेग ए। वुड्स

66

फ्लोटिंग पॉइंट नंबरों को हानिरहित तरीके से प्रिंट करने का संक्षिप्त उत्तर (जैसे कि वे NaN और इन्फिनिटी को छोड़कर, ठीक उसी संख्या में वापस पढ़ा जा सकता है):

  • यदि आपका प्रकार फ्लोट है: उपयोग करें printf("%.9g", number)
  • यदि आपका प्रकार दोहरा है: उपयोग करें printf("%.17g", number)

उपयोग न करें %f, क्योंकि यह केवल दशमलव के बाद कितने महत्वपूर्ण अंकों को निर्दिष्ट करता है और छोटी संख्याओं को काट देगा। संदर्भ के लिए, जादू नंबर 9 और 17 को पाया जा सकता है float.hजिसमें परिभाषित करता है FLT_DECIMAL_DIGऔर DBL_DECIMAL_DIG


6
क्या आप %gविनिर्देशक की व्याख्या कर पाएंगे ?
विल्हेम ग्रे

14
% g सटीकता के लिए आवश्यकतानुसार कई अंकों के साथ संख्या को प्रिंट करता है, घातांक सिंटैक्स को प्राथमिकता देते हैं जब संख्याएं छोटी या बड़ी होती हैं (.00005 के बजाय 1e-5) और किसी भी अनुगामी शून्य को लंघन करना (1.00 के बजाय 1)।
ccxvii

4
@truthseeker IEEE 754 बाइनरी 64 कोड का प्रतिनिधित्व करने के लिए वास्तव में कम से कम 15 महत्वपूर्ण दशमलव स्थानों को प्रिंट करने की आवश्यकता होती है । लेकिन असंदिग्ध-नेस् को बाइनरी संख्या (2,4,8, आदि) में सटीक परिवर्तन के रूप में 17 की आवश्यकता होती है और एक दशमलव संख्या (10,100,1000, आदि पर) कभी भी एक ही नंबर पर नहीं होती है (1.0 को छोड़कर)। उदाहरण: 2 doubleमूल्यों बस ऊपर 0.1: 1.000_0000_0000_0000_2e-01, 1.000_0000_0000_0000_3e-01जरूरत 17 अंक भेद करने के लिए।
चक्स -

3
@chux - आप% के व्यवहार के बारे में गलत हैं। यह 1.000_0000_0000_0000_2e-01 को 1.000_0000_0000_0000_3e-01 से अलग करने के आपके उदाहरण के लिए पर्याप्त नहीं है । % .17 जी की जरूरत है।
डॉन हैच

1
@Don हैच मैं मानता हूँ "%.16g"अपर्याप्त है और "%.17g"और "%.16e"पर्याप्त हैं। के विवरण %g, मेरे द्वारा गलत याद किए गए थे।
chux -

23

यदि आप केवल बिट (हेक्स पैटर्न का सम्मान) में रुचि रखते हैं तो आप %aप्रारूप का उपयोग कर सकते हैं । यह आपको गारंटी देता है:

डिफ़ॉल्ट सटीक मान मान के सटीक प्रतिनिधित्व के लिए होता है यदि बेस 2 में एक सटीक प्रतिनिधित्व मौजूद है और अन्यथा प्रकार डबल के मूल्यों को भेद करने के लिए पर्याप्त रूप से बड़ा है।

मुझे यह जोड़ना होगा कि यह केवल C99 के बाद से उपलब्ध है।


16

नहीं, अधिकतम सटीकता के साथ फ्लोटिंग-पॉइंट प्रिंट करने के लिए ऐसी कोई प्रिंटफ चौड़ाई निर्दिष्ट नहीं है । मुझे क्यों समझाते हैं।

की अधिकतम परिशुद्धता floatऔर doubleहै चर , और पर निर्भर वास्तविक मूल्य का floatया double

स्मरण करो floatऔर sign.exponent.mantissa प्रारूप doubleमें संग्रहीत हैं । इसका मतलब यह है कि बड़ी संख्या की तुलना में छोटी संख्या के लिए आंशिक घटक के लिए कई और बिट्स का उपयोग किया जाता है

यहां छवि विवरण दर्ज करें

उदाहरण के लिए, floatआसानी से 0.0 और 0.1 के बीच अंतर कर सकते हैं।

float r = 0;
printf( "%.6f\n", r ) ; // 0.000000
r+=0.1 ;
printf( "%.6f\n", r ) ; // 0.100000

लेकिन और के floatबीच अंतर का कोई पता नहीं है ।1e271e27 + 0.1

r = 1e27;
printf( "%.6f\n", r ) ; // 999999988484154753734934528.000000
r+=0.1 ;
printf( "%.6f\n", r ) ; // still 999999988484154753734934528.000000

ऐसा इसलिए है क्योंकि सभी सटीकता (जो मंटिसा बिट्स की संख्या तक सीमित है) का उपयोग दशमलव के बचे संख्या के बड़े हिस्से के लिए किया जाता है।

%.fसंशोधक बस का कहना है कि कितने दशमलव मान आप जहाँ तक नाव नंबर प्रिंट करना चाहते हैं स्वरूपण चला जाता है। तथ्य यह है कि उपलब्ध सटीकता संख्या के आकार पर निर्भर करती है आप को संभालने के लिए प्रोग्रामर के रूप में हैprintfआपके लिए ऐसा नहीं कर सकता / सकती।


2
यह विशिष्ट दशमलव स्थानों पर फ्लोटिंग पॉइंट मानों को सटीक रूप से प्रिंट करने की सीमाओं का एक उत्कृष्ट विवरण है। हालांकि, मेरा मानना ​​है कि मैं अपने मूल शब्दों के साथ बहुत अस्पष्ट था, इसलिए मैंने इस उम्मीद में "अधिकतम सटीक" शब्द से बचने के लिए अपने प्रश्न को अपडेट किया है कि यह भ्रम को दूर कर सकता है।
विल्हेम ग्रे

यह अभी भी उस संख्या के मूल्य पर निर्भर करता है जिसे आप प्रिंट कर रहे हैं।
बोब्बोबो

3
यह आंशिक रूप से सच है, लेकिन यह सवाल का जवाब नहीं देता है और आप ओपी से पूछ रहे हैं कि आप उलझन में हैं। वह पूछ रहा है कि क्या कोई महत्वपूर्ण [दशमलव] अंकों की संख्या को floatप्रदान कर सकता है, और आप दावा करते हैं कि ऐसी कोई बात नहीं है (अर्थात ऐसा नहीं है FLT_DIG), जो गलत है।

@ H2CO3 शायद आपको मेरी पोस्ट और डाउनवोट (j / k) संपादित करनी चाहिए। इस जवाब का FLT_DIGमतलब कुछ भी नहीं है। यह उत्तर उपलब्ध दशमलव स्थानों की संख्या को दर्शाता है जो फ्लोट के अंदर के मूल्य पर निर्भर करता है
बॉबोबो

1
क्या आप मान रहे हैं कि प्रारूप पत्र को "एफ" होना चाहिए? मुझे नहीं लगता कि इसकी आवश्यकता है। प्रश्न का मेरा पठन यह है कि ओपी कुछ प्रिंटफ़ प्रारूप निर्दिष्टकर्ता की तलाश कर रहा है जो एक गैर-हानिपूर्ण गोल यात्रा का उत्पादन करता है, इसलिए @ccxvii का उत्तर ("% .9g" फ्लोट के लिए, "% .17g" डबल के लिए है) अच्छा था। संभवत: प्रश्न "चौड़ाई" शब्द को हटाने से बेहतर होगा।
डॉन हैच

11

बस मैक्रो से <float.h>और चर-चौड़ाई रूपांतरण विनिर्देशक ( ".*") का उपयोग करें:

float f = 3.14159265358979323846;
printf("%.*f\n", FLT_DIG, f);

2
@OliCharlesworth क्या आपका मतलब ऐसा है:printf("%." FLT_DIG "f\n", f);
विल्हेम ग्रे

3
+1 लेकिन यह सबसे अच्छा काम करता है %e, इसके लिए इतना अच्छा नहीं है %f: केवल अगर यह जानता है कि प्रिंट करने का मूल्य करीब है 1.0
पास्कल क्यूक

3
%eबहुत कम संख्या के लिए महत्वपूर्ण अंक प्रिंट %fकरता है और नहीं करता है। उदा x = 1e-100%.5fप्रिंट 0.00000(रियायत की कुल हानि)। %.5eप्रिंट करता है 1.00000e-100
चक्स -

1
@bobobobo इसके अलावा, आप इसमें गलत हैं कि यह "अधिक सटीक कारण देता है"। FLT_DIGयह एक कारण के लिए परिभाषित मूल्य के लिए परिभाषित किया गया है यदि यह 6 है, ऐसा इसलिए floatहै क्योंकि परिशुद्धता के 6 से अधिक अंक रखने में सक्षम नहीं है। यदि आप इसका उपयोग करके प्रिंट करते हैं %.7f, तो अंतिम अंक का कोई अर्थ नहीं होगा। नीचे उतरने से पहले सोचें।

5
@bobobobo नहीं, %.6fबराबर नहीं है, क्योंकि FLT_DIGहमेशा 6 नहीं है। और दक्षता के बारे में कौन परवाह करता है? I / O पहले से ही नरक के रूप में महंगा है, एक या अधिक अंक कम सटीकता एक अड़चन नहीं बनाएगा।

5

मैं यह सत्यापित करने के लिए एक छोटा प्रयोग चलाता हूं कि मुद्रण DBL_DECIMAL_DIGवास्तव में संख्या के बाइनरी प्रतिनिधित्व को संरक्षित करता है। यह पता चला कि संकलक और सी पुस्तकालयों के लिए मैंने कोशिश की, DBL_DECIMAL_DIGवास्तव में अंकों की संख्या की आवश्यकता है, और यहां तक ​​कि एक अंक कम के साथ मुद्रण एक महत्वपूर्ण समस्या बनाता है।

#include <float.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

union {
    short s[4];
    double d;
} u;

void
test(int digits)
{
    int i, j;
    char buff[40];
    double d2;
    int n, num_equal, bin_equal;

    srand(17);
    n = num_equal = bin_equal = 0;
    for (i = 0; i < 1000000; i++) {
        for (j = 0; j < 4; j++)
            u.s[j] = (rand() << 8) ^ rand();
        if (isnan(u.d))
            continue;
        n++;
        sprintf(buff, "%.*g", digits, u.d);
        sscanf(buff, "%lg", &d2);
        if (u.d == d2)
            num_equal++;
        if (memcmp(&u.d, &d2, sizeof(double)) == 0)
            bin_equal++;
    }
    printf("Tested %d values with %d digits: %d found numericaly equal, %d found binary equal\n", n, digits, num_equal, bin_equal);
}

int
main()
{
    test(DBL_DECIMAL_DIG);
    test(DBL_DECIMAL_DIG - 1);
    return 0;
}

मैं इसे Microsoft के C कंपाइलर 19.00.24215.1 और gcc वर्जन 7.4.0 20170516 (डेबियन 6.3.0-18 + deb9u1) के साथ चलाता हूं। एक कम दशमलव अंक का उपयोग संख्या की संख्या को आधा कर देता है जो बिल्कुल बराबर की तुलना करता है। (मैंने यह भी सत्यापित rand()किया है कि जैसा कि वास्तव में उपयोग किया जाता है, लगभग एक मिलियन विभिन्न संख्याएँ पैदा करता है।) यहाँ विस्तृत परिणाम हैं।

माइक्रोसॉफ्ट सी

17 अंकों के साथ 999507 मूल्यों का परीक्षण किया गया: 999507 ने संख्यात्मक रूप से बराबर पाया, 999507 ने बाइनरी के बराबर पाया
16 अंकों के साथ 999507 मूल्यों का परीक्षण: 545389 संख्यात्मक रूप से बराबर पाया गया, 545389 बाइनरी बराबर पाया गया

जीसीसी

17 अंकों के साथ 999485 मूल्यों का परीक्षण किया गया: 999485 ने संख्यात्मक रूप से बराबर पाया, 999485 ने बाइनरी के बराबर पाया
16 अंकों के साथ 999485 मूल्यों का परीक्षण किया गया: 545402 संख्यात्मक रूप से बराबर पाया गया, 545402 बाइनरी बराबर पाया गया

1
"इसे Microsoft के C कंपाइलर के साथ चलाएं" -> उस कंपाइलर में हो सकता है RAND_MAX == 32767u.s[j] = (rand() << 8) ^ rand();कुछ बिट्स को 0 या 1. होने का मौका मिलने पर विचार करें या पसंद करें
chux - मोनिका

वास्तव में, इसका RAND_MAX 32767 है, इसलिए आपका प्रस्ताव सही है।
डायोमिडिस स्पिनेलिस

1
मैंने @ chux-ReinstateMonica द्वारा सुझाए गए RAND_MAX को संभालने के लिए पोस्ट को अपडेट किया। परिणाम पहले प्राप्त किए गए समान हैं।
डायोमिडिस स्पिनेलिस

3

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

static unsigned int
ilog10(uintmax_t v);

/*
 * Note:  As presented this demo code prints a whole line including information
 * about how the form was arrived with, as well as in certain cases a couple of
 * interesting details about the number, such as the number of decimal places,
 * and possibley the magnitude of the value and the number of significant
 * digits.
 */
void
print_decimal(double d)
{
        size_t sigdig;
        int dplaces;
        double flintmax;

        /*
         * If we really want to see a plain decimal presentation with all of
         * the possible significant digits of precision for a floating point
         * number, then we must calculate the correct number of decimal places
         * to show with "%.*f" as follows.
         *
         * This is in lieu of always using either full on scientific notation
         * with "%e" (where the presentation is always in decimal format so we
         * can directly print the maximum number of significant digits
         * supported by the representation, taking into acount the one digit
         * represented by by the leading digit)
         *
         *        printf("%1.*e", DBL_DECIMAL_DIG - 1, d)
         *
         * or using the built-in human-friendly formatting with "%g" (where a
         * '*' parameter is used as the number of significant digits to print
         * and so we can just print exactly the maximum number supported by the
         * representation)
         *
         *         printf("%.*g", DBL_DECIMAL_DIG, d)
         *
         *
         * N.B.:  If we want the printed result to again survive a round-trip
         * conversion to binary and back, and to be rounded to a human-friendly
         * number, then we can only print DBL_DIG significant digits (instead
         * of the larger DBL_DECIMAL_DIG digits).
         *
         * Note:  "flintmax" here refers to the largest consecutive integer
         * that can be safely stored in a floating point variable without
         * losing precision.
         */
#ifdef PRINT_ROUND_TRIP_SAFE
# ifdef DBL_DIG
        sigdig = DBL_DIG;
# else
        sigdig = ilog10(uipow(FLT_RADIX, DBL_MANT_DIG - 1));
# endif
#else
# ifdef DBL_DECIMAL_DIG
        sigdig = DBL_DECIMAL_DIG;
# else
        sigdig = (size_t) lrint(ceil(DBL_MANT_DIG * log10((double) FLT_RADIX))) + 1;
# endif
#endif
        flintmax = pow((double) FLT_RADIX, (double) DBL_MANT_DIG); /* xxx use uipow() */
        if (d == 0.0) {
                printf("z = %.*s\n", (int) sigdig + 1, "0.000000000000000000000"); /* 21 */
        } else if (fabs(d) >= 0.1 &&
                   fabs(d) <= flintmax) {
                dplaces = (int) (sigdig - (size_t) lrint(ceil(log10(ceil(fabs(d))))));
                if (dplaces < 0) {
                        /* XXX this is likely never less than -1 */
                        /*
                         * XXX the last digit is not significant!!! XXX
                         *
                         * This should also be printed with sprintf() and edited...
                         */
                        printf("R = %.0f [%d too many significant digits!!!, zero decimal places]\n", d, abs(dplaces));
                } else if (dplaces == 0) {
                        /*
                         * The decimal fraction here is not significant and
                         * should always be zero  (XXX I've never seen this)
                         */
                        printf("R = %.0f [zero decimal places]\n", d);
                } else {
                        if (fabs(d) == 1.0) {
                                /*
                                 * This is a special case where the calculation
                                 * is off by one because log10(1.0) is 0, but
                                 * we still have the leading '1' whole digit to
                                 * count as a significant digit.
                                 */
#if 0
                                printf("ceil(1.0) = %f, log10(ceil(1.0)) = %f, ceil(log10(ceil(1.0))) = %f\n",
                                       ceil(fabs(d)), log10(ceil(fabs(d))), ceil(log10(ceil(fabs(d)))));
#endif
                                dplaces--;
                        }
                        /* this is really the "useful" range of %f */
                        printf("r = %.*f [%d decimal places]\n", dplaces, d, dplaces);
                }
        } else {
                if (fabs(d) < 1.0) {
                        int lz;

                        lz = abs((int) lrint(floor(log10(fabs(d)))));
                        /* i.e. add # of leading zeros to the precision */
                        dplaces = (int) sigdig - 1 + lz;
                        printf("f = %.*f [%d decimal places]\n", dplaces, d, dplaces);
                } else {                /* d > flintmax */
                        size_t n;
                        size_t i;
                        char *df;

                        /*
                         * hmmmm...  the easy way to suppress the "invalid",
                         * i.e. non-significant digits is to do a string
                         * replacement of all dgits after the first
                         * DBL_DECIMAL_DIG to convert them to zeros, and to
                         * round the least significant digit.
                         */
                        df = malloc((size_t) 1);
                        n = (size_t) snprintf(df, (size_t) 1, "%.1f", d);
                        n++;                /* for the NUL */
                        df = realloc(df, n);
                        (void) snprintf(df, n, "%.1f", d);
                        if ((n - 2) > sigdig) {
                                /*
                                 * XXX rounding the integer part here is "hard"
                                 * -- we would have to convert the digits up to
                                 * this point back into a binary format and
                                 * round that value appropriately in order to
                                 * do it correctly.
                                 */
                                if (df[sigdig] >= '5' && df[sigdig] <= '9') {
                                        if (df[sigdig - 1] == '9') {
                                                /*
                                                 * xxx fixing this is left as
                                                 * an exercise to the reader!
                                                 */
                                                printf("F = *** failed to round integer part at the least significant digit!!! ***\n");
                                                free(df);
                                                return;
                                        } else {
                                                df[sigdig - 1]++;
                                        }
                                }
                                for (i = sigdig; df[i] != '.'; i++) {
                                        df[i] = '0';
                                }
                        } else {
                                i = n - 1; /* less the NUL */
                                if (isnan(d) || isinf(d)) {
                                        sigdig = 0; /* "nan" or "inf" */
                                }
                        }
                        printf("F = %.*s. [0 decimal places, %lu digits, %lu digits significant]\n",
                               (int) i, df, (unsigned long int) i, (unsigned long int) sigdig);
                        free(df);
                }
        }

        return;
}


static unsigned int
msb(uintmax_t v)
{
        unsigned int mb = 0;

        while (v >>= 1) { /* unroll for more speed...  (see ilog2()) */
                mb++;
        }

        return mb;
}

static unsigned int
ilog10(uintmax_t v)
{
        unsigned int r;
        static unsigned long long int const PowersOf10[] =
                { 1LLU, 10LLU, 100LLU, 1000LLU, 10000LLU, 100000LLU, 1000000LLU,
                  10000000LLU, 100000000LLU, 1000000000LLU, 10000000000LLU,
                  100000000000LLU, 1000000000000LLU, 10000000000000LLU,
                  100000000000000LLU, 1000000000000000LLU, 10000000000000000LLU,
                  100000000000000000LLU, 1000000000000000000LLU,
                  10000000000000000000LLU };

        if (!v) {
                return ~0U;
        }
        /*
         * By the relationship "log10(v) = log2(v) / log2(10)", we need to
         * multiply "log2(v)" by "1 / log2(10)", which is approximately
         * 1233/4096, or (1233, followed by a right shift of 12).
         *
         * Finally, since the result is only an approximation that may be off
         * by one, the exact value is found by subtracting "v < PowersOf10[r]"
         * from the result.
         */
        r = ((msb(v) * 1233) >> 12) + 1;

        return r - (v < PowersOf10[r]);
}

मुझे परवाह नहीं है कि यह सवाल का जवाब देता है या नहीं - यह करने के लिए वास्तव में प्रभावशाली है। यह कुछ सोचा गया और इसे स्वीकार किया जाना चाहिए और इसकी प्रशंसा की जानी चाहिए। हो सकता है कि यह अच्छा होगा यदि आप किसी भी तरह (चाहे यहां या फिर) परीक्षण के लिए पूर्ण कोड शामिल करें, लेकिन इसके बिना भी यह वास्तव में एक अच्छा काम है। उस के लिए एक +1 है!
प्रिएफ्टन

0

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.