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 | |
| 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
| -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 | } |
