diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2009-04-23 19:14:16 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2009-04-23 19:14:16 (GMT) |
commit | ad476dab097c3a0701faf035974c7c1f4b916396 (patch) | |
tree | 4cd97c289085e0224f1e00803391d68b46329a04 /Objects | |
parent | f16e71d889175a76c711dc2c02a33978e5e7e5f7 (diff) | |
download | cpython-ad476dab097c3a0701faf035974c7c1f4b916396.zip cpython-ad476dab097c3a0701faf035974c7c1f4b916396.tar.gz cpython-ad476dab097c3a0701faf035974c7c1f4b916396.tar.bz2 |
Issue #5816: Simplify code for parsing and printing of complex numbers.
nans and infs are no longer given special treatment; as a result,
repr(complex(z)) recovers z for any complex number z.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/complexobject.c | 318 |
1 files changed, 103 insertions, 215 deletions
diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 721db8f..27765ad 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -332,99 +332,64 @@ complex_dealloc(PyObject *op) static PyObject * complex_format(PyComplexObject *v, char format_code) { - PyObject *result = NULL; - Py_ssize_t len; - - /* If these are non-NULL, they'll need to be freed. */ - char *pre = NULL; - char *pim = NULL; - char *buf = NULL; - - /* These do not need to be freed. They're either aliases for pim - and pre, or pointers to constants. */ - char *re = NULL; - char *im = NULL; - char *lead = ""; - char *tail = ""; - - - if (v->cval.real == 0.) { - re = ""; - if (!Py_IS_FINITE(v->cval.imag)) { - if (Py_IS_NAN(v->cval.imag)) - im = "nan*"; - else if (copysign(1, v->cval.imag) == 1) - im = "inf*"; - else - im = "-inf*"; - } - else { - pim = PyOS_double_to_string(v->cval.imag, format_code, - 0, 0, NULL); - if (!pim) { - PyErr_NoMemory(); - goto done; - } - im = pim; - } - } else { - /* Format imaginary part with sign, real part without */ - if (!Py_IS_FINITE(v->cval.real)) { - if (Py_IS_NAN(v->cval.real)) - re = "nan"; - /* else if (copysign(1, v->cval.real) == 1) */ - else if (v->cval.real > 0) - re = "inf"; - else - re = "-inf"; - } - else { - pre = PyOS_double_to_string(v->cval.real, format_code, - 0, 0, NULL); - if (!pre) { - PyErr_NoMemory(); - goto done; - } - re = pre; - } - - if (!Py_IS_FINITE(v->cval.imag)) { - if (Py_IS_NAN(v->cval.imag)) - im = "+nan*"; - /* else if (copysign(1, v->cval.imag) == 1) */ - else if (v->cval.imag > 0) - im = "+inf*"; - else - im = "-inf*"; - } - else { - pim = PyOS_double_to_string(v->cval.imag, format_code, - 0, Py_DTSF_SIGN, NULL); - if (!pim) { - PyErr_NoMemory(); - goto done; - } - im = pim; - } - lead = "("; - tail = ")"; - } - /* Alloc the final buffer. Add one for the "j" in the format string, and - one for the trailing zero. */ - len = strlen(lead) + strlen(re) + strlen(im) + strlen(tail) + 2; - buf = PyMem_Malloc(len); - if (!buf) { - PyErr_NoMemory(); - goto done; - } - PyOS_snprintf(buf, len, "%s%s%sj%s", lead, re, im, tail); - result = PyUnicode_FromString(buf); -done: - PyMem_Free(pim); - PyMem_Free(pre); - PyMem_Free(buf); - - return result; + PyObject *result = NULL; + Py_ssize_t len; + + /* If these are non-NULL, they'll need to be freed. */ + char *pre = NULL; + char *im = NULL; + char *buf = NULL; + + /* These do not need to be freed. re is either an alias + for pre or a pointer to a constant. lead and tail + are pointers to constants. */ + char *re = NULL; + char *lead = ""; + char *tail = ""; + + if (v->cval.real == 0. && copysign(1.0, v->cval.real)==1.0) { + re = ""; + im = PyOS_double_to_string(v->cval.imag, format_code, + 0, 0, NULL); + if (!im) { + PyErr_NoMemory(); + goto done; + } + } else { + /* Format imaginary part with sign, real part without */ + pre = PyOS_double_to_string(v->cval.real, format_code, + 0, 0, NULL); + if (!pre) { + PyErr_NoMemory(); + goto done; + } + re = pre; + + im = PyOS_double_to_string(v->cval.imag, format_code, + 0, Py_DTSF_SIGN, NULL); + if (!im) { + PyErr_NoMemory(); + goto done; + } + lead = "("; + tail = ")"; + } + /* Alloc the final buffer. Add one for the "j" in the format string, + and one for the trailing zero. */ + len = strlen(lead) + strlen(re) + strlen(im) + strlen(tail) + 2; + buf = PyMem_Malloc(len); + if (!buf) { + PyErr_NoMemory(); + goto done; + } + PyOS_snprintf(buf, len, "%s%s%sj%s", lead, re, im, tail); + result = PyUnicode_FromString(buf); + done: + PyMem_Free(im); + PyMem_Free(pre); + PyMem_Free(buf); + + return result; } static PyObject * @@ -757,11 +722,7 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v) const char *s, *start; char *end; double x=0.0, y=0.0, z; - int got_re=0, got_im=0, got_bracket=0, done=0; - int digit_or_dot; - int sw_error=0; - int sign; - char buffer[256]; /* For errors */ + int got_bracket=0; char s_buffer[256]; Py_ssize_t len; @@ -785,16 +746,13 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v) return NULL; } + errno = 0; + /* position on first nonblank */ start = s; while (*s && isspace(Py_CHARMASK(*s))) s++; - if (s[0] == '\0') { - PyErr_SetString(PyExc_ValueError, - "complex() arg is an empty string"); - return NULL; - } - if (s[0] == '(') { + if (*s == '(') { /* Skip over possible bracket from repr(). */ got_bracket = 1; s++; @@ -802,120 +760,50 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v) s++; } - z = -1.0; - sign = 1; - do { - - switch (*s) { - - case '\0': - if (s-start != len) { - PyErr_SetString( - PyExc_ValueError, - "complex() arg contains a null byte"); - return NULL; - } - if(!done) sw_error=1; - break; - - case ')': - if (!got_bracket || !(got_re || got_im)) { - sw_error=1; - break; - } - got_bracket=0; - done=1; - s++; - while (*s && isspace(Py_CHARMASK(*s))) - s++; - if (*s) sw_error=1; - break; - - case '-': - sign = -1; - /* Fallthrough */ - case '+': - if (done) sw_error=1; - s++; - if ( *s=='\0'||*s=='+'||*s=='-'||*s==')'|| - isspace(Py_CHARMASK(*s)) ) sw_error=1; - break; - - case 'J': - case 'j': - if (got_im || done) { - sw_error = 1; - break; - } - if (z<0.0) { - y=sign; - } - else{ - y=sign*z; - } - got_im=1; - s++; - if (*s!='+' && *s!='-' ) - done=1; - break; - - default: - if (isspace(Py_CHARMASK(*s))) { - while (*s && isspace(Py_CHARMASK(*s))) - s++; - if (*s && *s != ')') - sw_error=1; - else - done = 1; - break; - } - digit_or_dot = - (*s=='.' || isdigit(Py_CHARMASK(*s))); - if (done||!digit_or_dot) { - sw_error=1; - break; - } - errno = 0; - PyFPE_START_PROTECT("strtod", return 0) - z = PyOS_ascii_strtod(s, &end) ; - PyFPE_END_PROTECT(z) - if (errno != 0) { - PyOS_snprintf(buffer, sizeof(buffer), - "float() out of range: %.150s", s); - PyErr_SetString( - PyExc_ValueError, - buffer); - return NULL; - } - s=end; - if (*s=='J' || *s=='j') { - - break; - } - if (got_re) { - sw_error=1; - break; - } - - /* accept a real part */ - x=sign*z; - got_re=1; - if (got_im) done=1; - z = -1.0; - sign = 1; - break; - - } /* end of switch */ - - } while (s - start < len && !sw_error); - - if (sw_error || got_bracket) { - PyErr_SetString(PyExc_ValueError, - "complex() arg is a malformed string"); - return NULL; + /* get float---might be real or imaginary part */ + z = PyOS_ascii_strtod(s, &end); + if (end == s) + goto error; + s = end; + if (*s == '+' || *s == '-') { + /* we've got a real part *and* an imaginary part */ + x = z; + y = PyOS_ascii_strtod(s, &end); + if (end == s || !(*end == 'j' || *end == 'J')) + goto error; + s = ++end; + } + else if (*s == 'j' || *s == 'J') { + /* no real part; z was the imaginary part */ + s++; + y = z; + } + else + /* no imaginary part */ + x = z; + + /* trailing whitespace and closing bracket */ + while (*s && isspace(Py_CHARMASK(*s))) + s++; + if (got_bracket && *s == ')') { + got_bracket = 0; + s++; + while (*s && isspace(Py_CHARMASK(*s))) + s++; } + /* we should now be at the end of the string */ + if (s-start != len || got_bracket) + goto error; return complex_subtype_from_doubles(type, x, y); + + error: + /* check for PyOS_ascii_strtod failure due to lack of memory */ + if (errno == ENOMEM) + return PyErr_NoMemory(); + PyErr_SetString(PyExc_ValueError, + "complex() arg is a malformed string"); + return NULL; } static PyObject * |