diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2009-05-20 22:05:25 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2009-05-20 22:05:25 (GMT) |
commit | bd16edd305ba8067615e703a2cfeeb33907f40b8 (patch) | |
tree | 6c167711c3e67a713c0bfc27eeef1e530816bdd9 /Python | |
parent | 4db6ff683d1b1d6e6c6bef875a88c9121c68137d (diff) | |
download | cpython-bd16edd305ba8067615e703a2cfeeb33907f40b8.zip cpython-bd16edd305ba8067615e703a2cfeeb33907f40b8.tar.gz cpython-bd16edd305ba8067615e703a2cfeeb33907f40b8.tar.bz2 |
Refactor to remove duplicated nan/inf parsing code in
pystrtod.c, floatobject.c and dtoa.c.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/dtoa.c | 50 | ||||
-rw-r--r-- | Python/pystrtod.c | 99 |
2 files changed, 60 insertions, 89 deletions
diff --git a/Python/dtoa.c b/Python/dtoa.c index 82434bc..1cac941 100644 --- a/Python/dtoa.c +++ b/Python/dtoa.c @@ -264,15 +264,6 @@ extern int strtod_diglim; #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) #define Big1 0xffffffff -#ifndef NAN_WORD0 -#define NAN_WORD0 0x7ff80000 -#endif - -#ifndef NAN_WORD1 -#define NAN_WORD1 0 -#endif - - /* struct BCinfo is used to pass information from _Py_dg_strtod to bigcomp */ typedef struct BCinfo BCinfo; @@ -1026,25 +1017,6 @@ static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, #define Scale_Bit 0x10 #define n_bigtens 5 -/* case insensitive string match, for recognising 'inf[inity]' and - 'nan' strings. */ - -static int -match(const char **sp, char *t) -{ - int c, d; - const char *s = *sp; - - while((d = *t++)) { - if ((c = *++s) >= 'A' && c <= 'Z') - c += 'a' - 'A'; - if (c != d) - return 0; - } - *sp = s + 1; - return 1; -} - #define ULbits 32 #define kshift 5 #define kmask 31 @@ -1459,28 +1431,6 @@ _Py_dg_strtod(const char *s00, char **se) } if (!nd) { if (!nz && !nz0) { - /* Check for Nan and Infinity */ - if (!bc.dplen) - switch(c) { - case 'i': - case 'I': - if (match(&s,"nf")) { - --s; - if (!match(&s,"inity")) - ++s; - word0(&rv) = 0x7ff00000; - word1(&rv) = 0; - goto ret; - } - break; - case 'n': - case 'N': - if (match(&s, "an")) { - word0(&rv) = NAN_WORD0; - word1(&rv) = NAN_WORD1; - goto ret; - } - } ret0: s = s00; sign = 0; diff --git a/Python/pystrtod.c b/Python/pystrtod.c index d36f931..95c0ff6 100644 --- a/Python/pystrtod.c +++ b/Python/pystrtod.c @@ -3,6 +3,57 @@ #include <Python.h> #include <locale.h> +/* _Py_parse_inf_or_nan: Attempt to parse a string of the form "nan", "inf" or + "infinity", with an optional leading sign of "+" or "-". On success, + return the NaN or Infinity as a double and set *endptr to point just beyond + the successfully parsed portion of the string. On failure, return -1.0 and + set *endptr to point to the start of the string. */ + +static int +case_insensitive_match(const char *s, const char *t) +{ + while(*t && Py_TOLOWER(*s) == *t) { + s++; + t++; + } + return *t ? 0 : 1; +} + +double +_Py_parse_inf_or_nan(const char *p, char **endptr) +{ + double retval; + const char *s; + int negate = 0; + + s = p; + if (*s == '-') { + negate = 1; + s++; + } + else if (*s == '+') { + s++; + } + if (case_insensitive_match(s, "inf")) { + s += 3; + if (case_insensitive_match(s, "inity")) + s += 5; + retval = negate ? -Py_HUGE_VAL : Py_HUGE_VAL; + } +#ifdef Py_NAN + else if (case_insensitive_match(s, "nan")) { + s += 3; + retval = negate ? -Py_NAN : Py_NAN; + } +#endif + else { + s = p; + retval = -1.0; + } + *endptr = (char *)s; + return retval; +} + /** * PyOS_ascii_strtod: * @nptr: the string to convert to a numeric value. @@ -49,6 +100,10 @@ _PyOS_ascii_strtod(const char *nptr, char **endptr) result = _Py_dg_strtod(nptr, endptr); _Py_SET_53BIT_PRECISION_END; + if (*endptr == nptr) + /* string might represent and inf or nan */ + result = _Py_parse_inf_or_nan(nptr, endptr); + return result; } @@ -63,19 +118,6 @@ _PyOS_ascii_strtod(const char *nptr, char **endptr) correctly rounded results. */ -/* Case-insensitive string match used for nan and inf detection; t should be - lower-case. Returns 1 for a successful match, 0 otherwise. */ - -static int -case_insensitive_match(const char *s, const char *t) -{ - while(*t && Py_TOLOWER(*s) == *t) { - s++; - t++; - } - return *t ? 0 : 1; -} - double _PyOS_ascii_strtod(const char *nptr, char **endptr) { @@ -101,6 +143,11 @@ _PyOS_ascii_strtod(const char *nptr, char **endptr) decimal_point_pos = NULL; + /* Parse infinities and nans */ + val = _Py_parse_inf_or_nan(nptr, endptr); + if (*endptr != nptr) + return val; + /* Set errno to zero, so that we can distinguish zero results and underflows */ errno = 0; @@ -118,31 +165,6 @@ _PyOS_ascii_strtod(const char *nptr, char **endptr) p++; } - /* Parse infinities and nans */ - if (*p == 'i' || *p == 'I') { - if (case_insensitive_match(p+1, "nf")) { - val = Py_HUGE_VAL; - if (case_insensitive_match(p+3, "inity")) - fail_pos = (char *)p+8; - else - fail_pos = (char *)p+3; - goto got_val; - } - else - goto invalid_string; - } -#ifdef Py_NAN - if (*p == 'n' || *p == 'N') { - if (case_insensitive_match(p+1, "an")) { - val = Py_NAN; - fail_pos = (char *)p+3; - goto got_val; - } - else - goto invalid_string; - } -#endif - /* Some platform strtods accept hex floats; Python shouldn't (at the moment), so we check explicitly for strings starting with '0x'. */ if (*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X')) @@ -231,7 +253,6 @@ _PyOS_ascii_strtod(const char *nptr, char **endptr) if (fail_pos == digits_pos) goto invalid_string; - got_val: if (negate && fail_pos != nptr) val = -val; *endptr = fail_pos; |