summaryrefslogtreecommitdiff
path: root/Modules/_decimal
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_decimal')
-rw-r--r--Modules/_decimal/_decimal.c113
-rw-r--r--Modules/_decimal/docstrings.h9
-rw-r--r--Modules/_decimal/libmpdec/basearith.c1
-rw-r--r--Modules/_decimal/libmpdec/io.c1
-rw-r--r--Modules/_decimal/libmpdec/memory.c7
-rw-r--r--Modules/_decimal/libmpdec/mpalloc.h (renamed from Modules/_decimal/libmpdec/memory.h)4
-rw-r--r--Modules/_decimal/libmpdec/mpdecimal.c2
-rw-r--r--Modules/_decimal/libmpdec/mpdecimal.h12
-rw-r--r--Modules/_decimal/libmpdec/vccompat.h5
-rw-r--r--Modules/_decimal/tests/deccheck.py6
10 files changed, 133 insertions, 27 deletions
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
index e15941aec8..fcc1f151cf 100644
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -36,7 +36,6 @@
#include <stdlib.h>
#include "docstrings.h"
-#include "memory.h"
#if !defined(MPD_VERSION_HEX) || MPD_VERSION_HEX < 0x02040100
@@ -1890,12 +1889,13 @@ is_space(enum PyUnicode_Kind kind, void *data, Py_ssize_t pos)
/* Return the ASCII representation of a numeric Unicode string. The numeric
string may contain ascii characters in the range [1, 127], any Unicode
space and any unicode digit. If strip_ws is true, leading and trailing
- whitespace is stripped.
+ whitespace is stripped. If ignore_underscores is true, underscores are
+ ignored.
Return NULL if malloc fails and an empty string if invalid characters
are found. */
static char *
-numeric_as_ascii(const PyObject *u, int strip_ws)
+numeric_as_ascii(const PyObject *u, int strip_ws, int ignore_underscores)
{
enum PyUnicode_Kind kind;
void *data;
@@ -1930,6 +1930,9 @@ numeric_as_ascii(const PyObject *u, int strip_ws)
for (; j < len; j++) {
ch = PyUnicode_READ(kind, data, j);
+ if (ignore_underscores && ch == '_') {
+ continue;
+ }
if (0 < ch && ch <= 127) {
*cp++ = ch;
continue;
@@ -2012,7 +2015,7 @@ PyDecType_FromUnicode(PyTypeObject *type, const PyObject *u,
PyObject *dec;
char *s;
- s = numeric_as_ascii(u, 0);
+ s = numeric_as_ascii(u, 0, 0);
if (s == NULL) {
return NULL;
}
@@ -2032,7 +2035,7 @@ PyDecType_FromUnicodeExactWS(PyTypeObject *type, const PyObject *u,
PyObject *dec;
char *s;
- s = numeric_as_ascii(u, 1);
+ s = numeric_as_ascii(u, 1, 1);
if (s == NULL) {
return NULL;
}
@@ -3394,6 +3397,105 @@ 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;
+
+ 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, _py_long_power(tmp, exponent, Py_None));
+ Py_DECREF(tmp);
+ if (exponent == NULL) {
+ goto error;
+ }
+
+ if (exp >= 0) {
+ Py_SETREF(numerator, _py_long_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, _py_long_floor_divide(numerator, tmp));
+ Py_SETREF(denominator, _py_long_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)
{
@@ -4702,6 +4804,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 71029a994b..f7fd6e7952 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/basearith.c b/Modules/_decimal/libmpdec/basearith.c
index 35de6b8284..dfe1523927 100644
--- a/Modules/_decimal/libmpdec/basearith.c
+++ b/Modules/_decimal/libmpdec/basearith.c
@@ -32,7 +32,6 @@
#include <string.h>
#include <assert.h>
#include "constants.h"
-#include "memory.h"
#include "typearith.h"
#include "basearith.h"
diff --git a/Modules/_decimal/libmpdec/io.c b/Modules/_decimal/libmpdec/io.c
index a45a429dbf..3aadfb0437 100644
--- a/Modules/_decimal/libmpdec/io.c
+++ b/Modules/_decimal/libmpdec/io.c
@@ -37,7 +37,6 @@
#include <locale.h>
#include "bits.h"
#include "constants.h"
-#include "memory.h"
#include "typearith.h"
#include "io.h"
diff --git a/Modules/_decimal/libmpdec/memory.c b/Modules/_decimal/libmpdec/memory.c
index 0f41fe5064..a854e09911 100644
--- a/Modules/_decimal/libmpdec/memory.c
+++ b/Modules/_decimal/libmpdec/memory.c
@@ -30,7 +30,12 @@
#include <stdio.h>
#include <stdlib.h>
#include "typearith.h"
-#include "memory.h"
+#include "mpalloc.h"
+
+
+#if defined(_MSC_VER)
+ #pragma warning(disable : 4232)
+#endif
/* Guaranteed minimum allocation for a coefficient. May be changed once
diff --git a/Modules/_decimal/libmpdec/memory.h b/Modules/_decimal/libmpdec/mpalloc.h
index 9c98d1a400..efd711953a 100644
--- a/Modules/_decimal/libmpdec/memory.h
+++ b/Modules/_decimal/libmpdec/mpalloc.h
@@ -26,8 +26,8 @@
*/
-#ifndef MEMORY_H
-#define MEMORY_H
+#ifndef MPALLOC_H
+#define MPALLOC_H
#include "mpdecimal.h"
diff --git a/Modules/_decimal/libmpdec/mpdecimal.c b/Modules/_decimal/libmpdec/mpdecimal.c
index 593f9f5e03..328ab92246 100644
--- a/Modules/_decimal/libmpdec/mpdecimal.c
+++ b/Modules/_decimal/libmpdec/mpdecimal.c
@@ -36,7 +36,7 @@
#include "bits.h"
#include "convolute.h"
#include "crt.h"
-#include "memory.h"
+#include "mpalloc.h"
#include "typearith.h"
#include "umodarith.h"
diff --git a/Modules/_decimal/libmpdec/mpdecimal.h b/Modules/_decimal/libmpdec/mpdecimal.h
index 5ca74135bf..daf2b9da38 100644
--- a/Modules/_decimal/libmpdec/mpdecimal.h
+++ b/Modules/_decimal/libmpdec/mpdecimal.h
@@ -48,6 +48,8 @@ extern "C" {
#include <string.h>
#include <limits.h>
#include <assert.h>
+#include <stdint.h>
+#include <inttypes.h>
#ifdef _MSC_VER
#include "vccompat.h"
@@ -59,12 +61,6 @@ extern "C" {
#define MPD_HIDE_SYMBOLS_END
#define EXTINLINE extern inline
#else
- #ifdef HAVE_STDINT_H
- #include <stdint.h>
- #endif
- #ifdef HAVE_INTTYPES_H
- #include <inttypes.h>
- #endif
#ifndef __GNUC_STDC_INLINE__
#define __GNUC_STDC_INLINE__ 1
#endif
@@ -108,9 +104,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/libmpdec/vccompat.h b/Modules/_decimal/libmpdec/vccompat.h
index f58e023c62..dd131d8da2 100644
--- a/Modules/_decimal/libmpdec/vccompat.h
+++ b/Modules/_decimal/libmpdec/vccompat.h
@@ -32,7 +32,6 @@
/* Visual C fixes: no stdint.h, no snprintf ... */
#ifdef _MSC_VER
- #include "vcstdint.h"
#undef inline
#define inline __inline
#undef random
@@ -49,10 +48,6 @@
#undef strtoll
#define strtoll _strtoi64
#define strdup _strdup
- #define PRIi64 "I64i"
- #define PRIu64 "I64u"
- #define PRIi32 "I32i"
- #define PRIu32 "I32u"
#endif
diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py
index ab7d5bdf4e..f907531e1f 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__']