dtostr.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. /*
  2. * Copyright (C) 2000, 2001 Manuel Novoa III
  3. *
  4. * Function: int __dtostr(FILE * fp, size_t size, double x,
  5. * char flag[], int width, int preci, char mode)
  6. *
  7. * This was written for uClibc to provide floating point support for
  8. * the printf functions. It handles +/- infinity and nan on i386.
  9. *
  10. * Notes:
  11. *
  12. * At most MAX_DIGITS significant digits are kept. Any trailing digits
  13. * are treated as 0 as they are really just the results of rounding noise
  14. * anyway. If you want to do better, use an arbitary precision arithmetic
  15. * package. ;-)
  16. *
  17. * It should also be fairly portable, as not assumptions are made about the
  18. * bit-layout of doubles.
  19. *
  20. * It should be too difficult to convert this to handle long doubles on i386.
  21. * For information, see the comments below.
  22. *
  23. * TODO:
  24. * long double and/or float version? (note: for float can trim code some).
  25. *
  26. * Decrease the size. This is really much bigger than I'd like.
  27. */
  28. /*****************************************************************************/
  29. /* Don't change anything that follows unless you know what you're doing. */
  30. /*****************************************************************************/
  31. /*
  32. * Configuration for the scaling power table. Ignoring denormals, you
  33. * should have 2**EXP_TABLE_SIZE >= MAX_DBL_EXP >= 2**(EXP_TABLE_SIZE-1).
  34. * The minimum for standard C is 6. For IEEE 8bit doubles, 9 suffices.
  35. */
  36. #define EXP_TABLE_SIZE 9
  37. /*
  38. * Set this to the maximum number of digits you want converted.
  39. * Conversion is done in blocks of DIGITS_PER_BLOCK (9 by default) digits.
  40. * 17 digits suffices to uniquely determine a double on i386.
  41. */
  42. #define MAX_DIGITS 17
  43. /*
  44. * Set this to the smallest integer type capable of storing a pointer.
  45. */
  46. #define INT_OR_PTR int
  47. /*
  48. * This is really only used to check for infinities. The macro produces
  49. * smaller code for i386 and, since this is tested before any floating point
  50. * calculations, it doesn't appear to suffer from the excess precision problem
  51. * caused by the FPU that strtod had. If it causes problems, call the function
  52. * and compile zoicheck.c with -ffloat-store.
  53. */
  54. #if 1
  55. #define _zero_or_inf_check(x) ( x == (x/4) )
  56. #else
  57. extern int _zero_or_inf_check(double x);
  58. #endif
  59. /*
  60. * Fairly portable nan check. Bitwise for i386 generated larger code.
  61. * If you have a better version, comment this out.
  62. */
  63. #define isnan(x) (x != x)
  64. /*****************************************************************************/
  65. /* Don't change anything that follows peroid!!! ;-) */
  66. /*****************************************************************************/
  67. #include <stdio.h>
  68. #include <string.h>
  69. #include <assert.h>
  70. #include <float.h>
  71. #include <limits.h>
  72. extern int fnprintf(FILE * fp, size_t size, const char *fmt, ...);
  73. /* from printf.c -- should really be in an internal header file */
  74. enum {
  75. FLAG_PLUS = 0,
  76. FLAG_MINUS_LJUSTIFY,
  77. FLAG_HASH,
  78. FLAG_0_PAD,
  79. FLAG_SPACE,
  80. };
  81. /*****************************************************************************/
  82. /*
  83. * Set things up for the scaling power table.
  84. */
  85. #if EXP_TABLE_SIZE < 6
  86. #error EXP_TABLE_SIZE should be at least 6 to comply with standards
  87. #endif
  88. #define EXP_TABLE_MAX (1U<<(EXP_TABLE_SIZE-1))
  89. /*
  90. * Only bother checking if this is too small.
  91. * Throw in some play for denormals ( roughly O(-324) vs O(-307) on i386 ).
  92. */
  93. #if (3+DBL_DIG-DBL_MIN_10_EXP)/2 > EXP_TABLE_MAX
  94. #error larger EXP_TABLE_SIZE needed
  95. #endif
  96. /*
  97. * With 32 bit ints, we can get 9 digits per block.
  98. */
  99. #define DIGITS_PER_BLOCK 9
  100. #if (INT_MAX >> 30)
  101. #define DIGIT_BLOCK_TYPE int
  102. #define DB_FMT "%.*d"
  103. #elif (LONG_MAX >> 30)
  104. #define DIGIT_BLOCK_TYPE long
  105. #define DB_FMT "%.*ld"
  106. #else
  107. #error need at least 32 bit longs
  108. #endif
  109. /* Are there actually any machines where this might fail? */
  110. #if 'A' > 'a'
  111. #error ordering assumption violated : 'A' > 'a'
  112. #endif
  113. /* Maximum number of calls to fnprintf to output double. */
  114. #define MAX_CALLS 8
  115. /*****************************************************************************/
  116. #define NUM_DIGIT_BLOCKS ((MAX_DIGITS+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
  117. /* extra space for '-', '.', 'e+###', and nul */
  118. #define BUF_SIZE ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
  119. /*****************************************************************************/
  120. static const char *fmts[] = {
  121. "%0*d", "%.*s", ".", "inf", "INF", "nan", "NAN", "%*s"
  122. };
  123. /*****************************************************************************/
  124. int __dtostr(FILE * fp, size_t size, double x,
  125. char flag[], int width, int preci, char mode)
  126. {
  127. double exp_table[EXP_TABLE_SIZE];
  128. double p10;
  129. DIGIT_BLOCK_TYPE digit_block; /* int of at least 32 bits */
  130. int i, j;
  131. int round, o_exp;
  132. int exp, exp_neg;
  133. char *s;
  134. char *e;
  135. char buf[BUF_SIZE];
  136. INT_OR_PTR pc_fwi[2*MAX_CALLS];
  137. INT_OR_PTR *ppc;
  138. char exp_buf[8];
  139. char drvr[8];
  140. char *pdrvr;
  141. int npc;
  142. int cnt;
  143. char sign_str[2];
  144. char o_mode;
  145. /* check that INT_OR_PTR is sufficiently large */
  146. assert( sizeof(INT_OR_PTR) == sizeof(char *) );
  147. *sign_str = flag[FLAG_PLUS];
  148. *(sign_str+1) = 0;
  149. if (isnan(x)) { /* nan check */
  150. pdrvr = drvr + 1;
  151. *pdrvr++ = 5 + (mode < 'a');
  152. pc_fwi[2] = 3;
  153. flag[FLAG_0_PAD] = 0;
  154. goto EXIT_SPECIAL;
  155. }
  156. if (x == 0) { /* handle 0 now to avoid false positive */
  157. exp = -1;
  158. goto GENERATE_DIGITS;
  159. }
  160. if (x < 0) { /* convert negatives to positives */
  161. *sign_str = '-';
  162. x = -x;
  163. }
  164. if (_zero_or_inf_check(x)) { /* must be inf since zero handled above */
  165. pdrvr = drvr + 1;
  166. *pdrvr++ = 3 + + (mode < 'a');
  167. pc_fwi[2] = 3;
  168. flag[FLAG_0_PAD] = 0;
  169. goto EXIT_SPECIAL;
  170. }
  171. /* need to build the scaling table */
  172. for (i = 0, p10 = 10 ; i < EXP_TABLE_SIZE ; i++) {
  173. exp_table[i] = p10;
  174. p10 *= p10;
  175. }
  176. exp_neg = 0;
  177. if (x < 1e8) { /* do we need to scale up or down? */
  178. exp_neg = 1;
  179. }
  180. exp = DIGITS_PER_BLOCK - 1;
  181. i = EXP_TABLE_SIZE;
  182. j = EXP_TABLE_MAX;
  183. while ( i-- ) { /* scale x such that 1e8 <= x < 1e9 */
  184. if (exp_neg) {
  185. if (x * exp_table[i] < 1e9) {
  186. x *= exp_table[i];
  187. exp -= j;
  188. }
  189. } else {
  190. if (x / exp_table[i] >= 1e8) {
  191. x /= exp_table[i];
  192. exp += j;
  193. }
  194. }
  195. j >>= 1;
  196. }
  197. if (x >= 1e9) { /* handle bad rounding case */
  198. x /= 10;
  199. ++exp;
  200. }
  201. assert(x < 1e9);
  202. GENERATE_DIGITS:
  203. s = buf + 2; /* leave space for '\0' and '0' */
  204. for (i = 0 ; i < NUM_DIGIT_BLOCKS ; ++i ) {
  205. digit_block = (DIGIT_BLOCK_TYPE) x;
  206. x = (x - digit_block) * 1e9;
  207. s += sprintf(s, DB_FMT, DIGITS_PER_BLOCK, digit_block);
  208. }
  209. /*************************************************************************/
  210. *exp_buf = 'e';
  211. if (mode < 'a') {
  212. *exp_buf = 'E';
  213. mode += ('a' - 'A');
  214. }
  215. o_mode = mode;
  216. round = preci;
  217. if ((mode == 'g') && (round > 0)){
  218. --round;
  219. }
  220. if (mode == 'f') {
  221. round += exp;
  222. }
  223. s = buf;
  224. *s++ = 0; /* terminator for rounding and 0-triming */
  225. *s = '0'; /* space to round */
  226. i = 0;
  227. e = s + MAX_DIGITS + 1;
  228. if (round < MAX_DIGITS) {
  229. e = s + round + 2;
  230. if (*e >= '5') {
  231. i = 1;
  232. }
  233. }
  234. do { /* handle rounding and trim trailing 0s */
  235. *--e += i; /* add the carry */
  236. } while ((*e == '0') || (*e > '9'));
  237. o_exp = exp;
  238. if (e <= s) { /* we carried into extra digit */
  239. ++o_exp;
  240. e = s; /* needed if all 0s */
  241. } else {
  242. ++s;
  243. }
  244. *++e = 0; /* ending nul char */
  245. if ((mode == 'g') && ((o_exp >= -4) && (o_exp < round))) {
  246. mode = 'f';
  247. }
  248. exp = o_exp;
  249. if (mode != 'f') {
  250. o_exp = 0;
  251. }
  252. if (o_exp < 0) {
  253. *--s = '0'; /* fake the first digit */
  254. }
  255. pdrvr = drvr+1;
  256. ppc = pc_fwi+2;
  257. *pdrvr++ = 0;
  258. *ppc++ = 1;
  259. *ppc++ = (INT_OR_PTR)(*s++ - '0');
  260. i = e - s; /* total digits */
  261. if (o_exp >= 0) {
  262. if (o_exp >= i) { /* all digit(s) left of decimal */
  263. *pdrvr++ = 1;
  264. *ppc++ = i;
  265. *ppc++ = (INT_OR_PTR)(s);
  266. o_exp -= i;
  267. i = 0;
  268. if (o_exp>0) { /* have 0s left of decimal */
  269. *pdrvr++ = 0;
  270. *ppc++ = o_exp;
  271. *ppc++ = 0;
  272. }
  273. } else if (o_exp > 0) { /* decimal between digits */
  274. *pdrvr++ = 1;
  275. *ppc++ = o_exp;
  276. *ppc++ = (INT_OR_PTR)(s);
  277. s += o_exp;
  278. i -= o_exp;
  279. }
  280. o_exp = -1;
  281. }
  282. if (flag[FLAG_HASH] || (i) || ((o_mode != 'g') && (preci > 0))) {
  283. *pdrvr++ = 2; /* need decimal */
  284. *ppc++ = 1; /* needed for width calc */
  285. ppc++;
  286. }
  287. if (++o_exp < 0) { /* have 0s right of decimal */
  288. *pdrvr++ = 0;
  289. *ppc++ = -o_exp;
  290. *ppc++ = 0;
  291. }
  292. if (i) { /* have digit(s) right of decimal */
  293. *pdrvr++ = 1;
  294. *ppc++ = i;
  295. *ppc++ = (INT_OR_PTR)(s);
  296. }
  297. if (o_mode != 'g') {
  298. i -= o_exp;
  299. if (i < preci) { /* have 0s right of digits */
  300. i = preci - i;
  301. *pdrvr++ = 0;
  302. *ppc++ = i;
  303. *ppc++ = 0;
  304. }
  305. }
  306. /* build exponent string */
  307. if (mode != 'f') {
  308. *pdrvr++ = 1;
  309. *ppc++ = sprintf(exp_buf,"%c%+.2d", *exp_buf, exp);
  310. *ppc++ = (INT_OR_PTR) exp_buf;
  311. }
  312. EXIT_SPECIAL:
  313. npc = pdrvr - drvr;
  314. ppc = pc_fwi + 2;
  315. for (i=1 ; i< npc ; i++) {
  316. width -= *(ppc++);
  317. ppc++;
  318. }
  319. i = 0;
  320. if (*sign_str) {
  321. i = 1;
  322. }
  323. width -= i;
  324. if (width <= 0) {
  325. width = 0;
  326. } else {
  327. if (flag[FLAG_MINUS_LJUSTIFY]) { /* padding on right */
  328. ++npc;
  329. *pdrvr++ = 7;
  330. *ppc = width;
  331. *++ppc = (INT_OR_PTR)("");
  332. width = 0;
  333. } else if (flag[FLAG_0_PAD] == '0') { /* 0 padding */
  334. pc_fwi[2] += width;
  335. width = 0;
  336. }
  337. }
  338. *drvr = 7;
  339. ppc = pc_fwi;
  340. *ppc++ = width + i;
  341. *ppc = (INT_OR_PTR) sign_str;
  342. pdrvr = drvr;
  343. ppc = pc_fwi;
  344. cnt = 0;
  345. for (i=0 ; i<npc ; i++) {
  346. #if 1
  347. fnprintf(fp, size, fmts[(int)(*pdrvr++)], (INT_OR_PTR)(*(ppc)),
  348. (INT_OR_PTR)(*(ppc+1)));
  349. #else
  350. j = fnprintf(fp, size, fmts[(int)(*pdrvr++)], (INT_OR_PTR)(*(ppc)),
  351. (INT_OR_PTR)(*(ppc+1)));
  352. assert(j == *ppc);
  353. #endif
  354. if (size > *ppc) {
  355. size -= *ppc;
  356. }
  357. cnt += *ppc; /* to avoid problems if j == -1 */
  358. ppc += 2;
  359. }
  360. return cnt;
  361. }