summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
Diffstat (limited to 'Objects')
-rw-r--r--Objects/floatobject.c159
-rw-r--r--Objects/typeobject.c18
2 files changed, 177 insertions, 0 deletions
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 859abf0..8ef3261 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -1073,6 +1073,163 @@ float_float(PyObject *v)
return v;
}
+static PyObject *
+float_as_integer_ratio(PyObject *v)
+{
+ double self;
+ double float_part;
+ int exponent;
+ int is_negative;
+ const int chunk_size = 28;
+ PyObject *prev;
+ PyObject *py_chunk = NULL;
+ PyObject *py_exponent = NULL;
+ PyObject *numerator = NULL;
+ PyObject *denominator = NULL;
+ PyObject *result_pair = NULL;
+ PyNumberMethods *long_methods;
+
+#define INPLACE_UPDATE(obj, call) \
+ prev = obj; \
+ obj = call; \
+ Py_DECREF(prev); \
+
+ CONVERT_TO_DOUBLE(v, self);
+
+ if (Py_IS_INFINITY(self)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "Cannot pass infinity to float.as_integer_ratio.");
+ return NULL;
+ }
+#ifdef Py_NAN
+ if (Py_IS_NAN(self)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Cannot pass nan to float.as_integer_ratio.");
+ return NULL;
+ }
+#endif
+
+ if (self == 0) {
+ numerator = PyLong_FromLong(0);
+ if (numerator == NULL) goto error;
+ denominator = PyLong_FromLong(1);
+ if (denominator == NULL) goto error;
+ result_pair = PyTuple_Pack(2, numerator, denominator);
+ /* Hand ownership over to the tuple. If the tuple
+ wasn't created successfully, we want to delete the
+ ints anyway. */
+ Py_DECREF(numerator);
+ Py_DECREF(denominator);
+ return result_pair;
+ }
+
+ /* XXX: Could perhaps handle FLT_RADIX!=2 by using ilogb and
+ scalbn, but those may not be in C89. */
+ PyFPE_START_PROTECT("as_integer_ratio", goto error);
+ float_part = frexp(self, &exponent);
+ is_negative = 0;
+ if (float_part < 0) {
+ float_part = -float_part;
+ is_negative = 1;
+ /* 0.5 <= float_part < 1.0 */
+ }
+ PyFPE_END_PROTECT(float_part);
+ /* abs(self) == float_part * 2**exponent exactly */
+
+ /* Suck up chunk_size bits at a time; 28 is enough so that we
+ suck up all bits in 2 iterations for all known binary
+ double-precision formats, and small enough to fit in a
+ long. */
+ numerator = PyLong_FromLong(0);
+ if (numerator == NULL) goto error;
+
+ long_methods = PyLong_Type.tp_as_number;
+
+ py_chunk = PyLong_FromLong(chunk_size);
+ if (py_chunk == NULL) goto error;
+
+ while (float_part != 0) {
+ /* invariant: abs(self) ==
+ (numerator + float_part) * 2**exponent exactly */
+ long digit;
+ PyObject *py_digit;
+
+ PyFPE_START_PROTECT("as_integer_ratio", goto error);
+ /* Pull chunk_size bits out of float_part, into digits. */
+ float_part = ldexp(float_part, chunk_size);
+ digit = (long)float_part;
+ float_part -= digit;
+ /* 0 <= float_part < 1 */
+ exponent -= chunk_size;
+ PyFPE_END_PROTECT(float_part);
+
+ /* Shift digits into numerator. */
+ // numerator <<= chunk_size
+ INPLACE_UPDATE(numerator,
+ long_methods->nb_lshift(numerator, py_chunk));
+ if (numerator == NULL) goto error;
+
+ // numerator |= digit
+ py_digit = PyLong_FromLong(digit);
+ if (py_digit == NULL) goto error;
+ INPLACE_UPDATE(numerator,
+ long_methods->nb_or(numerator, py_digit));
+ Py_DECREF(py_digit);
+ if (numerator == NULL) goto error;
+ }
+
+ /* Add in the sign bit. */
+ if (is_negative) {
+ INPLACE_UPDATE(numerator,
+ long_methods->nb_negative(numerator));
+ if (numerator == NULL) goto error;
+ }
+
+ /* now self = numerator * 2**exponent exactly; fold in 2**exponent */
+ denominator = PyLong_FromLong(1);
+ py_exponent = PyLong_FromLong(labs(exponent));
+ if (py_exponent == NULL) goto error;
+ INPLACE_UPDATE(py_exponent,
+ long_methods->nb_lshift(denominator, py_exponent));
+ if (py_exponent == NULL) goto error;
+ if (exponent > 0) {
+ INPLACE_UPDATE(numerator,
+ long_methods->nb_multiply(numerator,
+ py_exponent));
+ if (numerator == NULL) goto error;
+ }
+ else {
+ Py_DECREF(denominator);
+ denominator = py_exponent;
+ py_exponent = NULL;
+ }
+
+ result_pair = PyTuple_Pack(2, numerator, denominator);
+
+#undef INPLACE_UPDATE
+error:
+ Py_XDECREF(py_exponent);
+ Py_XDECREF(py_chunk);
+ Py_XDECREF(denominator);
+ Py_XDECREF(numerator);
+ return result_pair;
+}
+
+PyDoc_STRVAR(float_as_integer_ratio_doc,
+"float.as_integer_ratio() -> (int, int)\n"
+"\n"
+"Returns a pair of integers, not necessarily in lowest terms, whose\n"
+"ratio is exactly equal to the original float. This method raises an\n"
+"OverflowError on infinities and a ValueError on nans. The resulting\n"
+"denominator will be positive.\n"
+"\n"
+">>> (10.0).as_integer_ratio()\n"
+"(167772160L, 16777216L)\n"
+">>> (0.0).as_integer_ratio()\n"
+"(0, 1)\n"
+">>> (-.25).as_integer_ratio()\n"
+"(-134217728L, 536870912L)");
+
static PyObject *
float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
@@ -1281,6 +1438,8 @@ static PyMethodDef float_methods[] = {
{"__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)."},
+ {"as_integer_ratio", (PyCFunction)float_as_integer_ratio, METH_NOARGS,
+ float_as_integer_ratio_doc},
{"__getnewargs__", (PyCFunction)float_getnewargs, METH_NOARGS},
{"__getformat__", (PyCFunction)float_getformat,
METH_O|METH_CLASS, float_getformat_doc},
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 33b2023..1d6336c 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -33,6 +33,24 @@ struct method_cache_entry {
static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP];
static unsigned int next_version_tag = 0;
+static void type_modified(PyTypeObject *);
+
+unsigned int
+PyType_ClearCache(void)
+{
+ Py_ssize_t i;
+ unsigned int cur_version_tag = next_version_tag - 1;
+
+ for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) {
+ method_cache[i].version = 0;
+ Py_CLEAR(method_cache[i].name);
+ method_cache[i].value = NULL;
+ }
+ next_version_tag = 0;
+ /* mark all version tags as invalid */
+ type_modified(&PyBaseObject_Type);
+ return cur_version_tag;
+}
static void
type_modified(PyTypeObject *type)