strtod.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * Copyright (C) 2000 Manuel Novoa III
  3. *
  4. * Notes:
  5. *
  6. * The primary objective of this implementation was minimal size while
  7. * providing robustness and resonable accuracy.
  8. *
  9. * This implementation depends on IEEE floating point behavior and expects
  10. * to be able to generate +/- infinity as a result.
  11. *
  12. * There are a number of compile-time options below.
  13. *
  14. */
  15. /*****************************************************************************/
  16. /* OPTIONS */
  17. /*****************************************************************************/
  18. /* Set if we want to scale with a O(log2(exp)) multiplications. */
  19. #define _STRTOD_LOG_SCALING 1
  20. /* Set if we want strtod to set errno appropriately. */
  21. /* NOTE: Implies all options below and pulls in _zero_or_inf_check. */
  22. #define _STRTOD_ERRNO 0
  23. /* Set if we want support for the endptr arg. */
  24. /* Implied by _STRTOD_ERRNO. */
  25. #define _STRTOD_ENDPTR 1
  26. /* Set if we want to prevent overflow in accumulating the exponent. */
  27. #define _STRTOD_RESTRICT_EXP 1
  28. /* Set if we want to process mantissa digits more intelligently. */
  29. /* Implied by _STRTOD_ERRNO. */
  30. #define _STRTOD_RESTRICT_DIGITS 1
  31. /* Set if we want to skip scaling 0 for the exponent. */
  32. /* Implied by _STRTOD_ERRNO. */
  33. #define _STRTOD_ZERO_CHECK 0
  34. /*****************************************************************************/
  35. /* Don't change anything that follows. */
  36. /*****************************************************************************/
  37. #if _STRTOD_ERRNO
  38. #undef _STRTOD_ENDPTR
  39. #undef _STRTOD_RESTRICT_EXP
  40. #undef _STRTOD_RESTRICT_DIGITS
  41. #undef _STRTOD_ZERO_CHECK
  42. #define _STRTOD_ENDPTR 1
  43. #define _STRTOD_RESTRICT_EXP 1
  44. #define _STRTOD_RESTRICT_DIGITS 1
  45. #define _STRTOD_ZERO_CHECK 1
  46. #endif
  47. /*****************************************************************************/
  48. #include <stdlib.h>
  49. #include <float.h>
  50. #if _STRTOD_RESTRICT_DIGITS
  51. #define MAX_SIG_DIGITS 20
  52. #define EXP_DENORM_ADJUST MAX_SIG_DIGITS
  53. #define MAX_ALLOWED_EXP (MAX_SIG_DIGITS + EXP_DENORM_ADJUST - DBL_MIN_10_EXP)
  54. #if DBL_DIG > MAX_SIG_DIGITS
  55. #error need to adjust MAX_SIG_DIGITS
  56. #endif
  57. #include <limits.h>
  58. #if MAX_ALLOWED_EXP > INT_MAX
  59. #error size assumption violated for MAX_ALLOWED_EXP
  60. #endif
  61. #else
  62. /* We want some excess if we're not restricting mantissa digits. */
  63. #define MAX_ALLOWED_EXP ((20 - DBL_MIN_10_EXP) * 2)
  64. #endif
  65. #include <ctype.h>
  66. /* Note: For i386 the macro resulted in smaller code than the function call. */
  67. #if 1
  68. #undef isdigit
  69. #define isdigit(x) ( (x >= '0') && (x <= '9') )
  70. #endif
  71. #if _STRTOD_ERRNO
  72. #include <errno.h>
  73. extern int _zero_or_inf_check(double x);
  74. #endif
  75. double strtod(const char *str, char **endptr)
  76. {
  77. double number;
  78. #if _STRTOD_LOG_SCALING
  79. double p10;
  80. #endif
  81. char *pos0;
  82. #if _STRTOD_ENDPTR
  83. char *pos1;
  84. #endif
  85. char *pos = (char *) str;
  86. int exponent_power;
  87. int exponent_temp;
  88. int negative;
  89. #if _STRTOD_RESTRICT_DIGITS || _STRTOD_ENDPTR
  90. int num_digits;
  91. #endif
  92. while (isspace(*pos)) { /* skip leading whitespace */
  93. ++pos;
  94. }
  95. negative = 0;
  96. switch(*pos) { /* handle optional sign */
  97. case '-': negative = 1; /* fall through to increment position */
  98. case '+': ++pos;
  99. }
  100. number = 0.;
  101. #if _STRTOD_RESTRICT_DIGITS || _STRTOD_ENDPTR
  102. num_digits = -1;
  103. #endif
  104. exponent_power = 0;
  105. pos0 = NULL;
  106. LOOP:
  107. while (isdigit(*pos)) { /* process string of digits */
  108. #if _STRTOD_RESTRICT_DIGITS
  109. if (num_digits < 0) { /* first time through? */
  110. ++num_digits; /* we've now seen a digit */
  111. }
  112. if (num_digits || (*pos != '0')) { /* had/have nonzero */
  113. ++num_digits;
  114. if (num_digits <= MAX_SIG_DIGITS) { /* is digit significant */
  115. number = number * 10. + (*pos - '0');
  116. }
  117. }
  118. #else
  119. #if _STRTOD_ENDPTR
  120. ++num_digits;
  121. #endif
  122. number = number * 10. + (*pos - '0');
  123. #endif
  124. ++pos;
  125. }
  126. if ((*pos == '.') && !pos0) { /* is this the first decimal point? */
  127. pos0 = ++pos; /* save position of decimal point */
  128. goto LOOP; /* and process rest of digits */
  129. }
  130. #if _STRTOD_ENDPTR
  131. if (num_digits<0) { /* must have at least one digit */
  132. pos = (char *) str;
  133. goto DONE;
  134. }
  135. #endif
  136. #if _STRTOD_RESTRICT_DIGITS
  137. if (num_digits > MAX_SIG_DIGITS) { /* adjust exponent for skipped digits */
  138. exponent_power += num_digits - MAX_SIG_DIGITS;
  139. }
  140. #endif
  141. if (pos0) {
  142. exponent_power += pos0 - pos; /* adjust exponent for decimal point */
  143. }
  144. if (negative) { /* correct for sign */
  145. number = -number;
  146. negative = 0; /* reset for exponent processing below */
  147. }
  148. /* process an exponent string */
  149. if (*pos == 'e' || *pos == 'E') {
  150. #if _STRTOD_ENDPTR
  151. pos1 = pos;
  152. #endif
  153. switch(*++pos) { /* handle optional sign */
  154. case '-': negative = 1; /* fall through to increment pos */
  155. case '+': ++pos;
  156. }
  157. pos0 = pos;
  158. exponent_temp = 0;
  159. while (isdigit(*pos)) { /* process string of digits */
  160. #if _STRTOD_RESTRICT_EXP
  161. if (exponent_temp < MAX_ALLOWED_EXP) { /* overflow check */
  162. exponent_temp = exponent_temp * 10 + (*pos - '0');
  163. }
  164. #else
  165. exponent_temp = exponent_temp * 10 + (*pos - '0');
  166. #endif
  167. ++pos;
  168. }
  169. #if _STRTOD_ENDPTR
  170. if (pos == pos0) { /* were there no digits? */
  171. pos = pos1; /* back up to e|E */
  172. } /* else */
  173. #endif
  174. if (negative) {
  175. exponent_power -= exponent_temp;
  176. } else {
  177. exponent_power += exponent_temp;
  178. }
  179. }
  180. #if _STRTOD_ZERO_CHECK
  181. if (number == 0.) {
  182. goto DONE;
  183. }
  184. #endif
  185. /* scale the result */
  186. #if _STRTOD_LOG_SCALING
  187. exponent_temp = exponent_power;
  188. p10 = 10.;
  189. if (exponent_temp < 0) {
  190. exponent_temp = -exponent_temp;
  191. }
  192. while (exponent_temp) {
  193. if (exponent_temp & 1) {
  194. if (exponent_power < 0) {
  195. number /= p10;
  196. } else {
  197. number *= p10;
  198. }
  199. }
  200. exponent_temp >>= 1;
  201. p10 *= p10;
  202. }
  203. #else
  204. while (exponent_power) {
  205. if (exponent_power < 0) {
  206. number /= 10.;
  207. exponent_power++;
  208. } else {
  209. number *= 10.;
  210. exponent_power--;
  211. }
  212. }
  213. #endif
  214. #if _STRTOD_ERRNO
  215. if (_zero_or_inf_check(number)) {
  216. __set_errno(ERANGE);
  217. }
  218. #endif
  219. DONE:
  220. #if _STRTOD_ENDPTR
  221. if (endptr) {
  222. *endptr = pos;
  223. }
  224. #endif
  225. return number;
  226. }