summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorJeffrey Yasskin <jyasskin@gmail.com>2008-01-03 02:21:52 (GMT)
committerJeffrey Yasskin <jyasskin@gmail.com>2008-01-03 02:21:52 (GMT)
commit2f3c16be73a8562d357b9b13bbb8088e275840a7 (patch)
tree5334d4bd6c8b6456da10c0be232fb8bf95b1aca7 /Objects
parent27edd829d7673a642cf5b37c3011454ec33cb715 (diff)
downloadcpython-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.c60
-rw-r--r--Objects/floatobject.c108
-rw-r--r--Objects/intobject.c84
-rw-r--r--Objects/longobject.c82
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 */