शायद कोई आसान तरीका नहीं है। यह एक काफी शामिल समस्या है।
आपका कोड कई कारणों से सही इसे सुलझाने नहीं है:
- फ्लोटिंग प्वाइंट अंकगणित दशमलव में नहीं कर रहे हैं के अधिकांश व्यावहारिक कार्यान्वयन, वे बाइनरी हैं। इसलिए, जब आप फ्लोटिंग-पॉइंट नंबर 10 से गुणा करते हैं या इसे 10 तक विभाजित करते हैं, तो आप सटीकता खो सकते हैं (यह संख्या पर निर्भर करता है)।
- हालांकि मानक
64-bit IEEE-754
फ्लोटिंग प्वाइंट प्रारूप भंडार अपूर्णांश, जो floor(log10(2^53))
= 15
दशमलव अंक के बराबर है के लिए 53
बिट्स, इस प्रारूप में एक वैध संख्या कुछ 1080
दशमलव अंक के लिए आंशिक में आवश्यकता हो सकती है भाग जब बिल्कुल मुद्रित होता है, तो आप यही पूछते हैं।
इस के हल के लिए एक तरह से snprintf()
में %a
प्रारूप प्रकार निर्दिष्टकर्ता, जो अपूर्णांश और 1999 की गारंटी देता है कि यह सब प्रिंट होगा से सी मानक के लिए हेक्साडेसिमल अंक का उपयोग कर फ़्लोटिंग-बिंदु मान मुद्रित करने के लिए जा रहा है उपयोग करने के लिए है महत्वपूर्ण अंक यदि फ्लोटिंग-पॉइंट प्रारूप रेडिक्स -2 (एकेए बेस -2 या बस बाइनरी) है। तो, इसके साथ आप संख्या के मंटिसा के सभी द्विआधारी अंक प्राप्त कर सकते हैं। और यहां से आप यह पता लगाने में सक्षम होंगे कि आंशिक भाग में कितने दशमलव अंक हैं।
अब, देखें कि:
1।00000 = 2 +0 = 1,00000 (बाइनरी)
0,50000 = 2 -1 = 0,10000
0,25000 = 2 -2 = 0,01000
0,12500 = 2 -3 = 0,00100
0,06250 = 2 -4 = 0,00010
0,03125 = 2 -5 = 0,00001
और इतने पर।
आप स्पष्ट रूप से देख सकते हैं कि i
द्विआधारी प्रतिनिधित्व में बिंदु के दाईं करने के लिए मई के स्थान पर एक बाइनरी अंक के अधिकार के लिए i
वें स्थिति में भी पिछले गैर शून्य दशमलव अंकों का उत्पादन दशमलव प्रतिनिधित्व में बिंदु।
तो, यदि आपको पता है कि कम से कम महत्वपूर्ण गैर-शून्य बिट बाइनरी फ़्लोटिंग-पॉइंट नंबर में है, तो आप यह पता लगा सकते हैं कि संख्या के आंशिक भाग को मुद्रित करने के लिए कितने दशमलव अंकों की आवश्यकता है।
और यह मेरा प्रोग्राम कर रहा है।
कोड:
// file: PrintFullFraction.c
//
// compile with gcc 4.6.2 or better:
// gcc -Wall -Wextra -std=c99 -O2 PrintFullFraction.c -o PrintFullFraction.exe
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <assert.h>
#if FLT_RADIX != 2
#error currently supported only FLT_RADIX = 2
#endif
int FractionalDigits(double d)
{
char buf[
1 + // sign, '-' or '+'
(sizeof(d) * CHAR_BIT + 3)/4 + // mantissa hex digits max
1 + // decimal point, '.'
1 + // mantissa-exponent separator, 'p'
1 + // mantissa sign, '-' or '+'
(sizeof(d) * CHAR_BIT + 2)/3 + // exponent decimal digits max
1 // string terminator, '\0'
];
int n;
char *pp, *p;
int e, lsbFound, lsbPos;
// convert d into "+/- 0x h.hhhh p +/- ddd" representation and check for errors
if ((n = snprintf(buf, sizeof(buf), "%+a", d)) < 0 ||
(unsigned)n >= sizeof(buf))
return -1;
//printf("{%s}", buf);
// make sure the conversion didn't produce something like "nan" or "inf"
// instead of "+/- 0x h.hhhh p +/- ddd"
if (strstr(buf, "0x") != buf + 1 ||
(pp = strchr(buf, 'p')) == NULL)
return 0;
// extract the base-2 exponent manually, checking for overflows
e = 0;
p = pp + 1 + (pp[1] == '-' || pp[1] == '+'); // skip the exponent sign at first
for (; *p != '\0'; p++)
{
if (e > INT_MAX/10)
return -2;
e *= 10;
if (e > INT_MAX - (*p - '0'))
return -2;
e += *p - '0';
}
if (pp[1] == '-') // apply the sign to the exponent
e = -e;
//printf("[%s|%d]", buf, e);
// find the position of the least significant non-zero bit
lsbFound = lsbPos = 0;
for (p = pp - 1; *p != 'x'; p--)
{
if (*p == '.')
continue;
if (!lsbFound)
{
int hdigit = (*p >= 'a') ? (*p - 'a' + 10) : (*p - '0'); // assuming ASCII chars
if (hdigit)
{
static const int lsbPosInNibble[16] = { 0,4,3,4, 2,4,3,4, 1,4,3,4, 2,4,3,4 };
lsbFound = 1;
lsbPos = -lsbPosInNibble[hdigit];
}
}
else
{
lsbPos -= 4;
}
}
lsbPos += 4;
if (!lsbFound)
return 0; // d is 0 (integer)
// adjust the least significant non-zero bit position
// by the base-2 exponent (just add them), checking
// for overflows
if (lsbPos >= 0 && e >= 0)
return 0; // lsbPos + e >= 0, d is integer
if (lsbPos < 0 && e < 0)
if (lsbPos < INT_MIN - e)
return -2; // d isn't integer and needs too many fractional digits
if ((lsbPos += e) >= 0)
return 0; // d is integer
if (lsbPos == INT_MIN && -INT_MAX != INT_MIN)
return -2; // d isn't integer and needs too many fractional digits
return -lsbPos;
}
const double testData[] =
{
0,
1, // 2^0
0.5, // 2^-1
0.25, // 2^-2
0.125,
0.0625, // ...
0.03125,
0.015625,
0.0078125, // 2^-7
1.0/256, // 2^-8
1.0/256/256, // 2^-16
1.0/256/256/256, // 2^-24
1.0/256/256/256/256, // 2^-32
1.0/256/256/256/256/256/256/256/256, // 2^-64
3.14159265358979323846264338327950288419716939937510582097494459,
0.1,
INFINITY,
#ifdef NAN
NAN,
#endif
DBL_MIN
};
int main(void)
{
unsigned i;
for (i = 0; i < sizeof(testData)/sizeof(testData[0]); i++)
{
int digits = FractionalDigits(testData[i]);
assert(digits >= 0);
printf("%f %e %.*f\n", testData[i], testData[i], digits, testData[i]);
}
return 0;
}
आउटपुट (ideone):
0.000000 0.000000e+00 0
1.000000 1.000000e+00 1
0.500000 5.000000e-01 0.5
0.250000 2.500000e-01 0.25
0.125000 1.250000e-01 0.125
0.062500 6.250000e-02 0.0625
0.031250 3.125000e-02 0.03125
0.015625 1.562500e-02 0.015625
0.007812 7.812500e-03 0.0078125
0.003906 3.906250e-03 0.00390625
0.000015 1.525879e-05 0.0000152587890625
0.000000 5.960464e-08 0.000000059604644775390625
0.000000 2.328306e-10 0.00000000023283064365386962890625
0.000000 5.421011e-20 0.0000000000000000000542101086242752217003726400434970855712890625
3.141593 3.141593e+00 3.141592653589793115997963468544185161590576171875
0.100000 1.000000e-01 0.1000000000000000055511151231257827021181583404541015625
inf inf inf
nan nan nan
0.000000 2.225074e-308 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002225073858507201383090232717332404064219215980462331830553327416887204434813918195854283159012511020564067339731035811005152434161553460108856
आपको लगता है कि π
और 0.1
केवल 15
दशमलव अंक के लिए सही ऊपर और के बाकी देख सकते हैं अंक दिखाते हैं कि संख्या वास्तव में क्या मिल गई है क्योंकि इन संख्याओं को वास्तव में बाइनरी फ़्लोटिंग-पॉइंट प्रारूप में प्रदर्शित नहीं किया जा सकता है।
आप यह भी देख सकते हैं कि DBL_MIN
, छोटी से छोटी सकारात्मक सामान्यीकृत double
मूल्य, आंशिक भाग में 1022
अंक होते हैं और उन में से 715
महत्वपूर्ण अंक देखते हैं। इस समाधान के साथ
संभावित मुद्दों:
- आपका संकलक के
printf()
कार्यों %a
का समर्थन नहीं करते या सही ढंग से सभी अंक परिशुद्धता द्वारा अनुरोध मुद्रित नहीं की है (यह बहुत संभव है)।
- आपका कंप्यूटर गैर-बाइनरी फ़्लोटिंग-पॉइंट प्रारूपों का उपयोग करता है (यह बेहद दुर्लभ है)।
आप 'स्प्रिंटफ (लाइन,"%। * एफ ", पीएल, डी) का उपयोग कर सकते हैं;' 'स्विच 'के बजाय। –