fork(4) download
  1. // file: PrintFullFraction.c
  2. //
  3. // compile with gcc 4.6.2 or better:
  4. // gcc -Wall -Wextra -std=c99 -O2 PrintFullFraction.c -o PrintFullFraction.exe
  5. #include <limits.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include <math.h>
  10. #include <float.h>
  11. #include <assert.h>
  12.  
  13. #if FLT_RADIX != 2
  14. #error currently supported only FLT_RADIX = 2
  15. #endif
  16.  
  17. int FractionalDigits(double d)
  18. {
  19. char buf[
  20. 1 + // sign, '-' or '+'
  21. (sizeof(d) * CHAR_BIT + 3) / 4 + // mantissa hex digits max
  22. 1 + // decimal point, '.'
  23. 1 + // mantissa-exponent separator, 'p'
  24. 1 + // mantissa sign, '-' or '+'
  25. (sizeof(d) * CHAR_BIT + 2) / 3 + // exponent decimal digits max
  26. 1 // string terminator, '\0'
  27. ];
  28. int n;
  29. char *pp, *p;
  30. int e, lsbFound, lsbPos;
  31.  
  32. // convert d into "+/- 0x h.hhhh p +/- ddd" representation and check for errors
  33. if ((n = snprintf(buf, sizeof(buf), "%+a", d)) < 0 ||
  34. (unsigned)n >= sizeof(buf))
  35. return -1;
  36.  
  37. //printf("{%s}", buf);
  38.  
  39. // make sure the conversion didn't produce something like "nan" or "inf"
  40. // instead of "+/- 0x h.hhhh p +/- ddd"
  41. if (strstr(buf, "0x") != buf + 1 ||
  42. (pp = strchr(buf, 'p')) == NULL)
  43. return 0;
  44.  
  45. // extract the base-2 exponent manually, checking for overflows
  46. e = 0;
  47. p = pp + 1 + (pp[1] == '-' || pp[1] == '+'); // skip the exponent sign at first
  48. for (; *p != '\0'; p++)
  49. {
  50. if (e > INT_MAX / 10)
  51. return -2;
  52. e *= 10;
  53. if (e > INT_MAX - (*p - '0'))
  54. return -2;
  55. e += *p - '0';
  56. }
  57. if (pp[1] == '-') // apply the sign to the exponent
  58. e = -e;
  59.  
  60. //printf("[%s|%d]", buf, e);
  61.  
  62. // find the position of the least significant non-zero bit
  63. lsbFound = lsbPos = 0;
  64. for (p = pp - 1; *p != 'x'; p--)
  65. {
  66. if (*p == '.')
  67. continue;
  68. if (!lsbFound)
  69. {
  70. int hdigit = (*p >= 'a') ? (*p - 'a' + 10) : (*p - '0'); // assuming ASCII chars
  71. if (hdigit)
  72. {
  73. static const int lsbPosInNibble[16] = { 0,4,3,4, 2,4,3,4, 1,4,3,4, 2,4,3,4 };
  74. lsbFound = 1;
  75. lsbPos = -lsbPosInNibble[hdigit];
  76. }
  77. }
  78. else
  79. {
  80. lsbPos -= 4;
  81. }
  82. }
  83. lsbPos += 4;
  84.  
  85. if (!lsbFound)
  86. return 0; // d is 0 (integer)
  87.  
  88. // adjust the least significant non-zero bit position
  89. // by the base-2 exponent (just add them), checking
  90. // for overflows
  91.  
  92. if (lsbPos >= 0 && e >= 0)
  93. return 0; // lsbPos + e >= 0, d is integer
  94.  
  95. if (lsbPos < 0 && e < 0)
  96. if (lsbPos < INT_MIN - e)
  97. return -2; // d isn't integer and needs too many fractional digits
  98.  
  99. if ((lsbPos += e) >= 0)
  100. return 0; // d is integer
  101.  
  102. if (lsbPos == INT_MIN && -INT_MAX != INT_MIN)
  103. return -2; // d isn't integer and needs too many fractional digits
  104.  
  105. return -lsbPos;
  106. }
  107.  
  108. const double testData[] =
  109. {
  110. 0,
  111. 1, // 2 ^ 0
  112. 0.5, // 2 ^ -1
  113. 0.25, // 2 ^ -2
  114. 0.125,
  115. 0.0625, // ...
  116. 0.03125,
  117. 0.015625,
  118. 0.0078125, // 2 ^ -7
  119. 1.0/256, // 2 ^ -8
  120. 1.0/256/256, // 2 ^ -16
  121. 1.0/256/256/256, // 2 ^ -24
  122. 1.0/256/256/256/256, // 2 ^ -32
  123. 1.0/256/256/256/256/256/256/256/256, // 2 ^ -64
  124. 3.14159265358979323846264338327950288419716939937510582097494459,
  125. 0.1,
  126. INFINITY,
  127. #ifdef NAN
  128. NAN,
  129. #endif
  130. DBL_MIN
  131. };
  132.  
  133. int main(void)
  134. {
  135. unsigned i;
  136. for (i = 0; i < sizeof(testData) / sizeof(testData[0]); i++)
  137. {
  138. int digits = FractionalDigits(testData[i]);
  139. assert(digits >= 0);
  140. printf("%f %e %.*f\n", testData[i], testData[i], digits, testData[i]);
  141. }
  142. return 0;
  143. }
  144.  
Success #stdin #stdout 0s 1832KB
stdin
Standard input is empty
stdout
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.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002225073858507201383090232717332404064219215980462331830553327416887204434813918195854283159012511020564067339731035811005152434161553460108856012385377718821130777993532002330479610147442583636071921565046942503734208375250806650616658158948720491179968591639648500635908770118304874799780887753749949451580451605050915399856582470818645113537935804992115981085766051992433352114352390148795699609591288891602992641511063466313393663477586513029371762047325631781485664350872122828637642044846811407613911477062801689853244110024161447421618567166150540154285084716752901903161322778896729707373123334086988983175067838846926092773977972858659654941091369095406136467568702398678315290680984617210924625396728515625