You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

fpconv.c 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. #include <stdbool.h>
  2. #include <string.h>
  3. #include <sys/param.h>
  4. #include "fpconv.h"
  5. #include "powers.h"
  6. #define fracmask 0x000FFFFFFFFFFFFFU
  7. #define expmask 0x7FF0000000000000U
  8. #define hiddenbit 0x0010000000000000U
  9. #define signmask 0x8000000000000000U
  10. #define expbias (1023 + 52)
  11. #define absv(n) ((n) < 0 ? -(n) : (n))
  12. #define minv(a, b) ((a) < (b) ? (a) : (b))
  13. static uint64_t tens[] = {
  14. 10000000000000000000U, 1000000000000000000U, 100000000000000000U,
  15. 10000000000000000U, 1000000000000000U, 100000000000000U,
  16. 10000000000000U, 1000000000000U, 100000000000U,
  17. 10000000000U, 1000000000U, 100000000U,
  18. 10000000U, 1000000U, 100000U,
  19. 10000U, 1000U, 100U,
  20. 10U, 1U
  21. };
  22. static inline uint64_t get_dbits (double d) {
  23. union {
  24. double dbl;
  25. uint64_t i;
  26. } dbl_bits = {d};
  27. return dbl_bits.i;
  28. }
  29. static Fp build_fp (double d) {
  30. uint64_t bits = get_dbits (d);
  31. Fp fp;
  32. fp.frac = bits & fracmask;
  33. fp.exp = (bits & expmask) >> 52u;
  34. if (fp.exp) {
  35. fp.frac += hiddenbit;
  36. fp.exp -= expbias;
  37. }
  38. else {
  39. fp.exp = -expbias + 1;
  40. }
  41. return fp;
  42. }
  43. static void normalize (Fp *fp) {
  44. while ((fp->frac & hiddenbit) == 0) {
  45. fp->frac <<= 1u;
  46. fp->exp--;
  47. }
  48. const unsigned int shift = 64 - 52 - 1;
  49. fp->frac <<= shift;
  50. fp->exp -= shift;
  51. }
  52. static void get_normalized_boundaries (Fp *fp, Fp *lower, Fp *upper) {
  53. upper->frac = (fp->frac << 1u) + 1u;
  54. upper->exp = fp->exp - 1u;
  55. while ((upper->frac & (hiddenbit << 1u)) == 0) {
  56. upper->frac <<= 1u;
  57. upper->exp--;
  58. }
  59. const unsigned int u_shift = 64 - 52 - 2;
  60. upper->frac <<= u_shift;
  61. upper->exp = upper->exp - u_shift;
  62. unsigned int l_shift = fp->frac == hiddenbit ? 2u : 1u;
  63. lower->frac = (fp->frac << l_shift) - 1;
  64. lower->exp = fp->exp - l_shift;
  65. lower->frac <<= lower->exp - upper->exp;
  66. lower->exp = upper->exp;
  67. }
  68. static Fp multiply (Fp *a, Fp *b) {
  69. const uint64_t lomask = 0x00000000FFFFFFFFu;
  70. uint64_t ah_bl = (a->frac >> 32u) * (b->frac & lomask);
  71. uint64_t al_bh = (a->frac & lomask) * (b->frac >> 32u);
  72. uint64_t al_bl = (a->frac & lomask) * (b->frac & lomask);
  73. uint64_t ah_bh = (a->frac >> 32u) * (b->frac >> 32u);
  74. uint64_t tmp = (ah_bl & lomask) + (al_bh & lomask) + (al_bl >> 32u);
  75. /* round up */
  76. tmp += 1U << 31u;
  77. Fp fp = {
  78. ah_bh + (ah_bl >> 32u) + (al_bh >> 32u) + (tmp >> 32u),
  79. a->exp + b->exp + 64u
  80. };
  81. return fp;
  82. }
  83. static void round_digit (char *digits, int ndigits, uint64_t delta, uint64_t rem, uint64_t kappa, uint64_t frac) {
  84. while (rem < frac && delta - rem >= kappa &&
  85. (rem + kappa < frac || frac - rem > rem + kappa - frac)) {
  86. digits[ndigits - 1]--;
  87. rem += kappa;
  88. }
  89. }
  90. static int generate_digits (Fp *fp, Fp *upper, Fp *lower, char *digits, int *K) {
  91. uint64_t wfrac = upper->frac - fp->frac;
  92. uint64_t delta = upper->frac - lower->frac;
  93. Fp one;
  94. one.frac = 1ULL << -upper->exp;
  95. one.exp = upper->exp;
  96. uint64_t part1 = upper->frac >> -one.exp;
  97. uint64_t part2 = upper->frac & (one.frac - 1);
  98. int idx = 0, kappa = 10;
  99. uint64_t *divp;
  100. /* 1000000000 */
  101. for (divp = tens + 10; kappa > 0; divp++) {
  102. uint64_t div = *divp;
  103. unsigned digit = part1 / div;
  104. if (digit || idx) {
  105. digits[idx++] = digit + '0';
  106. }
  107. part1 -= digit * div;
  108. kappa--;
  109. uint64_t tmp = (part1 << -one.exp) + part2;
  110. if (tmp <= delta) {
  111. *K += kappa;
  112. round_digit (digits, idx, delta, tmp, div << -one.exp, wfrac);
  113. return idx;
  114. }
  115. }
  116. /* 10 */
  117. uint64_t *unit = tens + 18;
  118. while (true) {
  119. part2 *= 10;
  120. delta *= 10;
  121. kappa--;
  122. unsigned digit = part2 >> -one.exp;
  123. if (digit || idx) {
  124. digits[idx++] = digit + '0';
  125. }
  126. part2 &= one.frac - 1;
  127. if (part2 < delta) {
  128. *K += kappa;
  129. round_digit (digits, idx, delta, part2, one.frac, wfrac * *unit);
  130. return idx;
  131. }
  132. unit--;
  133. }
  134. }
  135. static int grisu2 (double d, char *digits, int *K) {
  136. Fp w = build_fp (d);
  137. Fp lower, upper;
  138. get_normalized_boundaries (&w, &lower, &upper);
  139. normalize (&w);
  140. int k;
  141. Fp cp = find_cachedpow10 (upper.exp, &k);
  142. w = multiply (&w, &cp);
  143. upper = multiply (&upper, &cp);
  144. lower = multiply (&lower, &cp);
  145. lower.frac++;
  146. upper.frac--;
  147. *K = -k;
  148. return generate_digits (&w, &upper, &lower, digits, K);
  149. }
  150. static inline int emit_integer (char *digits, int ndigits,
  151. char *dest, int K, bool neg,
  152. unsigned precision)
  153. {
  154. char *d = dest;
  155. memcpy (d, digits, ndigits);
  156. d += ndigits;
  157. memset (d, '0', K);
  158. d += K;
  159. precision = MIN(precision, FPCONV_BUFLEN - (ndigits + K + 1));
  160. if (precision) {
  161. *d++ = '.';
  162. memset (d, '0', precision);
  163. d += precision;
  164. }
  165. return d - dest;
  166. }
  167. static inline int emit_scientific_digits (char *digits, int ndigits,
  168. char *dest, int K, bool neg,
  169. unsigned precision, int exp)
  170. {
  171. /* write decimal w/ scientific notation */
  172. ndigits = minv(ndigits, 18 - neg);
  173. int idx = 0;
  174. dest[idx++] = digits[0];
  175. if (ndigits > 1) {
  176. dest[idx++] = '.';
  177. memcpy(dest + idx, digits + 1, ndigits - 1);
  178. idx += ndigits - 1;
  179. }
  180. dest[idx++] = 'e';
  181. char sign = K + ndigits - 1 < 0 ? '-' : '+';
  182. dest[idx++] = sign;
  183. int cent = 0;
  184. if (exp > 99) {
  185. cent = exp / 100;
  186. dest[idx++] = cent + '0';
  187. exp -= cent * 100;
  188. }
  189. if (exp > 9) {
  190. int dec = exp / 10;
  191. dest[idx++] = dec + '0';
  192. exp -= dec * 10;
  193. }
  194. else if (cent) {
  195. dest[idx++] = '0';
  196. }
  197. dest[idx++] = exp % 10 + '0';
  198. return idx;
  199. }
  200. static inline int emit_fixed_digits (char *digits, int ndigits,
  201. char *dest, int K, bool neg,
  202. unsigned precision, int exp)
  203. {
  204. int offset = ndigits - absv(K), to_print;
  205. /* fp < 1.0 -> write leading zero */
  206. if (K < 0) {
  207. if (offset <= 0) {
  208. if (precision) {
  209. if (-offset >= precision) {
  210. /* Just print 0.[0]{precision} */
  211. dest[0] = '0';
  212. dest[1] = '.';
  213. memset(dest + 2, '0', precision);
  214. return precision + 2;
  215. }
  216. to_print = MAX(ndigits - offset, precision);
  217. }
  218. else {
  219. to_print = ndigits - offset;
  220. }
  221. if (to_print <= FPCONV_BUFLEN - 3) {
  222. offset = -offset;
  223. dest[0] = '0';
  224. dest[1] = '.';
  225. memset(dest + 2, '0', offset);
  226. if (precision) {
  227. /* The case where offset > precision is covered previously */
  228. precision -= offset;
  229. if (precision <= ndigits) {
  230. /* Truncate or leave as is */
  231. memcpy(dest + offset + 2, digits, precision);
  232. return precision + 2 + offset;
  233. }
  234. else {
  235. /* Expand */
  236. memcpy(dest + offset + 2, digits, ndigits);
  237. precision -= ndigits;
  238. memset(dest + offset + 2 + ndigits, '0', precision);
  239. return ndigits + 2 + offset + precision;
  240. }
  241. }
  242. else {
  243. memcpy(dest + offset + 2, digits, ndigits);
  244. }
  245. return ndigits + 2 + offset;
  246. }
  247. else {
  248. return emit_scientific_digits (digits, ndigits, dest, K, neg, precision, exp);
  249. }
  250. }
  251. else {
  252. /*
  253. * fp > 1.0, if offset > 0 then we have less digits than
  254. * fp exponent, so we need to switch to scientific notation to
  255. * display number at least more or less precisely
  256. */
  257. if (offset > 0 && ndigits <= FPCONV_BUFLEN - 3) {
  258. char *d = dest;
  259. memcpy(d, digits, offset);
  260. d += offset;
  261. *d++ = '.';
  262. ndigits -= offset;
  263. if (precision) {
  264. if (ndigits >= precision) {
  265. /* Truncate or leave as is */
  266. memcpy(d, digits + offset, precision);
  267. d += precision;
  268. }
  269. else {
  270. /* Expand */
  271. memcpy(d, digits + offset, ndigits);
  272. precision -= ndigits;
  273. d += ndigits;
  274. /* Check if we have enough bufspace */
  275. if ((d - dest) + precision <= FPCONV_BUFLEN) {
  276. memset (d, '0', precision);
  277. d += precision;
  278. }
  279. else {
  280. memset (d, '0', FPCONV_BUFLEN - (d - dest));
  281. d += FPCONV_BUFLEN - (d - dest);
  282. }
  283. }
  284. }
  285. else {
  286. memcpy(d, digits + offset, ndigits);
  287. d += ndigits;
  288. }
  289. return d - dest;
  290. }
  291. }
  292. }
  293. return emit_scientific_digits (digits, ndigits, dest, K, neg, precision, exp);
  294. }
  295. static int emit_digits (char *digits, int ndigits, char *dest, int K, bool neg,
  296. unsigned precision, bool scientific)
  297. {
  298. int exp = absv(K + ndigits - 1);
  299. /* write plain integer */
  300. if (K >= 0 && (exp < (ndigits + 7))) {
  301. return emit_integer (digits, ndigits, dest, K, neg, precision);
  302. }
  303. /* write decimal w/o scientific notation */
  304. if (!scientific || (K < 0 && (K > -7 || exp < 4))) {
  305. return emit_fixed_digits (digits, ndigits, dest, K, neg, precision, exp);
  306. }
  307. return emit_scientific_digits (digits, ndigits, dest, K, neg, precision, exp);
  308. }
  309. static int filter_special (double fp, char *dest, unsigned precision)
  310. {
  311. int nchars = 3;
  312. char *d = dest;
  313. if (fp == 0.0) {
  314. if (get_dbits (fp) & signmask) {
  315. *d++ = '-';
  316. *d++ = '0';
  317. }
  318. else {
  319. *d++ = '0';
  320. }
  321. if (precision) {
  322. *d ++ = '.';
  323. memset (d, '0', precision);
  324. }
  325. return d - dest + precision;
  326. }
  327. uint64_t bits = get_dbits (fp);
  328. bool nan = (bits & expmask) == expmask;
  329. if (!nan) {
  330. return 0;
  331. }
  332. if (bits & fracmask) {
  333. dest[0] = 'n';
  334. dest[1] = 'a';
  335. dest[2] = 'n';
  336. }
  337. else {
  338. if (get_dbits (fp) & signmask) {
  339. dest[0] = '-';
  340. dest[1] = 'i';
  341. dest[2] = 'n';
  342. dest[3] = 'f';
  343. nchars = 4;
  344. }
  345. else {
  346. dest[0] = 'i';
  347. dest[1] = 'n';
  348. dest[2] = 'f';
  349. }
  350. }
  351. return nchars;
  352. }
  353. int
  354. fpconv_dtoa (double d, char dest[FPCONV_BUFLEN],
  355. unsigned precision, bool scientific)
  356. {
  357. char digits[18];
  358. int str_len = 0;
  359. bool neg = false;
  360. if (precision > FPCONV_BUFLEN - 5) {
  361. precision = FPCONV_BUFLEN - 5;
  362. }
  363. int spec = filter_special (d, dest, precision);
  364. if (spec) {
  365. return spec;
  366. }
  367. if (get_dbits (d) & signmask) {
  368. dest[0] = '-';
  369. str_len++;
  370. neg = true;
  371. }
  372. int K = 0;
  373. int ndigits = grisu2 (d, digits, &K);
  374. str_len += emit_digits (digits, ndigits, dest + str_len, K, neg, precision,
  375. scientific);
  376. return str_len;
  377. }