dtostr.c 9.5 KB

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