strtod.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:8k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* strtod.c function for stdlib  */
  2. /* Copyright 1992-1995 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01e,11feb95,jdi  doc fix.
  7. 01d,16aug93,dvs  fixed value of endptr for strings that start with d, D, e, or E
  8.  (SPR #2229)
  9. 01c,08feb93,jdi  documentation cleanup for 5.1.
  10. 01b,20sep92,smb  documentation additions.
  11. 01a,19jul92,smb  written  and documented
  12. */
  13. /*
  14. DESCRIPTION
  15. INCLUDE FILES: stdlib.h, math.h, assert.h, arrno.h
  16. SEE ALSO: American National Standard X3.159-1989
  17. NOMANUAL
  18. */
  19. #include "vxWorks.h"
  20. #include "stdlib.h"
  21. #include "math.h"
  22. #include "errno.h"
  23. #define Ise(c)          ((c == 'e') || (c == 'E') || (c == 'd') || (c == 'D'))
  24. #define Isdigit(c)      ((c <= '9') && (c >= '0'))
  25. #define Isspace(c)      ((c == ' ') || (c == 't') || (c=='n') || (c=='v') 
  26.  || (c == 'r') || (c == 'f'))
  27. #define Issign(c)       ((c == '-') || (c == '+'))
  28. #define Val(c)          ((c - '0'))
  29. #define MAXE  308
  30. #define MINE  (-308)
  31. static double powtab[] = {1.0,
  32.           10.0,
  33.   100.0,
  34.   1000.0,
  35.   10000.0};
  36. /* flags */
  37. #define SIGN    0x01
  38. #define ESIGN   0x02
  39. #define DECP    0x04
  40. /* locals */
  41. int             __ten_mul (double *acc, int digit);
  42. double          __adjust (double *acc, int dexp, int sign);
  43. double          __exp10 (uint_t x);
  44. /*****************************************************************************
  45. *
  46. * strtod - convert the initial portion of a string to a double (ANSI) 
  47. *
  48. * This routine converts the initial portion of a specified string <s> to a
  49. * double.  First, it decomposes the input string into three parts:  an initial, 
  50. * possibly empty, sequence of white-space characters (as specified by the 
  51. * isspace() function); a subject sequence resembling a floating-point
  52. * constant; and a final string of one or more unrecognized characters, 
  53. * including the terminating null character of the input string.  Then, it
  54. * attempts to convert the subject sequence to a floating-point number, and 
  55. * returns the result.
  56. *
  57. * The expected form of the subject sequence is an optional plus or minus
  58. * decimal-point character, then an optional exponent part but no floating
  59. * suffix.  The subject sequence is defined as the longest initial
  60. * subsequence of the input string, starting with the first non-white-space
  61. * character, that is of the expected form.  The subject sequence contains
  62. * no characters if the input string is empty or consists entirely of 
  63. * white space, or if the first non-white-space character is other than a 
  64. * sign, a digit, or a decimal-point character.
  65. *
  66. * If the subject sequence has the expected form, the sequence of characters
  67. * starting with the first digit or the decimal-point character (whichever
  68. * occurs first) is interpreted as a floating constant, except that the 
  69. * decimal-point character is used in place of a period, and that if neither
  70. * an exponent part nor a decimal-point character appears, a decimal point is
  71. * assumed to follow the last digit in the string.  If the subject sequence
  72. * begins with a minus sign, the value resulting form the conversion is negated.
  73. * A pointer to the final string is stored in the object pointed to by <endptr>,
  74. * provided that <endptr> is not a null pointer.
  75. *
  76. * In other than the "C" locale, additional implementation-defined subject
  77. * sequence forms may be accepted.  VxWorks supports only the "C" locale.
  78. *
  79. * If the subject sequence is empty or does not have the expected form, no
  80. * conversion is performed; the value of <s> is stored in the object pointed
  81. * to by <endptr>, provided that <endptr> is not a null pointer.
  82. *
  83. * INCLUDE FILES: stdlib.h 
  84. *
  85. * RETURNS:
  86. * The converted value, if any.  If no conversion could be performed, it
  87. * returns zero.  If the correct value is outside the range of representable
  88. * values, it returns plus or minus HUGE_VAL (according to the sign of the
  89. * value), and stores the value of the macro ERANGE in `errno'.  If the
  90. * correct value would cause underflow, it returns zero and stores the value
  91. * of the macro ERANGE in `errno'.
  92. *
  93. */
  94. double strtod 
  95.     (
  96.     const char * s, /* string to convert */
  97.     char **      endptr /* ptr to final string */
  98.     )
  99.     {
  100.     /* Note that the point positioning is locale dependant */
  101.     const char *start     = s;
  102.     double      accum     = 0.0;
  103.     int         flags     = 0;
  104.     int         texp      = 0;
  105.     int         e         = 0;
  106.     BOOL        conv_done = FALSE;
  107.     while (Isspace (*s)) s++;
  108.     if (*s == EOS)
  109. {   /* just leading spaces */
  110. if (endptr != NULL) 
  111.     *endptr = CHAR_FROM_CONST (start);
  112. return (0.0);
  113. }
  114.     if (Issign (*s))
  115. {
  116. if (*s == '-') flags = SIGN;
  117. if (*++s == EOS)
  118.     {   /* "+|-" : should be an error ? */
  119.     if (endptr != NULL) 
  120. *endptr = CHAR_FROM_CONST (start);
  121.     return (0.0);
  122.     }
  123. }
  124.     /* added code to fix problem with leading e, E, d, or D */
  125.     if ( !Isdigit (*s) && (*s != '.'))
  126. {
  127. if (endptr != NULL)
  128.     *endptr = CHAR_FROM_CONST (start);
  129. return (0.0);
  130. }
  131.     for ( ; (Isdigit (*s) || (*s == '.')); s++)
  132. {
  133. conv_done = TRUE;
  134. if (*s == '.')
  135.     flags |= DECP;
  136. else
  137.     {
  138.     if ( __ten_mul (&accum, Val(*s)) ) 
  139. texp++;
  140.     if (flags & DECP) 
  141. texp--;
  142.     }
  143. }
  144.     if (Ise (*s))
  145. {
  146. conv_done = TRUE;
  147. if (*++s != EOS)             /* skip e|E|d|D */
  148.     {                         /* ! ([s]xxx[.[yyy]]e)  */
  149.     while (Isspace (*s)) s++; /* Ansi allows spaces after e */
  150.     if (*s != EOS)
  151. {                     /*  ! ([s]xxx[.[yyy]]e[space])  */
  152. if (Issign (*s))
  153.     if (*s++ == '-') flags |= ESIGN;
  154. if (*s != EOS)
  155.                                       /*  ! ([s]xxx[.[yyy]]e[s])  -- error?? */
  156.     {                
  157.     for(; Isdigit (*s); s++)
  158.                                       /* prevent from grossly overflowing */
  159. if (e < MAXE) 
  160.     e = e*10 + Val (*s);
  161.                       /* dont care what comes after this */
  162.     if (flags & ESIGN)
  163. texp -= e;
  164.     else
  165. texp += e;
  166.     }
  167. }
  168.     }
  169. }
  170.     if (endptr != NULL)
  171. *endptr = CHAR_FROM_CONST ((conv_done) ? s : start);
  172.     return (__adjust (&accum, (int) texp, (int) (flags & SIGN)));
  173.     }
  174. /*******************************************************************************
  175. *
  176. * __ten_mul -
  177. *
  178. * multiply 64 bit accumulator by 10 and add digit.
  179. * The KA/CA way to do this should be to use
  180. * a 64-bit integer internally and use "adjust" to
  181. * convert it to float at the end of processing.
  182. *
  183. * AUTHOR:
  184. * Taken from cygnus.
  185. *
  186. * RETURNS:
  187. * NOMANUAL
  188. */
  189. LOCAL int __ten_mul 
  190.     (
  191.     double *acc,
  192.     int     digit
  193.     )
  194.     {
  195.     *acc *= 10;
  196.     *acc += digit;
  197.     return (0);     /* no overflow */
  198.     }
  199. /*******************************************************************************
  200. *
  201. * __adjust -
  202. *
  203. * return (*acc) scaled by 10**dexp.
  204. *
  205. * AUTHOR:
  206. * Taken from cygnus.
  207. *
  208. * RETURNS:
  209. * NOMANUAL
  210. */
  211. LOCAL double __adjust 
  212.     (
  213.     double *acc, /* *acc    the 64 bit accumulator */
  214.     int     dexp,    /* dexp    decimal exponent       */
  215.     int     sign /* sign    sign flag              */
  216.     )
  217.     {
  218.     double  r;
  219.     if (dexp > MAXE)
  220. {
  221. errno = ERANGE;
  222. return (sign) ? -HUGE_VAL : HUGE_VAL;
  223. }
  224.     else if (dexp < MINE)
  225. {
  226. errno = ERANGE;
  227. return 0.0;
  228. }
  229.     r = *acc;
  230.     if (sign)
  231. r = -r;
  232.     if (dexp==0)
  233. return r;
  234.     if (dexp < 0)
  235. return r / __exp10 (abs (dexp));
  236.     else
  237. return r * __exp10 (dexp);
  238.     }
  239. /*******************************************************************************
  240. *
  241. * __exp10 -
  242. *
  243. *  compute 10**x by successive squaring.
  244. *
  245. * AUTHOR:
  246. * Taken from cygnus.
  247. *
  248. * RETURNS:
  249. * NOMANUAL
  250. */
  251. double __exp10 
  252.     (
  253.     uint_t x
  254.     )
  255.     {
  256.     if (x < (sizeof (powtab) / sizeof (double)))
  257. return (powtab [x]);
  258.     else if (x & 1)
  259. return (10.0 * __exp10 (x-1));
  260.     else
  261. return (__exp10 (x/2) * __exp10 (x/2));
  262.     }