• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * strtod.c
3  *
4  * Convert string to double
5  *
6  * Copyright (C) 2002 Michael Ringgaard. All rights reserved.
7  * Copyright 2006-2008 H. Peter Anvin - All Rights Reserved
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the project nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33  * OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include <errno.h>
37 #include <ctype.h>
38 #include <stdlib.h>
39 #include <math.h>
40 
is_real(double x)41 static inline int is_real(double x)
42 {
43     const double Inf = 1.0 / 0.0;
44     return (x < Inf) && (x >= -Inf);
45 }
46 
strtod(const char * str,char ** endptr)47 double strtod(const char *str, char **endptr)
48 {
49     double number;
50     int exponent;
51     int negative;
52     char *p = (char *)str;
53     double p10;
54     int n;
55     int num_digits;
56     int num_decimals;
57     const double Inf = 1.0 / 0.0;
58 
59     // Skip leading whitespace
60     while (isspace(*p))
61 	p++;
62 
63     // Handle optional sign
64     negative = 0;
65     switch (*p) {
66     case '-':
67 	negative = 1;		// Fall through to increment position
68     case '+':
69 	p++;
70     }
71 
72     number = 0.;
73     exponent = 0;
74     num_digits = 0;
75     num_decimals = 0;
76 
77     // Process string of digits
78     while (isdigit(*p)) {
79 	number = number * 10. + (*p - '0');
80 	p++;
81 	num_digits++;
82     }
83 
84     // Process decimal part
85     if (*p == '.') {
86 	p++;
87 
88 	while (isdigit(*p)) {
89 	    number = number * 10. + (*p - '0');
90 	    p++;
91 	    num_digits++;
92 	    num_decimals++;
93 	}
94 
95 	exponent -= num_decimals;
96     }
97 
98     if (num_digits == 0) {
99 	errno = ERANGE;
100 	return 0.0;
101     }
102     // Correct for sign
103     if (negative)
104 	number = -number;
105 
106     // Process an exponent string
107     if (*p == 'e' || *p == 'E') {
108 	// Handle optional sign
109 	negative = 0;
110 	switch (*++p) {
111 	case '-':
112 	    negative = 1;	// Fall through to increment pos
113 	case '+':
114 	    p++;
115 	}
116 
117 	// Process string of digits
118 	n = 0;
119 	while (isdigit(*p)) {
120 	    n = n * 10 + (*p - '0');
121 	    p++;
122 	}
123 
124 	if (negative)
125 	    exponent -= n;
126 	else
127 	    exponent += n;
128     }
129 
130     if (exponent < __DBL_MIN_EXP__ || exponent > __DBL_MAX_EXP__) {
131 	errno = ERANGE;
132 	return Inf;
133     }
134     // Scale the result
135     p10 = 10.;
136     n = exponent;
137     if (n < 0)
138 	n = -n;
139     while (n) {
140 	if (n & 1) {
141 	    if (exponent < 0)
142 		number /= p10;
143 	    else
144 		number *= p10;
145 	}
146 	n >>= 1;
147 	p10 *= p10;
148     }
149 
150     if (!is_real(number))
151 	errno = ERANGE;
152     if (endptr)
153 	*endptr = p;
154 
155     return number;
156 }
157