diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2013-05-27 14:42:38 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2013-05-27 14:42:38 -0300 |
commit | ee865b9fe768195bb81abec0cbc85136526e6894 (patch) | |
tree | f8f3c349104e85468c6d1b8384ef479aa3ec035e /lobject.c | |
parent | d630daca1a3dad6357226fdc6472692fa7e4b5c0 (diff) | |
download | lua-ee865b9fe768195bb81abec0cbc85136526e6894.tar.gz lua-ee865b9fe768195bb81abec0cbc85136526e6894.tar.bz2 lua-ee865b9fe768195bb81abec0cbc85136526e6894.zip |
new implementation for 'lua_strx2number' to correct small
problems with numbers like 0x10000...000p-100
Diffstat (limited to 'lobject.c')
-rw-r--r-- | lobject.c | 60 |
1 files changed, 36 insertions, 24 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lobject.c,v 2.63 2013/05/14 15:59:04 roberto Exp roberto $ | 2 | ** $Id: lobject.c,v 2.64 2013/05/26 14:43:35 roberto Exp roberto $ |
3 | ** Some generic functions over Lua objects | 3 | ** Some generic functions over Lua objects |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -145,52 +145,64 @@ static int isneg (const char **s) { | |||
145 | #include <math.h> | 145 | #include <math.h> |
146 | 146 | ||
147 | 147 | ||
148 | static lua_Number readhexa (const char **s, lua_Number r, int *count) { | 148 | /* maximum number of significant digits to read (to avoid overflows |
149 | for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */ | 149 | even with single floats) */ |
150 | r = (r * cast_num(16.0)) + cast_num(luaO_hexavalue(cast_uchar(**s))); | 150 | #define MAXSIGDIG 30 |
151 | (*count)++; | ||
152 | } | ||
153 | return r; | ||
154 | } | ||
155 | |||
156 | 151 | ||
157 | /* | 152 | /* |
158 | ** convert an hexadecimal numeric string to a number, following | 153 | ** convert an hexadecimal numeric string to a number, following |
159 | ** C99 specification for 'strtod' | 154 | ** C99 specification for 'strtod' |
160 | */ | 155 | */ |
161 | static lua_Number lua_strx2number (const char *s, char **endptr) { | 156 | static lua_Number lua_strx2number (const char *s, char **endptr) { |
162 | lua_Number r = 0.0; | 157 | lua_Number r = 0.0; /* result (accumulator) */ |
163 | int e = 0, i = 0; | 158 | int sigdig = 0; /* number of significant digits */ |
159 | int nosigdig = 0; /* number of non-significant digits */ | ||
160 | int e = 0; /* exponent correction */ | ||
164 | int neg = 0; /* 1 if number is negative */ | 161 | int neg = 0; /* 1 if number is negative */ |
162 | int dot = 0; /* true after seen a dot */ | ||
165 | *endptr = cast(char *, s); /* nothing is valid yet */ | 163 | *endptr = cast(char *, s); /* nothing is valid yet */ |
166 | while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ | 164 | while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ |
167 | neg = isneg(&s); /* check signal */ | 165 | neg = isneg(&s); /* check signal */ |
168 | if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ | 166 | if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ |
169 | return 0.0; /* invalid format (no '0x') */ | 167 | return 0.0; /* invalid format (no '0x') */ |
170 | s += 2; /* skip '0x' */ | 168 | for (s += 2; ; s++) { /* skip '0x' and read numeral */ |
171 | r = readhexa(&s, r, &i); /* read integer part */ | 169 | if (*s == '.') { |
172 | if (*s == '.') { | 170 | if (dot) break; /* second dot? stop loop */ |
173 | s++; /* skip dot */ | 171 | else dot = 1; |
174 | r = readhexa(&s, r, &e); /* read fractional part */ | 172 | } |
173 | else if (lisxdigit(cast_uchar(*s))) { | ||
174 | if (sigdig == 0 && *s == '0') { /* non-significant zero? */ | ||
175 | nosigdig++; | ||
176 | if (dot) e--; /* zero after dot? correct exponent */ | ||
177 | } | ||
178 | else { | ||
179 | if (++sigdig <= MAXSIGDIG) { /* can read it without overflow? */ | ||
180 | r = (r * cast_num(16.0)) + luaO_hexavalue(cast_uchar(*s)); | ||
181 | if (dot) e--; /* decimal digit */ | ||
182 | } | ||
183 | else /* too many digits; ignore */ | ||
184 | if (!dot) e++; /* still count it for exponent */ | ||
185 | } | ||
186 | } | ||
187 | else break; /* neither a dot nor a digit */ | ||
175 | } | 188 | } |
176 | if (i == 0 && e == 0) | 189 | if (nosigdig + sigdig == 0) /* no digits? */ |
177 | return 0.0; /* invalid format (no digit) */ | 190 | return 0.0; /* invalid format */ |
178 | e *= -4; /* each fractional digit divides value by 2^-4 */ | ||
179 | *endptr = cast(char *, s); /* valid up to here */ | 191 | *endptr = cast(char *, s); /* valid up to here */ |
192 | e *= 4; /* each digit multiplies/divides value by 2^4 */ | ||
180 | if (*s == 'p' || *s == 'P') { /* exponent part? */ | 193 | if (*s == 'p' || *s == 'P') { /* exponent part? */ |
181 | int exp1 = 0; | 194 | int exp1 = 0; /* exponent value */ |
182 | int neg1; | 195 | int neg1; /* exponent signal */ |
183 | s++; /* skip 'p' */ | 196 | s++; /* skip 'p' */ |
184 | neg1 = isneg(&s); /* signal */ | 197 | neg1 = isneg(&s); /* signal */ |
185 | if (!lisdigit(cast_uchar(*s))) | 198 | if (!lisdigit(cast_uchar(*s))) |
186 | goto ret; /* must have at least one digit */ | 199 | return 0.0; /* invalid; must have at least one digit */ |
187 | while (lisdigit(cast_uchar(*s))) /* read exponent */ | 200 | while (lisdigit(cast_uchar(*s))) /* read exponent */ |
188 | exp1 = exp1 * 10 + *(s++) - '0'; | 201 | exp1 = exp1 * 10 + *(s++) - '0'; |
189 | if (neg1) exp1 = -exp1; | 202 | if (neg1) exp1 = -exp1; |
190 | e += exp1; | 203 | e += exp1; |
204 | *endptr = cast(char *, s); /* valid up to here */ | ||
191 | } | 205 | } |
192 | *endptr = cast(char *, s); /* valid up to here */ | ||
193 | ret: | ||
194 | if (neg) r = -r; | 206 | if (neg) r = -r; |
195 | return l_mathop(ldexp)(r, e); | 207 | return l_mathop(ldexp)(r, e); |
196 | } | 208 | } |