diff options
| author | Eric Wieser <wieser.eric@gmail.com> | 2017-11-05 01:16:16 -0800 |
|---|---|---|
| committer | Eric Wieser <wieser.eric@gmail.com> | 2019-04-10 23:40:54 -0700 |
| commit | 79799b32a13a3dfb15eb48bdd8b4c6a433ce50df (patch) | |
| tree | f9e1c25d13b052c29b288e9e29f4cf9667c6abfe /numpy/core/src/multiarray | |
| parent | d7a73f8c700edcf150d59a570e0173b60f84c7a7 (diff) | |
| download | numpy-79799b32a13a3dfb15eb48bdd8b4c6a433ce50df.tar.gz | |
ENH: Implement `np.floating.as_integer_ratio`
This matches the builtin `float.as_integer_ratio` and (in recent python versions) `int.as_integer_ratio`.
Diffstat (limited to 'numpy/core/src/multiarray')
| -rw-r--r-- | numpy/core/src/multiarray/scalartypes.c.src | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index 52de31289..715decbde 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -1993,6 +1993,92 @@ static PyObject * } /**end repeat**/ +/**begin repeat + * #name = half, float, double, longdouble# + * #Name = Half, Float, Double, LongDouble# + * #is_half = 1,0,0,0# + * #c = f, f, , l# + * #convert = PyLong_FromDouble, PyLong_FromDouble, PyLong_FromDouble, + * npy_longdouble_to_PyLong# + * # + */ +/* Heavily copied from the builtin float.as_integer_ratio */ +static PyObject * +@name@_as_integer_ratio(PyObject *self) +{ +#if @is_half@ + npy_double val = npy_half_to_double(PyArrayScalar_VAL(self, @Name@)); + npy_double frac; +#else + npy_@name@ val = PyArrayScalar_VAL(self, @Name@); + npy_@name@ frac; +#endif + int exponent; + int i; + + PyObject *py_exponent = NULL; + PyObject *numerator = NULL; + PyObject *denominator = NULL; + PyObject *result_pair = NULL; + PyNumberMethods *long_methods = PyLong_Type.tp_as_number; + + if (npy_isnan(val)) { + PyErr_SetString(PyExc_ValueError, + "cannot convert NaN to integer ratio"); + return NULL; + } + if (!npy_isfinite(val)) { + PyErr_SetString(PyExc_OverflowError, + "cannot convert Infinity to integer ratio"); + return NULL; + } + + frac = npy_frexp@c@(val, &exponent); /* val == frac * 2**exponent exactly */ + + /* This relies on the floating point type being base 2 to converge */ + for (i = 0; frac != npy_floor@c@(frac); i++) { + frac *= 2.0; + exponent--; + } + + /* self == frac * 2**exponent exactly and frac is integral. */ + numerator = @convert@(frac); + if (numerator == NULL) + goto error; + denominator = PyLong_FromLong(1); + if (denominator == NULL) + goto error; + py_exponent = PyLong_FromLong(exponent < 0 ? -exponent : exponent); + if (py_exponent == NULL) + goto error; + + /* fold in 2**exponent */ + if (exponent > 0) { + PyObject *temp = long_methods->nb_lshift(numerator, py_exponent); + if (temp == NULL) + goto error; + Py_DECREF(numerator); + numerator = temp; + } + else { + PyObject *temp = long_methods->nb_lshift(denominator, py_exponent); + if (temp == NULL) + goto error; + Py_DECREF(denominator); + denominator = temp; + } + + result_pair = PyTuple_Pack(2, numerator, denominator); + +error: + Py_XDECREF(py_exponent); + Py_XDECREF(denominator); + Py_XDECREF(numerator); + return result_pair; +} +/**end repeat**/ + + /* * need to fill in doc-strings for these methods on import -- copy from * array docstrings @@ -2256,6 +2342,17 @@ static PyMethodDef @name@type_methods[] = { }; /**end repeat**/ +/**begin repeat + * #name = half,float,double,longdouble# + */ +static PyMethodDef @name@type_methods[] = { + {"as_integer_ratio", + (PyCFunction)@name@_as_integer_ratio, + METH_NOARGS, NULL}, + {NULL, NULL, 0, NULL} +}; +/**end repeat**/ + /************* As_mapping functions for void array scalar ************/ static Py_ssize_t @@ -4311,6 +4408,15 @@ initialize_numeric_types(void) /**end repeat**/ + /**begin repeat + * #name = half, float, double, longdouble# + * #Name = Half, Float, Double, LongDouble# + */ + + Py@Name@ArrType_Type.tp_methods = @name@type_methods; + + /**end repeat**/ + #if (NPY_SIZEOF_INT != NPY_SIZEOF_LONG) || defined(NPY_PY3K) /* We won't be inheriting from Python Int type. */ PyIntArrType_Type.tp_hash = int_arrtype_hash; |
