dtostr.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * Copyright (C) 2000 Manuel Novoa III
  3. *
  4. * Function: const char *__dtostr(double x)
  5. *
  6. * This was written for uClibc to give it the ability to at least output
  7. * floating point values in exponential form. No formatting is done.
  8. * No trailing 0's are removed. Number of digits generated is not
  9. * runtime selectable. It does however handle +/- infinity and nan on i386.
  10. *
  11. * The goal was usable floating point %e-type output in minimal size. For
  12. * me, "gcc -c -Os -fomit-frame-pointer dtostr.c && size dtostr.o" gives
  13. * text data bss dec hex filename
  14. * 535 9 26 570 23a dtostr.o (WANT_EXP_FORM = 1)
  15. * 530 9 26 565 235 dtostr.o (WANT_EXP_FORM = 0)
  16. *
  17. * Output is of the form [-][#].######{e|E}{+|-}##. Choices of upper or
  18. * lower case exponent character, and initial digit/initial decimal forms
  19. * are compile-time options. Number of digits generated is also selected
  20. * at compile time (MAX_DIGITS).
  21. *
  22. * Notes:
  23. *
  24. * The primary objective of this implementation was minimal size while
  25. * maintaining reasonable accuracy. It should also be fairly portable,
  26. * as not assumptions are made about the bit-layout of doubles.
  27. *
  28. * It should be too difficult to convert this to handle long doubles on i386.
  29. * For information, see the comments below.
  30. *
  31. * There are 2 compile-time options below, as well as some tuning parameters.
  32. *
  33. * TODO:
  34. * long double and/or float version? (note: for float can trim code some).
  35. */
  36. /*****************************************************************************/
  37. /* OPTIONS */
  38. /*****************************************************************************/
  39. /*
  40. * Set this if you want output results with 1 digit before the decimal point.
  41. * If this is 0, all digits follow a leading decimal point.
  42. */
  43. #define WANT_EXP_FORM 1
  44. /*
  45. * Set if you want exponent character 'E' rather than 'e'.
  46. */
  47. #define EXP_UPPERCASE 1
  48. /*****************************************************************************/
  49. /* Don't change anything that follows unless you know what you're doing. */
  50. /*****************************************************************************/
  51. /*
  52. * Configuration for the scaling power table. Ignoring denormals, you
  53. * should have 2**EXP_TABLE_SIZE >= MAX_DBL_EXP >= 2**(EXP_TABLE_SIZE-1).
  54. * The minimum for standard C is 6. For IEEE 8bit doubles, 9 suffices.
  55. */
  56. #define EXP_TABLE_SIZE 9
  57. /*
  58. * Set this to the maximum number of digits you want converted.
  59. * Conversion is done in blocks of DIGITS_PER_BLOCK (9 by default) digits.
  60. * 17 digits suffices to uniquely determine a double on i386.
  61. */
  62. #define MAX_DIGITS 17
  63. /*
  64. * This is really only used to check for infinities. The macro produces
  65. * smaller code for i386 and, since this is tested before any floating point
  66. * calculations, it doesn't appear to suffer from the excess precision problem
  67. * caused by the FPU that strtod had. If it causes problems, call the function
  68. * and compile zoicheck.c with -ffloat-store.
  69. */
  70. #if 1
  71. #define _zero_or_inf_check(x) ( x == (x/4) )
  72. #else
  73. extern int _zero_or_inf_check(double x);
  74. #endif
  75. /*
  76. * Fairly portable nan check. Bitwise for i386 generated larger code.
  77. * If you have a better version, comment this out.
  78. */
  79. #define isnan(x) (x != x)
  80. /*****************************************************************************/
  81. /* Don't change anything that follows peroid!!! ;-) */
  82. /*****************************************************************************/
  83. #include <float.h>
  84. #include <limits.h>
  85. /*
  86. * Set things up for the scaling power table.
  87. */
  88. #if EXP_TABLE_SIZE < 6
  89. #error EXP_TABLE_SIZE should be at least 6 to comply with standards
  90. #endif
  91. #define EXP_TABLE_MAX (1U<<(EXP_TABLE_SIZE-1))
  92. /*
  93. * Only bother checking if this is too small.
  94. * Throw in some play for denormals ( roughly O(-324) vs O(-307) on i386 ).
  95. */
  96. #if (3+DBL_DIG-DBL_MIN_10_EXP)/2 > EXP_TABLE_MAX
  97. #error larger EXP_TABLE_SIZE needed
  98. #endif
  99. /*
  100. * With 32 bit ints, we can get 9 digits per block.
  101. */
  102. #define DIGITS_PER_BLOCK 9
  103. #if (INT_MAX >> 30)
  104. #define DIGIT_BLOCK_TYPE int
  105. #elif (LONG_MAX >> 30)
  106. #define DIGIT_BLOCK_TYPE long
  107. #else
  108. #error need at least 32 bit longs
  109. #endif
  110. /*
  111. * This is kind of a place-holder for LONG_DOUBLE support to show what I
  112. * think needs to be changed. I haven't tried it though. Changing this
  113. * from 3 to 4 and converting double to long double should work on i386.
  114. * DON'T FORGET to increase EXP_TABLE_SIZE and MAX_DIGITS.
  115. * DON'T FORGET the "larger EXP_TABLE_SIZE needed" check above.
  116. */
  117. #define MAX_EXP_DIGITS 3
  118. /*****************************************************************************/
  119. #define NUM_DIGIT_BLOCKS ((MAX_DIGITS+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
  120. static char infstr[] = " inf"; /* save space for a - sign */
  121. static char nanstr[] = "nan";
  122. /* extra space for '-', '.', 'e+###', and nul */
  123. /*static char buf[ 5 + MAX_EXP_DIGITS + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK];*/
  124. #define BUF_SIZE ( 5 + MAX_EXP_DIGITS + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
  125. /*****************************************************************************/
  126. const char *__dtostr(char *buf, double x)
  127. {
  128. double exp_table[EXP_TABLE_SIZE];
  129. double p10;
  130. DIGIT_BLOCK_TYPE digit_block; /* int of at least 32 bits */
  131. int i, j;
  132. int exp, exp_neg;
  133. int negative = 0;
  134. char *pos;
  135. if (isnan(x)) { /* nan check */
  136. return nanstr;
  137. }
  138. if (x == 0) { /* handle 0 now to avoid false positive */
  139. exp = 0; /* with inf test, and to avoid scaling */
  140. goto GENERATE_DIGITS; /* note: time vs space tradeoff */
  141. }
  142. if (x < 0) { /* convert negatives to positives */
  143. negative = 1;
  144. x = -x;
  145. }
  146. if (_zero_or_inf_check(x)) { /* must be inf since zero handled above */
  147. pos = infstr + 1;
  148. goto DO_SIGN;
  149. }
  150. /* need to build the scaling table */
  151. for (i = 0, p10 = 10 ; i < EXP_TABLE_SIZE ; i++) {
  152. exp_table[i] = p10;
  153. p10 *= p10;
  154. }
  155. exp_neg = 0;
  156. if (x < 1e8) { /* do we need to scale up or down? */
  157. exp_neg = 1;
  158. }
  159. #if WANT_EXP_FORM
  160. exp = DIGITS_PER_BLOCK - 1;
  161. #else
  162. exp = DIGITS_PER_BLOCK;
  163. #endif
  164. i = EXP_TABLE_SIZE;
  165. j = EXP_TABLE_MAX;
  166. while ( i-- ) { /* scale x such that 1e8 <= x < 1e9 */
  167. if (exp_neg) {
  168. if (x * exp_table[i] < 1e9) {
  169. x *= exp_table[i];
  170. exp -= j;
  171. }
  172. } else {
  173. if (x / exp_table[i] >= 1e8) {
  174. x /= exp_table[i];
  175. exp += j;
  176. }
  177. }
  178. j >>= 1;
  179. }
  180. GENERATE_DIGITS:
  181. pos = buf - BUF_SIZE + 1 + DIGITS_PER_BLOCK + 1; /* leave space for '.' and - */
  182. for (i = 0 ; i < NUM_DIGIT_BLOCKS ; ++i ) {
  183. digit_block = (int) x;
  184. x = (x - digit_block) * 1e9;
  185. for (j = 0 ; j < DIGITS_PER_BLOCK ; j++) {
  186. *--pos = '0' + (digit_block % 10);
  187. digit_block /= 10;
  188. }
  189. pos += (2*DIGITS_PER_BLOCK);
  190. }
  191. pos -= (DIGITS_PER_BLOCK*(NUM_DIGIT_BLOCKS+1))-MAX_DIGITS;
  192. /* start generating the exponent */
  193. #if EXP_UPPERCASE
  194. *pos = 'E';
  195. #else
  196. *pos = 'e';
  197. #endif
  198. *++pos = '+';
  199. if (exp < 0) {
  200. *pos = '-';
  201. exp = -exp;
  202. }
  203. pos += 3; /* WARNING: Assumes max exp < 1000!!! */
  204. if (exp >= 100) {
  205. ++pos;
  206. #if MAX_EXP_DIGITS > 4
  207. #error need to modify exponent string generation code
  208. #elif MAX_EXP_DIGITS > 3
  209. if (exp >= 1000) { /* WARNING: hasn't been checked */
  210. ++pos; /* but should work */
  211. }
  212. #endif
  213. }
  214. *pos = '\0';
  215. for (j = 0 ; (j < 2) || exp ; j++) { /* standard says at least 2 digits */
  216. *--pos = '0' + (exp % 10);
  217. exp /= 10;
  218. }
  219. /* insert the decimal point */
  220. pos = buf - BUF_SIZE + 1;
  221. #if WANT_EXP_FORM
  222. *pos = *(pos+1);
  223. *(pos+1) = '.';
  224. #else
  225. *pos = '.';
  226. #endif
  227. DO_SIGN:
  228. if (negative) {
  229. *--pos = '-';
  230. }
  231. return pos;
  232. }