diff options
Diffstat (limited to 'Modules/_decimal')
-rw-r--r-- | Modules/_decimal/_decimal.c | 101 | ||||
-rw-r--r-- | Modules/_decimal/docstrings.h | 9 | ||||
-rw-r--r-- | Modules/_decimal/libmpdec/memory.c | 5 | ||||
-rw-r--r-- | Modules/_decimal/libmpdec/mpdecimal.h | 4 | ||||
-rw-r--r-- | Modules/_decimal/tests/deccheck.py | 6 |
5 files changed, 120 insertions, 5 deletions
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 112b44f..3c2ad85 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -3380,6 +3380,106 @@ dec_as_long(PyObject *dec, PyObject *context, int round) return (PyObject *) pylong; } +/* Convert a Decimal to its exact integer ratio representation. */ +static PyObject * +dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED) +{ + PyObject *numerator = NULL; + PyObject *denominator = NULL; + PyObject *exponent = NULL; + PyObject *result = NULL; + PyObject *tmp; + mpd_ssize_t exp; + PyObject *context; + uint32_t status = 0; + PyNumberMethods *long_methods = PyLong_Type.tp_as_number; + + if (mpd_isspecial(MPD(self))) { + if (mpd_isnan(MPD(self))) { + PyErr_SetString(PyExc_ValueError, + "cannot convert NaN to integer ratio"); + } + else { + PyErr_SetString(PyExc_OverflowError, + "cannot convert Infinity to integer ratio"); + } + return NULL; + } + + CURRENT_CONTEXT(context); + + tmp = dec_alloc(); + if (tmp == NULL) { + return NULL; + } + + if (!mpd_qcopy(MPD(tmp), MPD(self), &status)) { + Py_DECREF(tmp); + PyErr_NoMemory(); + return NULL; + } + + exp = mpd_iszero(MPD(tmp)) ? 0 : MPD(tmp)->exp; + MPD(tmp)->exp = 0; + + /* context and rounding are unused here: the conversion is exact */ + numerator = dec_as_long(tmp, context, MPD_ROUND_FLOOR); + Py_DECREF(tmp); + if (numerator == NULL) { + goto error; + } + + exponent = PyLong_FromSsize_t(exp < 0 ? -exp : exp); + if (exponent == NULL) { + goto error; + } + + tmp = PyLong_FromLong(10); + if (tmp == NULL) { + goto error; + } + + Py_SETREF(exponent, long_methods->nb_power(tmp, exponent, Py_None)); + Py_DECREF(tmp); + if (exponent == NULL) { + goto error; + } + + if (exp >= 0) { + Py_SETREF(numerator, long_methods->nb_multiply(numerator, exponent)); + if (numerator == NULL) { + goto error; + } + denominator = PyLong_FromLong(1); + if (denominator == NULL) { + goto error; + } + } + else { + denominator = exponent; + exponent = NULL; + tmp = _PyLong_GCD(numerator, denominator); + if (tmp == NULL) { + goto error; + } + Py_SETREF(numerator, long_methods->nb_floor_divide(numerator, tmp)); + Py_SETREF(denominator, long_methods->nb_floor_divide(denominator, tmp)); + Py_DECREF(tmp); + if (numerator == NULL || denominator == NULL) { + goto error; + } + } + + result = PyTuple_Pack(2, numerator, denominator); + + +error: + Py_XDECREF(exponent); + Py_XDECREF(denominator); + Py_XDECREF(numerator); + return result; +} + static PyObject * PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) { @@ -4688,6 +4788,7 @@ static PyMethodDef dec_methods [] = /* Miscellaneous */ { "from_float", dec_from_float, METH_O|METH_CLASS, doc_from_float }, { "as_tuple", PyDec_AsTuple, METH_NOARGS, doc_as_tuple }, + { "as_integer_ratio", dec_as_integer_ratio, METH_NOARGS, doc_as_integer_ratio }, /* Special methods */ { "__copy__", dec_copy, METH_NOARGS, NULL }, diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h index 71029a9..f7fd6e7 100644 --- a/Modules/_decimal/docstrings.h +++ b/Modules/_decimal/docstrings.h @@ -70,6 +70,15 @@ PyDoc_STRVAR(doc_as_tuple, Return a tuple representation of the number.\n\ \n"); +PyDoc_STRVAR(doc_as_integer_ratio, +"as_integer_ratio($self, /)\n--\n\n\ +Decimal.as_integer_ratio() -> (int, int)\n\ +\n\ +Return a pair of integers, whose ratio is exactly equal to the original\n\ +Decimal and with a positive denominator. The ratio is in lowest terms.\n\ +Raise OverflowError on infinities and a ValueError on NaNs.\n\ +\n"); + PyDoc_STRVAR(doc_canonical, "canonical($self, /)\n--\n\n\ Return the canonical encoding of the argument. Currently, the encoding\n\ diff --git a/Modules/_decimal/libmpdec/memory.c b/Modules/_decimal/libmpdec/memory.c index 0f41fe5..61eb633 100644 --- a/Modules/_decimal/libmpdec/memory.c +++ b/Modules/_decimal/libmpdec/memory.c @@ -33,6 +33,11 @@ #include "memory.h" +#if defined(_MSC_VER) + #pragma warning(disable : 4232) +#endif + + /* Guaranteed minimum allocation for a coefficient. May be changed once at program start using mpd_setminalloc(). */ mpd_ssize_t MPD_MINALLOC = MPD_MINALLOC_MIN; diff --git a/Modules/_decimal/libmpdec/mpdecimal.h b/Modules/_decimal/libmpdec/mpdecimal.h index 5ca7413..56e4887 100644 --- a/Modules/_decimal/libmpdec/mpdecimal.h +++ b/Modules/_decimal/libmpdec/mpdecimal.h @@ -108,9 +108,9 @@ MPD_PRAGMA(MPD_HIDE_SYMBOLS_START) #define MPD_MAJOR_VERSION 2 #define MPD_MINOR_VERSION 4 -#define MPD_MICRO_VERSION 1 +#define MPD_MICRO_VERSION 2 -#define MPD_VERSION "2.4.1" +#define MPD_VERSION "2.4.2" #define MPD_VERSION_HEX ((MPD_MAJOR_VERSION << 24) | \ (MPD_MINOR_VERSION << 16) | \ diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py index ab7d5bd..f907531 100644 --- a/Modules/_decimal/tests/deccheck.py +++ b/Modules/_decimal/tests/deccheck.py @@ -50,8 +50,8 @@ Functions = { '__abs__', '__bool__', '__ceil__', '__complex__', '__copy__', '__floor__', '__float__', '__hash__', '__int__', '__neg__', '__pos__', '__reduce__', '__repr__', '__str__', '__trunc__', - 'adjusted', 'as_tuple', 'canonical', 'conjugate', 'copy_abs', - 'copy_negate', 'is_canonical', 'is_finite', 'is_infinite', + 'adjusted', 'as_integer_ratio', 'as_tuple', 'canonical', 'conjugate', + 'copy_abs', 'copy_negate', 'is_canonical', 'is_finite', 'is_infinite', 'is_nan', 'is_qnan', 'is_signed', 'is_snan', 'is_zero', 'radix' ), # Unary with optional context: @@ -128,7 +128,7 @@ ContextFunctions = { # Functions that require a restricted exponent range for reasonable runtimes. UnaryRestricted = [ '__ceil__', '__floor__', '__int__', '__trunc__', - 'to_integral', 'to_integral_value' + 'as_integer_ratio', 'to_integral', 'to_integral_value' ] BinaryRestricted = ['__round__'] |