]>
Commit | Line | Data |
---|---|---|
4710c53d | 1 | #include <stdio.h>\r |
2 | #include <string.h>\r | |
3 | \r | |
4 | #include "pyconfig.h"\r | |
5 | \r | |
6 | /* comp.sources.misc strtod(), as posted in comp.lang.tcl,\r | |
7 | with bugfix for "123000.0" and acceptance of space after 'e' sign nuked.\r | |
8 | \r | |
9 | ************************************************************\r | |
10 | * YOU MUST EDIT THE MACHINE-DEPENDENT DEFINITIONS BELOW!!! *\r | |
11 | ************************************************************\r | |
12 | */\r | |
13 | \r | |
14 | /* File : stdtod.c (Modified version of str2dbl.c)\r | |
15 | Author : Richard A. O'Keefe @ Quintus Computer Systems, Inc.\r | |
16 | Updated: Tuesday August 2nd, 1988\r | |
17 | Defines: double strtod (char *str, char**ptr)\r | |
18 | */\r | |
19 | \r | |
20 | /* This is an implementation of the strtod() function described in the\r | |
21 | System V manuals, with a different name to avoid linker problems.\r | |
22 | All that str2dbl() does itself is check that the argument is well-formed\r | |
23 | and is in range. It leaves the work of conversion to atof(), which is\r | |
24 | assumed to exist and deliver correct results (if they can be represented).\r | |
25 | \r | |
26 | There are two reasons why this should be provided to the net:\r | |
27 | (a) some UNIX systems do not yet have strtod(), or do not have it\r | |
28 | available in the BSD "universe" (but they do have atof()).\r | |
29 | (b) some of the UNIX systems that *do* have it get it wrong.\r | |
30 | (some crash with large arguments, some assign the wrong *ptr value).\r | |
31 | There is a reason why *we* are providing it: we need a correct version\r | |
32 | of strtod(), and if we give this one away maybe someone will look for\r | |
33 | mistakes in it and fix them for us (:-).\r | |
34 | */\r | |
35 | \r | |
36 | /* The following constants are machine-specific. MD{MIN,MAX}EXPT are\r | |
37 | integers and MD{MIN,MAX}FRAC are strings such that\r | |
38 | 0.${MDMAXFRAC}e${MDMAXEXPT} is the largest representable double,\r | |
39 | 0.${MDMINFRAC}e${MDMINEXPT} is the smallest representable +ve double\r | |
40 | MD{MIN,MAX}FRAC must not have any trailing zeros.\r | |
41 | The values here are for IEEE-754 64-bit floats.\r | |
42 | It is not perfectly clear to me whether an IEEE infinity should be\r | |
43 | returned for overflow, nor what a portable way of writing one is,\r | |
44 | so HUGE is just 0.MAXFRAC*10**MAXEXPT (this seems still to be the\r | |
45 | UNIX convention).\r | |
46 | \r | |
47 | I do know about <values.h>, but the whole point of this file is that\r | |
48 | we can't always trust that stuff to be there or to be correct.\r | |
49 | */\r | |
50 | static int MDMINEXPT = -323;\r | |
51 | static char MDMINFRAC[] = "494065645841246544";\r | |
52 | static double ZERO = 0.0;\r | |
53 | \r | |
54 | static int MDMAXEXPT = 309;\r | |
55 | static char MDMAXFRAC[] = "17976931348623157";\r | |
56 | static double HUGE = 1.7976931348623157e308;\r | |
57 | \r | |
58 | extern double atof(const char *); /* Only called when result known to be ok */\r | |
59 | \r | |
60 | #ifdef HAVE_ERRNO_H\r | |
61 | #include <errno.h>\r | |
62 | #endif\r | |
63 | extern int errno;\r | |
64 | \r | |
65 | double strtod(char *str, char **ptr)\r | |
66 | {\r | |
67 | int sign, scale, dotseen;\r | |
68 | int esign, expt;\r | |
69 | char *save;\r | |
70 | register char *sp, *dp;\r | |
71 | register int c;\r | |
72 | char *buforg, *buflim;\r | |
73 | char buffer[64]; /* 45-digit significant + */\r | |
74 | /* 13-digit exponent */\r | |
75 | sp = str;\r | |
76 | while (*sp == ' ') sp++;\r | |
77 | sign = 1;\r | |
78 | if (*sp == '-') sign -= 2, sp++;\r | |
79 | dotseen = 0, scale = 0;\r | |
80 | dp = buffer;\r | |
81 | *dp++ = '0'; *dp++ = '.';\r | |
82 | buforg = dp, buflim = buffer+48;\r | |
83 | for (save = sp; (c = *sp); sp++)\r | |
84 | if (c == '.') {\r | |
85 | if (dotseen) break;\r | |
86 | dotseen++;\r | |
87 | } else\r | |
88 | if ((unsigned)(c-'0') > (unsigned)('9'-'0')) {\r | |
89 | break;\r | |
90 | } else\r | |
91 | if (c == '0') {\r | |
92 | if (dp != buforg) {\r | |
93 | /* This is not the first digit, so we want to keep it */\r | |
94 | if (dp < buflim) *dp++ = c;\r | |
95 | if (!dotseen) scale++;\r | |
96 | } else {\r | |
97 | /* No non-zero digits seen yet */\r | |
98 | /* If a . has been seen, scale must be adjusted */\r | |
99 | if (dotseen) scale--;\r | |
100 | }\r | |
101 | } else {\r | |
102 | /* This is a nonzero digit, so we want to keep it */\r | |
103 | if (dp < buflim) *dp++ = c;\r | |
104 | /* If it precedes a ., scale must be adjusted */\r | |
105 | if (!dotseen) scale++;\r | |
106 | }\r | |
107 | if (sp == save) {\r | |
108 | if (ptr) *ptr = str;\r | |
109 | errno = EDOM; /* what should this be? */\r | |
110 | return ZERO;\r | |
111 | }\r | |
112 | \r | |
113 | while (dp > buforg && dp[-1] == '0') --dp;\r | |
114 | if (dp == buforg) *dp++ = '0';\r | |
115 | *dp = '\0';\r | |
116 | /* Now the contents of buffer are\r | |
117 | +--+--------+-+--------+\r | |
118 | |0.|fraction|\|leftover|\r | |
119 | +--+--------+-+--------+\r | |
120 | ^dp points here\r | |
121 | where fraction begins with 0 iff it is "0", and has at most\r | |
122 | 45 digits in it, and leftover is at least 16 characters.\r | |
123 | */\r | |
124 | save = sp, expt = 0, esign = 1;\r | |
125 | do {\r | |
126 | c = *sp++;\r | |
127 | if (c != 'e' && c != 'E') break;\r | |
128 | c = *sp++;\r | |
129 | if (c == '-') esign -= 2, c = *sp++; else\r | |
130 | if (c == '+' /* || c == ' ' */ ) c = *sp++;\r | |
131 | if ((unsigned)(c-'0') > (unsigned)('9'-'0')) break;\r | |
132 | while (c == '0') c = *sp++;\r | |
133 | for (; (unsigned)(c-'0') <= (unsigned)('9'-'0'); c = *sp++)\r | |
134 | expt = expt*10 + c-'0';\r | |
135 | if (esign < 0) expt = -expt;\r | |
136 | save = sp-1;\r | |
137 | } while (0);\r | |
138 | if (ptr) *ptr = save;\r | |
139 | expt += scale;\r | |
140 | /* Now the number is sign*0.fraction*10**expt */\r | |
141 | errno = ERANGE;\r | |
142 | if (expt > MDMAXEXPT) {\r | |
143 | return HUGE*sign;\r | |
144 | } else\r | |
145 | if (expt == MDMAXEXPT) {\r | |
146 | if (strcmp(buforg, MDMAXFRAC) > 0) return HUGE*sign;\r | |
147 | } else\r | |
148 | if (expt < MDMINEXPT) {\r | |
149 | return ZERO*sign;\r | |
150 | } else\r | |
151 | if (expt == MDMINEXPT) {\r | |
152 | if (strcmp(buforg, MDMINFRAC) < 0) return ZERO*sign;\r | |
153 | }\r | |
154 | /* We have now established that the number can be */\r | |
155 | /* represented without overflow or underflow */\r | |
156 | (void) sprintf(dp, "E%d", expt);\r | |
157 | errno = 0;\r | |
158 | return atof(buffer)*sign;\r | |
159 | }\r |