sfcvt.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. #include <limits.h>
  11. #include <sfio/sfhdr.h>
  12. /* Convert a floating point value to ASCII
  13. **
  14. ** Written by Kiem-Phong Vo
  15. */
  16. static char *Inf = "Inf", *Zero = "0";
  17. #define SF_INTPART (SF_IDIGITS/2)
  18. #define SF_INFINITE ((_Sfi = 3), Inf)
  19. #define SF_ZERO ((_Sfi = 1), Zero)
  20. /**
  21. * @param dv value to convert
  22. * @param n_digit number of digits wanted
  23. * @param decpt return decimal point
  24. * @param sign return sign
  25. * @param format conversion format
  26. */
  27. char *_sfcvt(void * dv, int n_digit, int *decpt, int *sign, int format)
  28. {
  29. char *sp;
  30. long n, v;
  31. char *ep, *buf, *endsp;
  32. static char Buf[SF_MAXDIGITS];
  33. *sign = *decpt = 0;
  34. {
  35. double dval = *(double *)dv;
  36. if (dval == 0.)
  37. return SF_ZERO;
  38. else if ((*sign = dval < 0.)) /* assignment = */
  39. dval = -dval;
  40. n = 0;
  41. if (dval >= (double)LONG_MAX) { /* scale to a small enough number to fit an int */
  42. v = SF_MAXEXP10 - 1;
  43. do {
  44. if (dval < _Sfpos10[v])
  45. v -= 1;
  46. else {
  47. dval *= _Sfneg10[v];
  48. if ((n += 1 << v) >= SF_IDIGITS)
  49. return SF_INFINITE;
  50. }
  51. } while (dval >= (double)LONG_MAX);
  52. }
  53. *decpt = (int) n;
  54. buf = sp = Buf + SF_INTPART;
  55. if ((v = (int) dval) != 0) { /* translate the integer part */
  56. dval -= (double) v;
  57. sfucvt(v, sp, n, ep, long, ulong);
  58. n = buf - sp;
  59. if ((*decpt += (int) n) >= SF_IDIGITS)
  60. return SF_INFINITE;
  61. buf = sp;
  62. sp = Buf + SF_INTPART;
  63. } else
  64. n = 0;
  65. /* remaining number of digits to compute; add 1 for later rounding */
  66. n = (((format & SFFMT_EFORMAT)
  67. || *decpt <= 0) ? 1 : *decpt + 1) - n;
  68. if (n_digit > 0)
  69. n += n_digit;
  70. if ((ep = sp + n) > (endsp = Buf + (SF_MAXDIGITS - 2)))
  71. ep = endsp;
  72. if (sp > ep)
  73. sp = ep;
  74. else {
  75. if ((format & SFFMT_EFORMAT) && *decpt == 0 && dval > 0.) {
  76. double d;
  77. while ((int) (d = dval * 10.) == 0) {
  78. dval = d;
  79. *decpt -= 1;
  80. }
  81. }
  82. while (sp < ep) { /* generate fractional digits */
  83. if (dval <= 0.) { /* fill with 0's */
  84. do {
  85. *sp++ = '0';
  86. } while (sp < ep);
  87. goto done;
  88. } else if ((n = (int) (dval *= 10.)) < 10) {
  89. *sp++ = (char) ('0' + n);
  90. dval -= n;
  91. } else { /* n == 10 */
  92. do {
  93. *sp++ = '9';
  94. } while (sp < ep);
  95. }
  96. }
  97. }
  98. }
  99. if (ep <= buf)
  100. ep = buf + 1;
  101. else if (ep < endsp) { /* round the last digit */
  102. *--sp += 5;
  103. while (*sp > '9') {
  104. *sp = '0';
  105. if (sp > buf)
  106. *--sp += 1;
  107. else { /* next power of 10 */
  108. *sp = '1';
  109. *decpt += 1;
  110. if (!(format & SFFMT_EFORMAT)) { /* add one more 0 for %f precision */
  111. ep[-1] = '0';
  112. ep += 1;
  113. }
  114. }
  115. }
  116. }
  117. done:
  118. *--ep = '\0';
  119. _Sfi = ep - buf;
  120. return buf;
  121. }