diff options
author | Jeffrey Yasskin <jyasskin@gmail.com> | 2008-01-03 02:21:52 (GMT) |
---|---|---|
committer | Jeffrey Yasskin <jyasskin@gmail.com> | 2008-01-03 02:21:52 (GMT) |
commit | 2f3c16be73a8562d357b9b13bbb8088e275840a7 (patch) | |
tree | 5334d4bd6c8b6456da10c0be232fb8bf95b1aca7 /Objects | |
parent | 27edd829d7673a642cf5b37c3011454ec33cb715 (diff) | |
download | cpython-2f3c16be73a8562d357b9b13bbb8088e275840a7.zip cpython-2f3c16be73a8562d357b9b13bbb8088e275840a7.tar.gz cpython-2f3c16be73a8562d357b9b13bbb8088e275840a7.tar.bz2 |
Backport PEP 3141 from the py3k branch to the trunk. This includes r50877 (just
the complex_pow part), r56649, r56652, r56715, r57296, r57302, r57359, r57361,
r57372, r57738, r57739, r58017, r58039, r58040, and r59390, and new
documentation. The only significant difference is that round(x) returns a float
to preserve backward-compatibility. See http://bugs.python.org/issue1689.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/complexobject.c | 60 | ||||
-rw-r--r-- | Objects/floatobject.c | 108 | ||||
-rw-r--r-- | Objects/intobject.c | 84 | ||||
-rw-r--r-- | Objects/longobject.c | 82 |
4 files changed, 271 insertions, 63 deletions
diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 634a753..285c1d4 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -385,6 +385,41 @@ complex_hash(PyComplexObject *v) return combined; } +/* This macro may return! */ +#define TO_COMPLEX(obj, c) \ + if (PyComplex_Check(obj)) \ + c = ((PyComplexObject *)(obj))->cval; \ + else if (to_complex(&(obj), &(c)) < 0) \ + return (obj) + +static int +to_complex(PyObject **pobj, Py_complex *pc) +{ + PyObject *obj = *pobj; + + pc->real = pc->imag = 0.0; + if (PyInt_Check(obj)) { + pc->real = PyInt_AS_LONG(obj); + return 0; + } + if (PyLong_Check(obj)) { + pc->real = PyLong_AsDouble(obj); + if (pc->real == -1.0 && PyErr_Occurred()) { + *pobj = NULL; + return -1; + } + return 0; + } + if (PyFloat_Check(obj)) { + pc->real = PyFloat_AsDouble(obj); + return 0; + } + Py_INCREF(Py_NotImplemented); + *pobj = Py_NotImplemented; + return -1; +} + + static PyObject * complex_add(PyComplexObject *v, PyComplexObject *w) { @@ -502,24 +537,27 @@ complex_divmod(PyComplexObject *v, PyComplexObject *w) } static PyObject * -complex_pow(PyComplexObject *v, PyObject *w, PyComplexObject *z) +complex_pow(PyObject *v, PyObject *w, PyObject *z) { Py_complex p; Py_complex exponent; long int_exponent; + Py_complex a, b; + TO_COMPLEX(v, a); + TO_COMPLEX(w, b); - if ((PyObject *)z!=Py_None) { + if (z!=Py_None) { PyErr_SetString(PyExc_ValueError, "complex modulo"); return NULL; } PyFPE_START_PROTECT("complex_pow", return 0) errno = 0; - exponent = ((PyComplexObject*)w)->cval; + exponent = b; int_exponent = (long)exponent.real; if (exponent.imag == 0. && exponent.real == int_exponent) - p = c_powi(v->cval,int_exponent); + p = c_powi(a,int_exponent); else - p = c_pow(v->cval,exponent); + p = c_pow(a,exponent); PyFPE_END_PROTECT(p) Py_ADJUST_ERANGE2(p.real, p.imag); @@ -541,6 +579,10 @@ complex_int_div(PyComplexObject *v, PyComplexObject *w) { PyObject *t, *r; + if (PyErr_Warn(PyExc_DeprecationWarning, + "complex divmod(), // and % are deprecated") < 0) + return NULL; + t = complex_divmod(v, w); if (t != NULL) { r = PyTuple_GET_ITEM(t, 0); @@ -695,6 +737,11 @@ complex_conjugate(PyObject *self) return PyComplex_FromCComplex(c); } +PyDoc_STRVAR(complex_conjugate_doc, +"complex.conjugate() -> complex\n" +"\n" +"Returns the complex conjugate of its argument. (3-4j).conjugate() == 3+4j."); + static PyObject * complex_getnewargs(PyComplexObject *v) { @@ -702,7 +749,8 @@ complex_getnewargs(PyComplexObject *v) } static PyMethodDef complex_methods[] = { - {"conjugate", (PyCFunction)complex_conjugate, METH_NOARGS}, + {"conjugate", (PyCFunction)complex_conjugate, METH_NOARGS, + complex_conjugate_doc}, {"__getnewargs__", (PyCFunction)complex_getnewargs, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 5d0b920..574b96a 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -986,9 +986,10 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) * bugs so we have to figure it out ourselves. */ if (iw != floor(iw)) { - PyErr_SetString(PyExc_ValueError, "negative number " - "cannot be raised to a fractional power"); - return NULL; + /* Negative numbers raised to fractional powers + * become complex. + */ + return PyComplex_Type.tp_as_number->nb_power(v, w, z); } /* iw is an exact integer, albeit perhaps a very large one. * -1 raised to an exact integer should never be exceptional. @@ -1035,17 +1036,6 @@ float_neg(PyFloatObject *v) } static PyObject * -float_pos(PyFloatObject *v) -{ - if (PyFloat_CheckExact(v)) { - Py_INCREF(v); - return (PyObject *)v; - } - else - return PyFloat_FromDouble(v->ob_fval); -} - -static PyObject * float_abs(PyFloatObject *v) { return PyFloat_FromDouble(fabs(v->ob_fval)); @@ -1083,14 +1073,7 @@ float_coerce(PyObject **pv, PyObject **pw) } static PyObject * -float_long(PyObject *v) -{ - double x = PyFloat_AsDouble(v); - return PyLong_FromDouble(x); -} - -static PyObject * -float_int(PyObject *v) +float_trunc(PyObject *v) { double x = PyFloat_AsDouble(v); double wholepart; /* integral portion of x, rounded toward 0 */ @@ -1116,6 +1099,54 @@ float_int(PyObject *v) } static PyObject * +float_round(PyObject *v, PyObject *args) +{ +#define UNDEF_NDIGITS (-0x7fffffff) /* Unlikely ndigits value */ + double x; + double f; + double flr, cil; + double rounded; + int i; + int ndigits = UNDEF_NDIGITS; + + if (!PyArg_ParseTuple(args, "|i", &ndigits)) + return NULL; + + x = PyFloat_AsDouble(v); + + if (ndigits != UNDEF_NDIGITS) { + f = 1.0; + i = abs(ndigits); + while (--i >= 0) + f = f*10.0; + if (ndigits < 0) + x /= f; + else + x *= f; + } + + flr = floor(x); + cil = ceil(x); + + if (x-flr > 0.5) + rounded = cil; + else if (x-flr == 0.5) + rounded = fmod(flr, 2) == 0 ? flr : cil; + else + rounded = flr; + + if (ndigits != UNDEF_NDIGITS) { + if (ndigits < 0) + rounded *= f; + else + rounded /= f; + } + + return PyFloat_FromDouble(rounded); +#undef UNDEF_NDIGITS +} + +static PyObject * float_float(PyObject *v) { if (PyFloat_CheckExact(v)) @@ -1302,7 +1333,20 @@ PyDoc_STRVAR(float_setformat_doc, "Overrides the automatic determination of C-level floating point type.\n" "This affects how floats are converted to and from binary strings."); +static PyObject * +float_getzero(PyObject *v, void *closure) +{ + return PyFloat_FromDouble(0.0); +} + static PyMethodDef float_methods[] = { + {"conjugate", (PyCFunction)float_float, METH_NOARGS, + "Returns self, the complex conjugate of any float."}, + {"__trunc__", (PyCFunction)float_trunc, METH_NOARGS, + "Returns the Integral closest to x between 0 and x."}, + {"__round__", (PyCFunction)float_round, METH_VARARGS, + "Returns the Integral closest to x, rounding half toward even.\n" + "When an argument is passed, works like built-in round(x, ndigits)."}, {"__getnewargs__", (PyCFunction)float_getnewargs, METH_NOARGS}, {"__getformat__", (PyCFunction)float_getformat, METH_O|METH_CLASS, float_getformat_doc}, @@ -1311,6 +1355,18 @@ static PyMethodDef float_methods[] = { {NULL, NULL} /* sentinel */ }; +static PyGetSetDef float_getset[] = { + {"real", + (getter)float_float, (setter)NULL, + "the real part of a complex number", + NULL}, + {"imag", + (getter)float_getzero, (setter)NULL, + "the imaginary part of a complex number", + NULL}, + {NULL} /* Sentinel */ +}; + PyDoc_STRVAR(float_doc, "float(x) -> floating point number\n\ \n\ @@ -1326,7 +1382,7 @@ static PyNumberMethods float_as_number = { float_divmod, /*nb_divmod*/ float_pow, /*nb_power*/ (unaryfunc)float_neg, /*nb_negative*/ - (unaryfunc)float_pos, /*nb_positive*/ + (unaryfunc)float_float, /*nb_positive*/ (unaryfunc)float_abs, /*nb_absolute*/ (inquiry)float_nonzero, /*nb_nonzero*/ 0, /*nb_invert*/ @@ -1336,8 +1392,8 @@ static PyNumberMethods float_as_number = { 0, /*nb_xor*/ 0, /*nb_or*/ float_coerce, /*nb_coerce*/ - float_int, /*nb_int*/ - float_long, /*nb_long*/ + float_trunc, /*nb_int*/ + float_trunc, /*nb_long*/ float_float, /*nb_float*/ 0, /* nb_oct */ 0, /* nb_hex */ @@ -1389,7 +1445,7 @@ PyTypeObject PyFloat_Type = { 0, /* tp_iternext */ float_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + float_getset, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ diff --git a/Objects/intobject.c b/Objects/intobject.c index 0f11974..a93b9b2 100644 --- a/Objects/intobject.c +++ b/Objects/intobject.c @@ -4,6 +4,8 @@ #include "Python.h" #include <ctype.h> +static PyObject *int_int(PyIntObject *v); + long PyInt_GetMax(void) { @@ -783,21 +785,10 @@ int_neg(PyIntObject *v) } static PyObject * -int_pos(PyIntObject *v) -{ - if (PyInt_CheckExact(v)) { - Py_INCREF(v); - return (PyObject *)v; - } - else - return PyInt_FromLong(v->ob_ival); -} - -static PyObject * int_abs(PyIntObject *v) { if (v->ob_ival >= 0) - return int_pos(v); + return int_int(v); else return int_neg(v); } @@ -827,7 +818,7 @@ int_lshift(PyIntObject *v, PyIntObject *w) return NULL; } if (a == 0 || b == 0) - return int_pos(v); + return int_int(v); if (b >= LONG_BIT) { vv = PyLong_FromLong(PyInt_AS_LONG(v)); if (vv == NULL) @@ -871,7 +862,7 @@ int_rshift(PyIntObject *v, PyIntObject *w) return NULL; } if (a == 0 || b == 0) - return int_pos(v); + return int_int(v); if (b >= LONG_BIT) { if (a < 0) a = -1; @@ -1060,11 +1051,72 @@ int_getnewargs(PyIntObject *v) return Py_BuildValue("(l)", v->ob_ival); } +static PyObject * +int_getN(PyIntObject *v, void *context) { + return PyInt_FromLong((intptr_t)context); +} + +static PyObject * +int_round(PyObject *self, PyObject *args) +{ +#define UNDEF_NDIGITS (-0x7fffffff) /* Unlikely ndigits value */ + int ndigits = UNDEF_NDIGITS; + double x; + PyObject *res; + + if (!PyArg_ParseTuple(args, "|i", &ndigits)) + return NULL; + + if (ndigits == UNDEF_NDIGITS) + return int_float((PyIntObject *)self); + + /* If called with two args, defer to float.__round__(). */ + x = (double) PyInt_AS_LONG(self); + self = PyFloat_FromDouble(x); + if (self == NULL) + return NULL; + res = PyObject_CallMethod(self, "__round__", "i", ndigits); + Py_DECREF(self); + return res; +#undef UNDEF_NDIGITS +} + static PyMethodDef int_methods[] = { + {"conjugate", (PyCFunction)int_int, METH_NOARGS, + "Returns self, the complex conjugate of any int."}, + {"__trunc__", (PyCFunction)int_int, METH_NOARGS, + "Truncating an Integral returns itself."}, + {"__floor__", (PyCFunction)int_int, METH_NOARGS, + "Flooring an Integral returns itself."}, + {"__ceil__", (PyCFunction)int_int, METH_NOARGS, + "Ceiling of an Integral returns itself."}, + {"__round__", (PyCFunction)int_round, METH_VARARGS, + "Rounding an Integral returns itself.\n" + "Rounding with an ndigits arguments defers to float.__round__."}, {"__getnewargs__", (PyCFunction)int_getnewargs, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; +static PyGetSetDef int_getset[] = { + {"real", + (getter)int_int, (setter)NULL, + "the real part of a complex number", + NULL}, + {"imag", + (getter)int_getN, (setter)NULL, + "the imaginary part of a complex number", + (void*)0}, + {"numerator", + (getter)int_int, (setter)NULL, + "the numerator of a rational number in lowest terms", + NULL}, + {"denominator", + (getter)int_getN, (setter)NULL, + "the denominator of a rational number in lowest terms", + (void*)1}, + {NULL} /* Sentinel */ +}; + PyDoc_STRVAR(int_doc, "int(x[, base]) -> integer\n\ \n\ @@ -1085,7 +1137,7 @@ static PyNumberMethods int_as_number = { (binaryfunc)int_divmod, /*nb_divmod*/ (ternaryfunc)int_pow, /*nb_power*/ (unaryfunc)int_neg, /*nb_negative*/ - (unaryfunc)int_pos, /*nb_positive*/ + (unaryfunc)int_int, /*nb_positive*/ (unaryfunc)int_abs, /*nb_absolute*/ (inquiry)int_nonzero, /*nb_nonzero*/ (unaryfunc)int_invert, /*nb_invert*/ @@ -1149,7 +1201,7 @@ PyTypeObject PyInt_Type = { 0, /* tp_iternext */ int_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + int_getset, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ diff --git a/Objects/longobject.c b/Objects/longobject.c index 85e862a..262b40a 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1716,7 +1716,7 @@ PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base) /* forward */ static PyLongObject *x_divrem (PyLongObject *, PyLongObject *, PyLongObject **); -static PyObject *long_pos(PyLongObject *); +static PyObject *long_long(PyObject *v); static int long_divrem(PyLongObject *, PyLongObject *, PyLongObject **, PyLongObject **); @@ -2906,17 +2906,6 @@ long_invert(PyLongObject *v) } static PyObject * -long_pos(PyLongObject *v) -{ - if (PyLong_CheckExact(v)) { - Py_INCREF(v); - return (PyObject *)v; - } - else - return _PyLong_Copy(v); -} - -static PyObject * long_neg(PyLongObject *v) { PyLongObject *z; @@ -2937,7 +2926,7 @@ long_abs(PyLongObject *v) if (v->ob_size < 0) return long_neg(v); else - return long_pos(v); + return long_long((PyObject *)v); } static int @@ -3373,11 +3362,74 @@ long_getnewargs(PyLongObject *v) return Py_BuildValue("(N)", _PyLong_Copy(v)); } +static PyObject * +long_getN(PyLongObject *v, void *context) { + return PyLong_FromLong((intptr_t)context); +} + +static PyObject * +long_round(PyObject *self, PyObject *args) +{ +#define UNDEF_NDIGITS (-0x7fffffff) /* Unlikely ndigits value */ + int ndigits = UNDEF_NDIGITS; + double x; + PyObject *res; + + if (!PyArg_ParseTuple(args, "|i", &ndigits)) + return NULL; + + if (ndigits == UNDEF_NDIGITS) + return long_float(self); + + /* If called with two args, defer to float.__round__(). */ + x = PyLong_AsDouble(self); + if (x == -1.0 && PyErr_Occurred()) + return NULL; + self = PyFloat_FromDouble(x); + if (self == NULL) + return NULL; + res = PyObject_CallMethod(self, "__round__", "i", ndigits); + Py_DECREF(self); + return res; +#undef UNDEF_NDIGITS +} + static PyMethodDef long_methods[] = { + {"conjugate", (PyCFunction)long_long, METH_NOARGS, + "Returns self, the complex conjugate of any long."}, + {"__trunc__", (PyCFunction)long_long, METH_NOARGS, + "Truncating an Integral returns itself."}, + {"__floor__", (PyCFunction)long_long, METH_NOARGS, + "Flooring an Integral returns itself."}, + {"__ceil__", (PyCFunction)long_long, METH_NOARGS, + "Ceiling of an Integral returns itself."}, + {"__round__", (PyCFunction)long_round, METH_VARARGS, + "Rounding an Integral returns itself.\n" + "Rounding with an ndigits arguments defers to float.__round__."}, {"__getnewargs__", (PyCFunction)long_getnewargs, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; +static PyGetSetDef long_getset[] = { + {"real", + (getter)long_long, (setter)NULL, + "the real part of a complex number", + NULL}, + {"imag", + (getter)long_getN, (setter)NULL, + "the imaginary part of a complex number", + (void*)0}, + {"numerator", + (getter)long_long, (setter)NULL, + "the numerator of a rational number in lowest terms", + NULL}, + {"denominator", + (getter)long_getN, (setter)NULL, + "the denominator of a rational number in lowest terms", + (void*)1}, + {NULL} /* Sentinel */ +}; + PyDoc_STRVAR(long_doc, "long(x[, base]) -> integer\n\ \n\ @@ -3396,7 +3448,7 @@ static PyNumberMethods long_as_number = { long_divmod, /*nb_divmod*/ long_pow, /*nb_power*/ (unaryfunc) long_neg, /*nb_negative*/ - (unaryfunc) long_pos, /*tp_positive*/ + (unaryfunc) long_long, /*tp_positive*/ (unaryfunc) long_abs, /*tp_absolute*/ (inquiry) long_nonzero, /*tp_nonzero*/ (unaryfunc) long_invert, /*nb_invert*/ @@ -3461,7 +3513,7 @@ PyTypeObject PyLong_Type = { 0, /* tp_iternext */ long_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + long_getset, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ |