From 439380e27e3036e3d623dc846dbae61a5a075e1d Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 12 Jul 2025 14:10:53 +0300 Subject: [PATCH 01/16] gh-73487: convert the _decimal module to use AC --- .../pycore_global_objects_fini_generated.h | 2 + Include/internal/pycore_global_strings.h | 2 + .../internal/pycore_runtime_init_generated.h | 2 + .../internal/pycore_unicodeobject_generated.h | 8 + Modules/_decimal/_decimal.c | 87 ++++++--- Modules/_decimal/clinic/_decimal.c.h | 177 ++++++++++++++++++ Modules/_decimal/docstrings.h | 35 ---- 7 files changed, 257 insertions(+), 56 deletions(-) create mode 100644 Modules/_decimal/clinic/_decimal.c.h diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index ca4744789f1c23..447bc3241fede5 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1149,6 +1149,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(options)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(order)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(origin)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(other)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(out_fd)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(outgoing)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(outpath)); @@ -1204,6 +1205,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(return)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reverse)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reversed)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(rounding)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(salt)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sched_priority)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(scheduler)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 47bb6fcecc1ba6..5c55ce7c137e21 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -640,6 +640,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(options) STRUCT_FOR_ID(order) STRUCT_FOR_ID(origin) + STRUCT_FOR_ID(other) STRUCT_FOR_ID(out_fd) STRUCT_FOR_ID(outgoing) STRUCT_FOR_ID(outpath) @@ -695,6 +696,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(return) STRUCT_FOR_ID(reverse) STRUCT_FOR_ID(reversed) + STRUCT_FOR_ID(rounding) STRUCT_FOR_ID(salt) STRUCT_FOR_ID(sched_priority) STRUCT_FOR_ID(scheduler) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 70a54f5273e446..028c800ff2d6ef 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1147,6 +1147,7 @@ extern "C" { INIT_ID(options), \ INIT_ID(order), \ INIT_ID(origin), \ + INIT_ID(other), \ INIT_ID(out_fd), \ INIT_ID(outgoing), \ INIT_ID(outpath), \ @@ -1202,6 +1203,7 @@ extern "C" { INIT_ID(return), \ INIT_ID(reverse), \ INIT_ID(reversed), \ + INIT_ID(rounding), \ INIT_ID(salt), \ INIT_ID(sched_priority), \ INIT_ID(scheduler), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 89444f4fb83b94..3f438499121494 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -2348,6 +2348,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(other); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(out_fd); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2568,6 +2572,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(rounding); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(salt); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 602b23cfca8945..b9feff5bc37542 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -58,6 +58,14 @@ #define _PY_DEC_ROUND_GUARD (MPD_ROUND_GUARD-1) #endif +#include "clinic/_decimal.c.h" + +/*[clinic input] +module _decimal +class _decimal.Decimal "PyObject *" "&dec_spec" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e0e1f68f1f413f5f]*/ + struct PyDecContextObject; struct DecCondMap; @@ -4648,20 +4656,33 @@ dec_mpd_to_eng(PyObject *self, PyObject *args, PyObject *kwds) Dec_BinaryFuncVA_NO_CTX(mpd_compare_total) Dec_BinaryFuncVA_NO_CTX(mpd_compare_total_mag) +/*[clinic input] +_decimal.Decimal.copy_sign + + other: object + context: object = None + +Returns self with the sign of other. + +For example: + + >>> Decimal('2.3').copy_sign(Decimal('-1.5')) + Decimal('-2.3') + +This operation is unaffected by context and is quiet: no flags are changed +and no rounding is performed. As an exception, the C version may raise +InvalidOperation if the second operand cannot be converted exactly. +[clinic start generated code]*/ + static PyObject * -dec_mpd_qcopy_sign(PyObject *self, PyObject *args, PyObject *kwds) +_decimal_Decimal_copy_sign_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=72c62177763e012e input=f02ebb5d7489c502]*/ { - static char *kwlist[] = {"other", "context", NULL}; - PyObject *other; PyObject *a, *b; PyObject *result; - PyObject *context = Py_None; uint32_t status = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, - &other, &context)) { - return NULL; - } decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); @@ -4717,22 +4738,46 @@ Dec_BinaryFuncVA(mpd_qrotate) Dec_BinaryFuncVA(mpd_qscaleb) Dec_BinaryFuncVA(mpd_qshift) +/*[clinic input] +_decimal.Decimal.quantize + + exp as w: object + rounding: object = None + context: object = None + +Quantize self so its exponent is the same as that of exp. + +Return a value equal to the first operand after rounding and having the +exponent of the second operand. + + >>> Decimal('1.41421356').quantize(Decimal('1.000')) + Decimal('1.414') + +Unlike other operations, if the length of the coefficient after the quantize +operation would be greater than precision, then an InvalidOperation is signaled. +This guarantees that, unless there is an error condition, the quantized exponent +is always equal to that of the right-hand operand. + +Also unlike other operations, quantize never signals Underflow, even if the +result is subnormal and inexact. + +If the exponent of the second operand is larger than that of the first, then +rounding may be necessary. In this case, the rounding mode is determined by the +rounding argument if given, else by the given context argument; if neither +argument is given, the rounding mode of the current thread's context is used. +[clinic start generated code]*/ + static PyObject * -dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) +_decimal_Decimal_quantize_impl(PyObject *self, PyObject *w, + PyObject *rounding, PyObject *context) +/*[clinic end generated code: output=5e84581f96dc685c input=eed2fdd8d65fce21]*/ { - static char *kwlist[] = {"exp", "rounding", "context", NULL}; - PyObject *rounding = Py_None; - PyObject *context = Py_None; - PyObject *w, *a, *b; + PyObject *a, *b; PyObject *result; uint32_t status = 0; mpd_context_t workctx; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist, - &w, &rounding, &context)) { - return NULL; - } - decimal_state *state = get_module_state_by_def(Py_TYPE(v)); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); @@ -4746,7 +4791,7 @@ dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) } } - CONVERT_BINOP_RAISE(&a, &b, v, w, context); + CONVERT_BINOP_RAISE(&a, &b, self, w, context); result = dec_alloc(state); if (result == NULL) { @@ -5094,7 +5139,7 @@ static PyMethodDef dec_methods [] = { "min", _PyCFunction_CAST(dec_mpd_qmin), METH_VARARGS|METH_KEYWORDS, doc_min }, { "min_mag", _PyCFunction_CAST(dec_mpd_qmin_mag), METH_VARARGS|METH_KEYWORDS, doc_min_mag }, { "next_toward", _PyCFunction_CAST(dec_mpd_qnext_toward), METH_VARARGS|METH_KEYWORDS, doc_next_toward }, - { "quantize", _PyCFunction_CAST(dec_mpd_qquantize), METH_VARARGS|METH_KEYWORDS, doc_quantize }, + _DECIMAL_DECIMAL_QUANTIZE_METHODDEF { "remainder_near", _PyCFunction_CAST(dec_mpd_qrem_near), METH_VARARGS|METH_KEYWORDS, doc_remainder_near }, /* Ternary arithmetic functions, optional context arg */ @@ -5133,7 +5178,7 @@ static PyMethodDef dec_methods [] = /* Binary functions, optional context arg for conversion errors */ { "compare_total", _PyCFunction_CAST(dec_mpd_compare_total), METH_VARARGS|METH_KEYWORDS, doc_compare_total }, { "compare_total_mag", _PyCFunction_CAST(dec_mpd_compare_total_mag), METH_VARARGS|METH_KEYWORDS, doc_compare_total_mag }, - { "copy_sign", _PyCFunction_CAST(dec_mpd_qcopy_sign), METH_VARARGS|METH_KEYWORDS, doc_copy_sign }, + _DECIMAL_DECIMAL_COPY_SIGN_METHODDEF { "same_quantum", _PyCFunction_CAST(dec_mpd_same_quantum), METH_VARARGS|METH_KEYWORDS, doc_same_quantum }, /* Binary functions, optional context arg */ diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h new file mode 100644 index 00000000000000..c9bdb3fba10ab2 --- /dev/null +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -0,0 +1,177 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif +#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + +PyDoc_STRVAR(_decimal_Decimal_copy_sign__doc__, +"copy_sign($self, /, other, context=None)\n" +"--\n" +"\n" +"Returns self with the sign of other.\n" +"\n" +"For example:\n" +"\n" +" >>> Decimal(\'2.3\').copy_sign(Decimal(\'-1.5\'))\n" +" Decimal(\'-2.3\')\n" +"\n" +"This operation is unaffected by context and is quiet: no flags are changed\n" +"and no rounding is performed. As an exception, the C version may raise\n" +"InvalidOperation if the second operand cannot be converted exactly."); + +#define _DECIMAL_DECIMAL_COPY_SIGN_METHODDEF \ + {"copy_sign", _PyCFunction_CAST(_decimal_Decimal_copy_sign), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_copy_sign__doc__}, + +static PyObject * +_decimal_Decimal_copy_sign_impl(PyObject *self, PyObject *other, + PyObject *context); + +static PyObject * +_decimal_Decimal_copy_sign(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "copy_sign", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_copy_sign_impl(self, other, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_quantize__doc__, +"quantize($self, /, exp, rounding=None, context=None)\n" +"--\n" +"\n" +"Quantize self so its exponent is the same as that of exp.\n" +"\n" +"Return a value equal to the first operand after rounding and having the\n" +"exponent of the second operand.\n" +"\n" +" >>> Decimal(\'1.41421356\').quantize(Decimal(\'1.000\'))\n" +" Decimal(\'1.414\')\n" +"\n" +"Unlike other operations, if the length of the coefficient after the quantize\n" +"operation would be greater than precision, then an InvalidOperation is signaled.\n" +"This guarantees that, unless there is an error condition, the quantized exponent\n" +"is always equal to that of the right-hand operand.\n" +"\n" +"Also unlike other operations, quantize never signals Underflow, even if the\n" +"result is subnormal and inexact.\n" +"\n" +"If the exponent of the second operand is larger than that of the first, then\n" +"rounding may be necessary. In this case, the rounding mode is determined by the\n" +"rounding argument if given, else by the given context argument; if neither\n" +"argument is given, the rounding mode of the current thread\'s context is used."); + +#define _DECIMAL_DECIMAL_QUANTIZE_METHODDEF \ + {"quantize", _PyCFunction_CAST(_decimal_Decimal_quantize), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_quantize__doc__}, + +static PyObject * +_decimal_Decimal_quantize_impl(PyObject *self, PyObject *w, + PyObject *rounding, PyObject *context); + +static PyObject * +_decimal_Decimal_quantize(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(exp), &_Py_ID(rounding), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"exp", "rounding", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "quantize", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *w; + PyObject *rounding = Py_None; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + w = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + if (args[1]) { + rounding = args[1]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + context = args[2]; +skip_optional_pos: + return_value = _decimal_Decimal_quantize_impl(self, w, rounding, context); + +exit: + return return_value; +} +/*[clinic end generated code: output=6c9fd93f1bdb644a input=a9049054013a1b77]*/ diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h index 77017a92252cb8..a43bff697d7959 100644 --- a/Modules/_decimal/docstrings.h +++ b/Modules/_decimal/docstrings.h @@ -149,19 +149,6 @@ Return the negation of the argument. This operation is unaffected by context\n\ and is quiet: no flags are changed and no rounding is performed.\n\ \n"); -PyDoc_STRVAR(doc_copy_sign, -"copy_sign($self, /, other, context=None)\n--\n\n\ -Return a copy of the first operand with the sign set to be the same as the\n\ -sign of the second operand. For example:\n\ -\n\ - >>> Decimal('2.3').copy_sign(Decimal('-1.5'))\n\ - Decimal('-2.3')\n\ -\n\ -This operation is unaffected by context and is quiet: no flags are changed\n\ -and no rounding is performed. As an exception, the C version may raise\n\ -InvalidOperation if the second operand cannot be converted exactly.\n\ -\n"); - PyDoc_STRVAR(doc_exp, "exp($self, /, context=None)\n--\n\n\ Return the value of the (natural) exponential function e**x at the given\n\ @@ -383,28 +370,6 @@ is one of the following ten strings:\n\ \n\ \n"); -PyDoc_STRVAR(doc_quantize, -"quantize($self, /, exp, rounding=None, context=None)\n--\n\n\ -Return a value equal to the first operand after rounding and having the\n\ -exponent of the second operand.\n\ -\n\ - >>> Decimal('1.41421356').quantize(Decimal('1.000'))\n\ - Decimal('1.414')\n\ -\n\ -Unlike other operations, if the length of the coefficient after the quantize\n\ -operation would be greater than precision, then an InvalidOperation is signaled.\n\ -This guarantees that, unless there is an error condition, the quantized exponent\n\ -is always equal to that of the right-hand operand.\n\ -\n\ -Also unlike other operations, quantize never signals Underflow, even if the\n\ -result is subnormal and inexact.\n\ -\n\ -If the exponent of the second operand is larger than that of the first, then\n\ -rounding may be necessary. In this case, the rounding mode is determined by the\n\ -rounding argument if given, else by the given context argument; if neither\n\ -argument is given, the rounding mode of the current thread's context is used.\n\ -\n"); - PyDoc_STRVAR(doc_radix, "radix($self, /)\n--\n\n\ Return Decimal(10), the radix (base) in which the Decimal class does\n\ From ada9e7e99494ca99b91b6eb9dff61c82501d0cd3 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 10 Aug 2025 16:21:42 +0300 Subject: [PATCH 02/16] +1 --- Modules/_decimal/_decimal.c | 73 ++++++++---- Modules/_decimal/clinic/_decimal.c.h | 169 ++++++++++++++++++++++++++- Modules/_decimal/docstrings.h | 19 --- 3 files changed, 216 insertions(+), 45 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index b9feff5bc37542..574358f69c100f 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -3862,21 +3862,27 @@ dec_as_integer_ratio(PyObject *self, PyObject *Py_UNUSED(dummy)) return result; } +/*[clinic input] +_decimal.Decimal.to_integral + + rounding: object = None + context: object = None + +Identical to the to_integral_value() method. + +The to_integral() name has been kept for compatibility with older versions. +[clinic start generated code]*/ + static PyObject * -PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) +_decimal_Decimal_to_integral_impl(PyObject *self, PyObject *rounding, + PyObject *context) +/*[clinic end generated code: output=a0c7188686ee7f5c input=a57d62d1d29aed1b]*/ { - static char *kwlist[] = {"rounding", "context", NULL}; PyObject *result; - PyObject *rounding = Py_None; - PyObject *context = Py_None; uint32_t status = 0; mpd_context_t workctx; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, - &rounding, &context)) { - return NULL; - } - decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); @@ -3895,7 +3901,7 @@ PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) return NULL; } - mpd_qround_to_int(MPD(result), MPD(dec), &workctx, &status); + mpd_qround_to_int(MPD(result), MPD(self), &workctx, &status); if (dec_addstatus(context, status)) { Py_DECREF(result); return NULL; @@ -3904,21 +3910,30 @@ PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) return result; } +/*[clinic input] +_decimal.Decimal.to_integral_exact + + rounding: object = None + context: object = None + +Rounds to a nearby integer. + +Round to the nearest integer, signaling Inexact or Rounded as appropriate if +rounding occurs. The rounding mode is determined by the rounding parameter +if given, else by the given context. If neither parameter is given, then the +rounding mode of the current default context is used. +[clinic start generated code]*/ + static PyObject * -PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds) +_decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, + PyObject *context) +/*[clinic end generated code: output=8b004f9b45ac7746 input=e98e6aabbc97a92c]*/ { - static char *kwlist[] = {"rounding", "context", NULL}; PyObject *result; - PyObject *rounding = Py_None; - PyObject *context = Py_None; uint32_t status = 0; mpd_context_t workctx; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, - &rounding, &context)) { - return NULL; - } - decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); @@ -3937,7 +3952,7 @@ PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds) return NULL; } - mpd_qround_to_intx(MPD(result), MPD(dec), &workctx, &status); + mpd_qround_to_intx(MPD(result), MPD(self), &workctx, &status); if (dec_addstatus(context, status)) { Py_DECREF(result); return NULL; @@ -4512,8 +4527,16 @@ Dec_BoolFuncVA(mpd_isnormal) Dec_BoolFuncVA(mpd_issubnormal) /* Unary functions, no context arg */ + +/*[clinic input] +_decimal.Decimal.adjusted + +Return the adjusted exponent of the number. Defined as exp + digits - 1. +[clinic start generated code]*/ + static PyObject * -dec_mpd_adjexp(PyObject *self, PyObject *Py_UNUSED(dummy)) +_decimal_Decimal_adjusted_impl(PyObject *self) +/*[clinic end generated code: output=21ea2c9f23994c52 input=775a14d44f31f787]*/ { mpd_ssize_t retval; @@ -5126,9 +5149,9 @@ static PyMethodDef dec_methods [] = { "next_minus", _PyCFunction_CAST(dec_mpd_qnext_minus), METH_VARARGS|METH_KEYWORDS, doc_next_minus }, { "next_plus", _PyCFunction_CAST(dec_mpd_qnext_plus), METH_VARARGS|METH_KEYWORDS, doc_next_plus }, { "normalize", _PyCFunction_CAST(dec_mpd_qreduce), METH_VARARGS|METH_KEYWORDS, doc_normalize }, - { "to_integral", _PyCFunction_CAST(PyDec_ToIntegralValue), METH_VARARGS|METH_KEYWORDS, doc_to_integral }, - { "to_integral_exact", _PyCFunction_CAST(PyDec_ToIntegralExact), METH_VARARGS|METH_KEYWORDS, doc_to_integral_exact }, - { "to_integral_value", _PyCFunction_CAST(PyDec_ToIntegralValue), METH_VARARGS|METH_KEYWORDS, doc_to_integral_value }, + _DECIMAL_DECIMAL_TO_INTEGRAL_METHODDEF + _DECIMAL_DECIMAL_TO_INTEGRAL_EXACT_METHODDEF + { "to_integral_value", _PyCFunction_CAST(_decimal_Decimal_to_integral), METH_FASTCALL|METH_KEYWORDS, doc_to_integral_value }, { "sqrt", _PyCFunction_CAST(dec_mpd_qsqrt), METH_VARARGS|METH_KEYWORDS, doc_sqrt }, /* Binary arithmetic functions, optional context arg */ @@ -5160,7 +5183,7 @@ static PyMethodDef dec_methods [] = { "is_subnormal", _PyCFunction_CAST(dec_mpd_issubnormal), METH_VARARGS|METH_KEYWORDS, doc_is_subnormal }, /* Unary functions, no context arg */ - { "adjusted", dec_mpd_adjexp, METH_NOARGS, doc_adjusted }, + _DECIMAL_DECIMAL_ADJUSTED_METHODDEF { "canonical", dec_canonical, METH_NOARGS, doc_canonical }, { "conjugate", dec_conjugate, METH_NOARGS, doc_conjugate }, { "radix", dec_mpd_radix, METH_NOARGS, doc_radix }, diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index c9bdb3fba10ab2..bb0a9e05f08ebd 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -8,6 +8,173 @@ preserve #endif #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +PyDoc_STRVAR(_decimal_Decimal_to_integral__doc__, +"to_integral($self, /, rounding=None, context=None)\n" +"--\n" +"\n" +"Identical to the to_integral_value() method.\n" +"\n" +"The to_integral() name has been kept for compatibility with older versions."); + +#define _DECIMAL_DECIMAL_TO_INTEGRAL_METHODDEF \ + {"to_integral", _PyCFunction_CAST(_decimal_Decimal_to_integral), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral__doc__}, + +static PyObject * +_decimal_Decimal_to_integral_impl(PyObject *self, PyObject *rounding, + PyObject *context); + +static PyObject * +_decimal_Decimal_to_integral(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(rounding), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"rounding", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "to_integral", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *rounding = Py_None; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + rounding = args[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_to_integral_impl(self, rounding, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_to_integral_exact__doc__, +"to_integral_exact($self, /, rounding=None, context=None)\n" +"--\n" +"\n" +"Rounds to a nearby integer.\n" +"\n" +"Round to the nearest integer, signaling Inexact or Rounded as appropriate if\n" +"rounding occurs. The rounding mode is determined by the rounding parameter\n" +"if given, else by the given context. If neither parameter is given, then the\n" +"rounding mode of the current default context is used."); + +#define _DECIMAL_DECIMAL_TO_INTEGRAL_EXACT_METHODDEF \ + {"to_integral_exact", _PyCFunction_CAST(_decimal_Decimal_to_integral_exact), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_exact__doc__}, + +static PyObject * +_decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, + PyObject *context); + +static PyObject * +_decimal_Decimal_to_integral_exact(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(rounding), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"rounding", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "to_integral_exact", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *rounding = Py_None; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + rounding = args[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_to_integral_exact_impl(self, rounding, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_adjusted__doc__, +"adjusted($self, /)\n" +"--\n" +"\n" +"Return the adjusted exponent of the number. Defined as exp + digits - 1."); + +#define _DECIMAL_DECIMAL_ADJUSTED_METHODDEF \ + {"adjusted", (PyCFunction)_decimal_Decimal_adjusted, METH_NOARGS, _decimal_Decimal_adjusted__doc__}, + +static PyObject * +_decimal_Decimal_adjusted_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_adjusted(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_adjusted_impl(self); +} + PyDoc_STRVAR(_decimal_Decimal_copy_sign__doc__, "copy_sign($self, /, other, context=None)\n" "--\n" @@ -174,4 +341,4 @@ _decimal_Decimal_quantize(PyObject *self, PyObject *const *args, Py_ssize_t narg exit: return return_value; } -/*[clinic end generated code: output=6c9fd93f1bdb644a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7bdae3731d58dc09 input=a9049054013a1b77]*/ diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h index a43bff697d7959..55ece4ddde6b15 100644 --- a/Modules/_decimal/docstrings.h +++ b/Modules/_decimal/docstrings.h @@ -57,11 +57,6 @@ context does not affect the conversion and is only passed to determine if\n\ the InvalidOperation trap is active.\n\ \n"); -PyDoc_STRVAR(doc_adjusted, -"adjusted($self, /)\n--\n\n\ -Return the adjusted exponent of the number. Defined as exp + digits - 1.\n\ -\n"); - PyDoc_STRVAR(doc_as_tuple, "as_tuple($self, /)\n--\n\n\ Return a tuple representation of the number.\n\ @@ -442,20 +437,6 @@ The value of context.capitals determines whether the exponent sign is lower\n\ or upper case. Otherwise, the context does not affect the operation.\n\ \n"); -PyDoc_STRVAR(doc_to_integral, -"to_integral($self, /, rounding=None, context=None)\n--\n\n\ -Identical to the to_integral_value() method. The to_integral() name has been\n\ -kept for compatibility with older versions.\n\ -\n"); - -PyDoc_STRVAR(doc_to_integral_exact, -"to_integral_exact($self, /, rounding=None, context=None)\n--\n\n\ -Round to the nearest integer, signaling Inexact or Rounded as appropriate if\n\ -rounding occurs. The rounding mode is determined by the rounding parameter\n\ -if given, else by the given context. If neither parameter is given, then the\n\ -rounding mode of the current default context is used.\n\ -\n"); - PyDoc_STRVAR(doc_to_integral_value, "to_integral_value($self, /, rounding=None, context=None)\n--\n\n\ Round to the nearest integer without signaling Inexact or Rounded. The\n\ From 22eb776b9cb7ac7a6b468ff2ae89e633933f1184 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 10 Aug 2025 16:42:47 +0300 Subject: [PATCH 03/16] +1 --- Modules/_decimal/_decimal.c | 251 ++++++++++++---- Modules/_decimal/clinic/_decimal.c.h | 422 ++++++++++++++++++++++++++- Modules/_decimal/docstrings.h | 111 ------- 3 files changed, 619 insertions(+), 165 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 574358f69c100f..67c67576f406d6 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -2878,17 +2878,42 @@ PyDecType_FromSequenceExact(PyTypeObject *type, PyObject *v, PyDecType_FromSequenceExact((st)->PyDec_Type, sequence, context) /* class method */ + +/*[clinic input] +@classmethod +_decimal.Decimal.from_float + + f as pyfloat: object + / + +Class method that converts a float to a decimal number, exactly. + +Since 0.1 is not exactly representable in binary floating point, +Decimal.from_float(0.1) is not the same as Decimal('0.1'). + + >>> Decimal.from_float(0.1) + Decimal('0.1000000000000000055511151231257827021181583404541015625') + >>> Decimal.from_float(float('nan')) + Decimal('NaN') + >>> Decimal.from_float(float('inf')) + Decimal('Infinity') + >>> Decimal.from_float(float('-inf')) + Decimal('-Infinity') + +[clinic start generated code]*/ + static PyObject * -dec_from_float(PyObject *type, PyObject *pyfloat) +_decimal_Decimal_from_float_impl(PyTypeObject *type, PyObject *pyfloat) +/*[clinic end generated code: output=e62775271ac469e6 input=31302a9a4c1d9c99]*/ { PyObject *context; PyObject *result; - decimal_state *state = get_module_state_by_def((PyTypeObject *)type); + decimal_state *state = get_module_state_by_def(type); CURRENT_CONTEXT(state, context); result = PyDecType_FromFloatExact(state->PyDec_Type, pyfloat, context); - if (type != (PyObject *)state->PyDec_Type && result != NULL) { - Py_SETREF(result, PyObject_CallFunctionObjArgs(type, result, NULL)); + if (type != state->PyDec_Type && result != NULL) { + Py_SETREF(result, PyObject_CallFunctionObjArgs((PyObject *)type, result, NULL)); } return result; @@ -2923,17 +2948,36 @@ PyDecType_FromNumberExact(PyTypeObject *type, PyObject *v, PyObject *context) } /* class method */ + +/*[clinic input] +@classmethod +_decimal.Decimal.from_number + + number: object + / + +Class method that converts a real number to a decimal number, exactly. + + >>> Decimal.from_number(314) # int + Decimal('314') + >>> Decimal.from_number(0.1) # float + Decimal('0.1000000000000000055511151231257827021181583404541015625') + >>> Decimal.from_number(Decimal('3.14')) # another decimal instance + Decimal('3.14') +[clinic start generated code]*/ + static PyObject * -dec_from_number(PyObject *type, PyObject *number) +_decimal_Decimal_from_number_impl(PyTypeObject *type, PyObject *number) +/*[clinic end generated code: output=41885304e5beea0a input=c58b678e8916f66b]*/ { PyObject *context; PyObject *result; - decimal_state *state = get_module_state_by_def((PyTypeObject *)type); + decimal_state *state = get_module_state_by_def(type); CURRENT_CONTEXT(state, context); result = PyDecType_FromNumberExact(state->PyDec_Type, number, context); - if (type != (PyObject *)state->PyDec_Type && result != NULL) { - Py_SETREF(result, PyObject_CallFunctionObjArgs(type, result, NULL)); + if (type != state->PyDec_Type && result != NULL) { + Py_SETREF(result, PyObject_CallFunctionObjArgs((PyObject *)type, result, NULL)); } return result; @@ -3759,8 +3803,19 @@ dec_as_long(PyObject *dec, PyObject *context, int round) } /* Convert a Decimal to its exact integer ratio representation. */ + +/*[clinic input] +_decimal.Decimal.as_integer_ratio + +Return a pair of integers, whose ratio is exactly equal to the original. + +The ratio is in lowest terms and with a positive denominator. Raise +OverflowError on infinities and a ValueError on NaNs. +[clinic start generated code]*/ + static PyObject * -dec_as_integer_ratio(PyObject *self, PyObject *Py_UNUSED(dummy)) +_decimal_Decimal_as_integer_ratio_impl(PyObject *self) +/*[clinic end generated code: output=c5d88e900080c264 input=3a4819b9484919d5]*/ { PyObject *numerator = NULL; PyObject *denominator = NULL; @@ -4042,8 +4097,16 @@ PyDec_Round(PyObject *dec, PyObject *args) } /* Return the DecimalTuple representation of a PyDecObject. */ + +/*[clinic input] +_decimal.Decimal.as_tuple + +Return a tuple representation of the number. +[clinic start generated code]*/ + static PyObject * -PyDec_AsTuple(PyObject *dec, PyObject *Py_UNUSED(dummy)) +_decimal_Decimal_as_tuple_impl(PyObject *self) +/*[clinic end generated code: output=c6e8e2420c515eca input=e26f2151d78ff59d]*/ { PyObject *result = NULL; PyObject *sign = NULL; @@ -4055,13 +4118,13 @@ PyDec_AsTuple(PyObject *dec, PyObject *Py_UNUSED(dummy)) Py_ssize_t intlen, i; - x = mpd_qncopy(MPD(dec)); + x = mpd_qncopy(MPD(self)); if (x == NULL) { PyErr_NoMemory(); goto out; } - sign = PyLong_FromUnsignedLong(mpd_sign(MPD(dec))); + sign = PyLong_FromUnsignedLong(mpd_sign(MPD(self))); if (sign == NULL) { goto out; } @@ -4082,7 +4145,7 @@ PyDec_AsTuple(PyObject *dec, PyObject *Py_UNUSED(dummy)) expt = PyUnicode_FromString(mpd_isqnan(x)?"n":"N"); } else { - expt = PyLong_FromSsize_t(MPD(dec)->exp); + expt = PyLong_FromSsize_t(MPD(self)->exp); } if (expt == NULL) { goto out; @@ -4123,7 +4186,7 @@ PyDec_AsTuple(PyObject *dec, PyObject *Py_UNUSED(dummy)) } } - decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); result = PyObject_CallFunctionObjArgs((PyObject *)state->DecimalTuple, sign, coeff, expt, NULL); @@ -4550,14 +4613,31 @@ _decimal_Decimal_adjusted_impl(PyObject *self) return PyLong_FromSsize_t(retval); } +/*[clinic input] +_decimal.Decimal.canonical + +Return the canonical encoding of the argument. + +Currently, the encoding of a Decimal instance is always canonical, so this +operation returns its argument unchanged. +[clinic start generated code]*/ + static PyObject * -dec_canonical(PyObject *self, PyObject *Py_UNUSED(dummy)) +_decimal_Decimal_canonical_impl(PyObject *self) +/*[clinic end generated code: output=3cbeb47d91e6da2d input=9089f031f530238e]*/ { return Py_NewRef(self); } +/*[clinic input] +_decimal.Decimal.conjugate + +Return self. +[clinic start generated code]*/ + static PyObject * -dec_conjugate(PyObject *self, PyObject *Py_UNUSED(dummy)) +_decimal_Decimal_conjugate_impl(PyObject *self) +/*[clinic end generated code: output=9a37bf633f25a291 input=c7179975ef74fd84]*/ { return Py_NewRef(self); } @@ -4576,15 +4656,35 @@ _dec_mpd_radix(decimal_state *state) return result; } +/*[clinic input] +_decimal.Decimal.radix + +Return Decimal(10). + +I.e. return the radix (base) in which the Decimal class does +all its arithmetic. Included for compatibility with the specification. +[clinic start generated code]*/ + static PyObject * -dec_mpd_radix(PyObject *self, PyObject *Py_UNUSED(dummy)) +_decimal_Decimal_radix_impl(PyObject *self) +/*[clinic end generated code: output=6b1db4c3fcdb5ee1 input=c25ca314723040ed]*/ { decimal_state *state = get_module_state_by_def(Py_TYPE(self)); return _dec_mpd_radix(state); } +/*[clinic input] +_decimal.Decimal.copy_abs + +Return the absolute value of the argument. + +This operation is unaffected by context and is quiet: no flags are changed and +no rounding is performed. +[clinic start generated code]*/ + static PyObject * -dec_mpd_qcopy_abs(PyObject *self, PyObject *Py_UNUSED(dummy)) +_decimal_Decimal_copy_abs_impl(PyObject *self) +/*[clinic end generated code: output=fff53742cca94d70 input=fa96ebbfd9191e72]*/ { PyObject *result; uint32_t status = 0; @@ -4604,8 +4704,18 @@ dec_mpd_qcopy_abs(PyObject *self, PyObject *Py_UNUSED(dummy)) return result; } +/*[clinic input] +_decimal.Decimal.copy_negate + +Return the negation of the argument. + +This operation is unaffected by context and is quiet: no flags are changed and +no rounding is performed. +[clinic start generated code]*/ + static PyObject * -dec_mpd_qcopy_negate(PyObject *self, PyObject *Py_UNUSED(dummy)) +_decimal_Decimal_copy_negate_impl(PyObject *self) +/*[clinic end generated code: output=8551bc26dbc5d01d input=2ca2ce000154fca0]*/ { PyObject *result; uint32_t status = 0; @@ -4629,17 +4739,33 @@ dec_mpd_qcopy_negate(PyObject *self, PyObject *Py_UNUSED(dummy)) Dec_UnaryFuncVA(mpd_qinvert) Dec_UnaryFuncVA(mpd_qlogb) +/*[clinic input] +_decimal.Decimal.number_class + + context: object = None + +Return a string describing the class of the operand. + +The returned value is one of the following ten strings: + + * '-Infinity', indicating that the operand is negative infinity. + * '-Normal', indicating that the operand is a negative normal number. + * '-Subnormal', indicating that the operand is negative and subnormal. + * '-Zero', indicating that the operand is a negative zero. + * '+Zero', indicating that the operand is a positive zero. + * '+Subnormal', indicating that the operand is positive and subnormal. + * '+Normal', indicating that the operand is a positive normal number. + * '+Infinity', indicating that the operand is positive infinity. + * 'NaN', indicating that the operand is a quiet NaN (Not a Number). + * 'sNaN', indicating that the operand is a signaling NaN. +[clinic start generated code]*/ + static PyObject * -dec_mpd_class(PyObject *self, PyObject *args, PyObject *kwds) +_decimal_Decimal_number_class_impl(PyObject *self, PyObject *context) +/*[clinic end generated code: output=3044cd45966b4949 input=80cc37edb4fd663f]*/ { - static char *kwlist[] = {"context", NULL}; - PyObject *context = Py_None; const char *cp; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, - &context)) { - return NULL; - } decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); @@ -4647,19 +4773,30 @@ dec_mpd_class(PyObject *self, PyObject *args, PyObject *kwds) return PyUnicode_FromString(cp); } +/*[clinic input] +_decimal.Decimal.to_eng_string + + context: object = None + +Convert to an engineering-type string. + +Engineering notation has an exponent which is a multiple of 3, so there are up +to 3 digits left of the decimal place. For example, Decimal('123E+1') is +converted to Decimal('1.23E+3'). + +The value of context.capitals determines whether the exponent sign is lower or +upper case. Otherwise, the context does not affect the operation. + +[clinic start generated code]*/ + static PyObject * -dec_mpd_to_eng(PyObject *self, PyObject *args, PyObject *kwds) +_decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context) +/*[clinic end generated code: output=d386194c25ffffa7 input=fac5029cbf436bd5]*/ { - static char *kwlist[] = {"context", NULL}; PyObject *result; - PyObject *context = Py_None; mpd_ssize_t size; char *s; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, - &context)) { - return NULL; - } decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); @@ -4728,19 +4865,27 @@ _decimal_Decimal_copy_sign_impl(PyObject *self, PyObject *other, return result; } +/*[clinic input] +_decimal.Decimal.same_quantum + + other: object + context: object = None + +Test whether self and other have the same exponent or whether both are NaN. + +This operation is unaffected by context and is quiet: no flags are changed and +no rounding is performed. As an exception, the C version may raise +InvalidOperation if the second operand cannot be converted exactly. +[clinic start generated code]*/ + static PyObject * -dec_mpd_same_quantum(PyObject *self, PyObject *args, PyObject *kwds) +_decimal_Decimal_same_quantum_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=c0a3a046c662a7e2 input=0930e11241231ac2]*/ { - static char *kwlist[] = {"other", "context", NULL}; - PyObject *other; PyObject *a, *b; PyObject *result; - PyObject *context = Py_None; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, - &other, &context)) { - return NULL; - } decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); @@ -5184,25 +5329,25 @@ static PyMethodDef dec_methods [] = /* Unary functions, no context arg */ _DECIMAL_DECIMAL_ADJUSTED_METHODDEF - { "canonical", dec_canonical, METH_NOARGS, doc_canonical }, - { "conjugate", dec_conjugate, METH_NOARGS, doc_conjugate }, - { "radix", dec_mpd_radix, METH_NOARGS, doc_radix }, + _DECIMAL_DECIMAL_CANONICAL_METHODDEF + _DECIMAL_DECIMAL_CONJUGATE_METHODDEF + _DECIMAL_DECIMAL_RADIX_METHODDEF /* Unary functions, optional context arg for conversion errors */ - { "copy_abs", dec_mpd_qcopy_abs, METH_NOARGS, doc_copy_abs }, - { "copy_negate", dec_mpd_qcopy_negate, METH_NOARGS, doc_copy_negate }, + _DECIMAL_DECIMAL_COPY_ABS_METHODDEF + _DECIMAL_DECIMAL_COPY_NEGATE_METHODDEF /* Unary functions, optional context arg */ { "logb", _PyCFunction_CAST(dec_mpd_qlogb), METH_VARARGS|METH_KEYWORDS, doc_logb }, { "logical_invert", _PyCFunction_CAST(dec_mpd_qinvert), METH_VARARGS|METH_KEYWORDS, doc_logical_invert }, - { "number_class", _PyCFunction_CAST(dec_mpd_class), METH_VARARGS|METH_KEYWORDS, doc_number_class }, - { "to_eng_string", _PyCFunction_CAST(dec_mpd_to_eng), METH_VARARGS|METH_KEYWORDS, doc_to_eng_string }, + _DECIMAL_DECIMAL_NUMBER_CLASS_METHODDEF + _DECIMAL_DECIMAL_TO_ENG_STRING_METHODDEF /* Binary functions, optional context arg for conversion errors */ { "compare_total", _PyCFunction_CAST(dec_mpd_compare_total), METH_VARARGS|METH_KEYWORDS, doc_compare_total }, { "compare_total_mag", _PyCFunction_CAST(dec_mpd_compare_total_mag), METH_VARARGS|METH_KEYWORDS, doc_compare_total_mag }, _DECIMAL_DECIMAL_COPY_SIGN_METHODDEF - { "same_quantum", _PyCFunction_CAST(dec_mpd_same_quantum), METH_VARARGS|METH_KEYWORDS, doc_same_quantum }, + _DECIMAL_DECIMAL_SAME_QUANTUM_METHODDEF /* Binary functions, optional context arg */ { "logical_and", _PyCFunction_CAST(dec_mpd_qand), METH_VARARGS|METH_KEYWORDS, doc_logical_and }, @@ -5213,10 +5358,10 @@ static PyMethodDef dec_methods [] = { "shift", _PyCFunction_CAST(dec_mpd_qshift), METH_VARARGS|METH_KEYWORDS, doc_shift }, /* Miscellaneous */ - { "from_float", dec_from_float, METH_O|METH_CLASS, doc_from_float }, - { "from_number", dec_from_number, METH_O|METH_CLASS, doc_from_number }, - { "as_tuple", PyDec_AsTuple, METH_NOARGS, doc_as_tuple }, - { "as_integer_ratio", dec_as_integer_ratio, METH_NOARGS, doc_as_integer_ratio }, + _DECIMAL_DECIMAL_FROM_FLOAT_METHODDEF + _DECIMAL_DECIMAL_FROM_NUMBER_METHODDEF + _DECIMAL_DECIMAL_AS_TUPLE_METHODDEF + _DECIMAL_DECIMAL_AS_INTEGER_RATIO_METHODDEF /* Special methods */ { "__copy__", dec_copy, METH_NOARGS, NULL }, diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index bb0a9e05f08ebd..5d04fe0989d6d8 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -8,6 +8,90 @@ preserve #endif #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +PyDoc_STRVAR(_decimal_Decimal_from_float__doc__, +"from_float($type, f, /)\n" +"--\n" +"\n" +"Class method that converts a float to a decimal number, exactly.\n" +"\n" +"Since 0.1 is not exactly representable in binary floating point,\n" +"Decimal.from_float(0.1) is not the same as Decimal(\'0.1\').\n" +"\n" +" >>> Decimal.from_float(0.1)\n" +" Decimal(\'0.1000000000000000055511151231257827021181583404541015625\')\n" +" >>> Decimal.from_float(float(\'nan\'))\n" +" Decimal(\'NaN\')\n" +" >>> Decimal.from_float(float(\'inf\'))\n" +" Decimal(\'Infinity\')\n" +" >>> Decimal.from_float(float(\'-inf\'))\n" +" Decimal(\'-Infinity\')"); + +#define _DECIMAL_DECIMAL_FROM_FLOAT_METHODDEF \ + {"from_float", (PyCFunction)_decimal_Decimal_from_float, METH_O|METH_CLASS, _decimal_Decimal_from_float__doc__}, + +static PyObject * +_decimal_Decimal_from_float_impl(PyTypeObject *type, PyObject *pyfloat); + +static PyObject * +_decimal_Decimal_from_float(PyObject *type, PyObject *pyfloat) +{ + PyObject *return_value = NULL; + + return_value = _decimal_Decimal_from_float_impl((PyTypeObject *)type, pyfloat); + + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_from_number__doc__, +"from_number($type, number, /)\n" +"--\n" +"\n" +"Class method that converts a real number to a decimal number, exactly.\n" +"\n" +" >>> Decimal.from_number(314) # int\n" +" Decimal(\'314\')\n" +" >>> Decimal.from_number(0.1) # float\n" +" Decimal(\'0.1000000000000000055511151231257827021181583404541015625\')\n" +" >>> Decimal.from_number(Decimal(\'3.14\')) # another decimal instance\n" +" Decimal(\'3.14\')"); + +#define _DECIMAL_DECIMAL_FROM_NUMBER_METHODDEF \ + {"from_number", (PyCFunction)_decimal_Decimal_from_number, METH_O|METH_CLASS, _decimal_Decimal_from_number__doc__}, + +static PyObject * +_decimal_Decimal_from_number_impl(PyTypeObject *type, PyObject *number); + +static PyObject * +_decimal_Decimal_from_number(PyObject *type, PyObject *number) +{ + PyObject *return_value = NULL; + + return_value = _decimal_Decimal_from_number_impl((PyTypeObject *)type, number); + + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_as_integer_ratio__doc__, +"as_integer_ratio($self, /)\n" +"--\n" +"\n" +"Return a pair of integers, whose ratio is exactly equal to the original.\n" +"\n" +"The ratio is in lowest terms and with a positive denominator. Raise\n" +"OverflowError on infinities and a ValueError on NaNs."); + +#define _DECIMAL_DECIMAL_AS_INTEGER_RATIO_METHODDEF \ + {"as_integer_ratio", (PyCFunction)_decimal_Decimal_as_integer_ratio, METH_NOARGS, _decimal_Decimal_as_integer_ratio__doc__}, + +static PyObject * +_decimal_Decimal_as_integer_ratio_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_as_integer_ratio(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_as_integer_ratio_impl(self); +} + PyDoc_STRVAR(_decimal_Decimal_to_integral__doc__, "to_integral($self, /, rounding=None, context=None)\n" "--\n" @@ -157,6 +241,24 @@ _decimal_Decimal_to_integral_exact(PyObject *self, PyObject *const *args, Py_ssi return return_value; } +PyDoc_STRVAR(_decimal_Decimal_as_tuple__doc__, +"as_tuple($self, /)\n" +"--\n" +"\n" +"Return a tuple representation of the number."); + +#define _DECIMAL_DECIMAL_AS_TUPLE_METHODDEF \ + {"as_tuple", (PyCFunction)_decimal_Decimal_as_tuple, METH_NOARGS, _decimal_Decimal_as_tuple__doc__}, + +static PyObject * +_decimal_Decimal_as_tuple_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_as_tuple(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_as_tuple_impl(self); +} + PyDoc_STRVAR(_decimal_Decimal_adjusted__doc__, "adjusted($self, /)\n" "--\n" @@ -175,6 +277,254 @@ _decimal_Decimal_adjusted(PyObject *self, PyObject *Py_UNUSED(ignored)) return _decimal_Decimal_adjusted_impl(self); } +PyDoc_STRVAR(_decimal_Decimal_canonical__doc__, +"canonical($self, /)\n" +"--\n" +"\n" +"Return the canonical encoding of the argument.\n" +"\n" +"Currently, the encoding of a Decimal instance is always canonical, so this\n" +"operation returns its argument unchanged."); + +#define _DECIMAL_DECIMAL_CANONICAL_METHODDEF \ + {"canonical", (PyCFunction)_decimal_Decimal_canonical, METH_NOARGS, _decimal_Decimal_canonical__doc__}, + +static PyObject * +_decimal_Decimal_canonical_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_canonical(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_canonical_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_conjugate__doc__, +"conjugate($self, /)\n" +"--\n" +"\n" +"Return self."); + +#define _DECIMAL_DECIMAL_CONJUGATE_METHODDEF \ + {"conjugate", (PyCFunction)_decimal_Decimal_conjugate, METH_NOARGS, _decimal_Decimal_conjugate__doc__}, + +static PyObject * +_decimal_Decimal_conjugate_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_conjugate(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_conjugate_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_radix__doc__, +"radix($self, /)\n" +"--\n" +"\n" +"Return Decimal(10).\n" +"\n" +"I.e. return the radix (base) in which the Decimal class does\n" +"all its arithmetic. Included for compatibility with the specification."); + +#define _DECIMAL_DECIMAL_RADIX_METHODDEF \ + {"radix", (PyCFunction)_decimal_Decimal_radix, METH_NOARGS, _decimal_Decimal_radix__doc__}, + +static PyObject * +_decimal_Decimal_radix_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_radix(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_radix_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_copy_abs__doc__, +"copy_abs($self, /)\n" +"--\n" +"\n" +"Return the absolute value of the argument.\n" +"\n" +"This operation is unaffected by context and is quiet: no flags are changed and\n" +"no rounding is performed."); + +#define _DECIMAL_DECIMAL_COPY_ABS_METHODDEF \ + {"copy_abs", (PyCFunction)_decimal_Decimal_copy_abs, METH_NOARGS, _decimal_Decimal_copy_abs__doc__}, + +static PyObject * +_decimal_Decimal_copy_abs_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_copy_abs(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_copy_abs_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_copy_negate__doc__, +"copy_negate($self, /)\n" +"--\n" +"\n" +"Return the negation of the argument.\n" +"\n" +"This operation is unaffected by context and is quiet: no flags are changed and\n" +"no rounding is performed."); + +#define _DECIMAL_DECIMAL_COPY_NEGATE_METHODDEF \ + {"copy_negate", (PyCFunction)_decimal_Decimal_copy_negate, METH_NOARGS, _decimal_Decimal_copy_negate__doc__}, + +static PyObject * +_decimal_Decimal_copy_negate_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_copy_negate(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_copy_negate_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_number_class__doc__, +"number_class($self, /, context=None)\n" +"--\n" +"\n" +"Return a string describing the class of the operand.\n" +"\n" +"The returned value is one of the following ten strings:\n" +"\n" +" * \'-Infinity\', indicating that the operand is negative infinity.\n" +" * \'-Normal\', indicating that the operand is a negative normal number.\n" +" * \'-Subnormal\', indicating that the operand is negative and subnormal.\n" +" * \'-Zero\', indicating that the operand is a negative zero.\n" +" * \'+Zero\', indicating that the operand is a positive zero.\n" +" * \'+Subnormal\', indicating that the operand is positive and subnormal.\n" +" * \'+Normal\', indicating that the operand is a positive normal number.\n" +" * \'+Infinity\', indicating that the operand is positive infinity.\n" +" * \'NaN\', indicating that the operand is a quiet NaN (Not a Number).\n" +" * \'sNaN\', indicating that the operand is a signaling NaN."); + +#define _DECIMAL_DECIMAL_NUMBER_CLASS_METHODDEF \ + {"number_class", _PyCFunction_CAST(_decimal_Decimal_number_class), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_number_class__doc__}, + +static PyObject * +_decimal_Decimal_number_class_impl(PyObject *self, PyObject *context); + +static PyObject * +_decimal_Decimal_number_class(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "number_class", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_number_class_impl(self, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_to_eng_string__doc__, +"to_eng_string($self, /, context=None)\n" +"--\n" +"\n" +"Convert to an engineering-type string.\n" +"\n" +"Engineering notation has an exponent which is a multiple of 3, so there are up\n" +"to 3 digits left of the decimal place. For example, Decimal(\'123E+1\') is\n" +"converted to Decimal(\'1.23E+3\').\n" +"\n" +"The value of context.capitals determines whether the exponent sign is lower or\n" +"upper case. Otherwise, the context does not affect the operation."); + +#define _DECIMAL_DECIMAL_TO_ENG_STRING_METHODDEF \ + {"to_eng_string", _PyCFunction_CAST(_decimal_Decimal_to_eng_string), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_eng_string__doc__}, + +static PyObject * +_decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context); + +static PyObject * +_decimal_Decimal_to_eng_string(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "to_eng_string", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_to_eng_string_impl(self, context); + +exit: + return return_value; +} + PyDoc_STRVAR(_decimal_Decimal_copy_sign__doc__, "copy_sign($self, /, other, context=None)\n" "--\n" @@ -250,6 +600,76 @@ _decimal_Decimal_copy_sign(PyObject *self, PyObject *const *args, Py_ssize_t nar return return_value; } +PyDoc_STRVAR(_decimal_Decimal_same_quantum__doc__, +"same_quantum($self, /, other, context=None)\n" +"--\n" +"\n" +"Test whether self and other have the same exponent or whether both are NaN.\n" +"\n" +"This operation is unaffected by context and is quiet: no flags are changed and\n" +"no rounding is performed. As an exception, the C version may raise\n" +"InvalidOperation if the second operand cannot be converted exactly."); + +#define _DECIMAL_DECIMAL_SAME_QUANTUM_METHODDEF \ + {"same_quantum", _PyCFunction_CAST(_decimal_Decimal_same_quantum), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_same_quantum__doc__}, + +static PyObject * +_decimal_Decimal_same_quantum_impl(PyObject *self, PyObject *other, + PyObject *context); + +static PyObject * +_decimal_Decimal_same_quantum(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "same_quantum", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_same_quantum_impl(self, other, context); + +exit: + return return_value; +} + PyDoc_STRVAR(_decimal_Decimal_quantize__doc__, "quantize($self, /, exp, rounding=None, context=None)\n" "--\n" @@ -341,4 +761,4 @@ _decimal_Decimal_quantize(PyObject *self, PyObject *const *args, Py_ssize_t narg exit: return return_value; } -/*[clinic end generated code: output=7bdae3731d58dc09 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1a75fdce7878ecb4 input=a9049054013a1b77]*/ diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h index 55ece4ddde6b15..95106e3c2f56ea 100644 --- a/Modules/_decimal/docstrings.h +++ b/Modules/_decimal/docstrings.h @@ -57,27 +57,6 @@ context does not affect the conversion and is only passed to determine if\n\ the InvalidOperation trap is active.\n\ \n"); -PyDoc_STRVAR(doc_as_tuple, -"as_tuple($self, /)\n--\n\n\ -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\ -of a Decimal instance is always canonical, so this operation returns its\n\ -argument unchanged.\n\ -\n"); - PyDoc_STRVAR(doc_compare, "compare($self, /, other, context=None)\n--\n\n\ Compare self to other. Return a decimal value:\n\ @@ -127,23 +106,6 @@ and no rounding is performed. As an exception, the C version may raise\n\ InvalidOperation if the second operand cannot be converted exactly.\n\ \n"); -PyDoc_STRVAR(doc_conjugate, -"conjugate($self, /)\n--\n\n\ -Return self.\n\ -\n"); - -PyDoc_STRVAR(doc_copy_abs, -"copy_abs($self, /)\n--\n\n\ -Return the absolute value of the argument. This operation is unaffected by\n\ -context and is quiet: no flags are changed and no rounding is performed.\n\ -\n"); - -PyDoc_STRVAR(doc_copy_negate, -"copy_negate($self, /)\n--\n\n\ -Return the negation of the argument. This operation is unaffected by context\n\ -and is quiet: no flags are changed and no rounding is performed.\n\ -\n"); - PyDoc_STRVAR(doc_exp, "exp($self, /, context=None)\n--\n\n\ Return the value of the (natural) exponential function e**x at the given\n\ @@ -151,36 +113,6 @@ number. The function always uses the ROUND_HALF_EVEN mode and the result\n\ is correctly rounded.\n\ \n"); -PyDoc_STRVAR(doc_from_float, -"from_float($type, f, /)\n--\n\n\ -Class method that converts a float to a decimal number, exactly.\n\ -Since 0.1 is not exactly representable in binary floating point,\n\ -Decimal.from_float(0.1) is not the same as Decimal('0.1').\n\ -\n\ - >>> Decimal.from_float(0.1)\n\ - Decimal('0.1000000000000000055511151231257827021181583404541015625')\n\ - >>> Decimal.from_float(float('nan'))\n\ - Decimal('NaN')\n\ - >>> Decimal.from_float(float('inf'))\n\ - Decimal('Infinity')\n\ - >>> Decimal.from_float(float('-inf'))\n\ - Decimal('-Infinity')\n\ -\n\ -\n"); - -PyDoc_STRVAR(doc_from_number, -"from_number($type, number, /)\n--\n\n\ -Class method that converts a real number to a decimal number, exactly.\n\ -\n\ - >>> Decimal.from_number(314) # int\n\ - Decimal('314')\n\ - >>> Decimal.from_number(0.1) # float\n\ - Decimal('0.1000000000000000055511151231257827021181583404541015625')\n\ - >>> Decimal.from_number(Decimal('3.14')) # another decimal instance\n\ - Decimal('3.14')\n\ -\n\ -\n"); - PyDoc_STRVAR(doc_fma, "fma($self, /, other, third, context=None)\n--\n\n\ Fused multiply-add. Return self*other+third with no rounding of the\n\ @@ -347,30 +279,6 @@ For example, Decimal('32.100') and Decimal('0.321000e+2') both normalize\n\ to the equivalent value Decimal('32.1').\n\ \n"); -PyDoc_STRVAR(doc_number_class, -"number_class($self, /, context=None)\n--\n\n\ -Return a string describing the class of the operand. The returned value\n\ -is one of the following ten strings:\n\ -\n\ - * '-Infinity', indicating that the operand is negative infinity.\n\ - * '-Normal', indicating that the operand is a negative normal number.\n\ - * '-Subnormal', indicating that the operand is negative and subnormal.\n\ - * '-Zero', indicating that the operand is a negative zero.\n\ - * '+Zero', indicating that the operand is a positive zero.\n\ - * '+Subnormal', indicating that the operand is positive and subnormal.\n\ - * '+Normal', indicating that the operand is a positive normal number.\n\ - * '+Infinity', indicating that the operand is positive infinity.\n\ - * 'NaN', indicating that the operand is a quiet NaN (Not a Number).\n\ - * 'sNaN', indicating that the operand is a signaling NaN.\n\ -\n\ -\n"); - -PyDoc_STRVAR(doc_radix, -"radix($self, /)\n--\n\n\ -Return Decimal(10), the radix (base) in which the Decimal class does\n\ -all its arithmetic. Included for compatibility with the specification.\n\ -\n"); - PyDoc_STRVAR(doc_remainder_near, "remainder_near($self, /, other, context=None)\n--\n\n\ Return the remainder from dividing self by other. This differs from\n\ @@ -394,15 +302,6 @@ length precision if necessary. The sign and exponent of the first operand are\n\ unchanged.\n\ \n"); -PyDoc_STRVAR(doc_same_quantum, -"same_quantum($self, /, other, context=None)\n--\n\n\ -Test whether self and other have the same exponent or whether both are NaN.\n\ -\n\ -This operation is unaffected by context and is quiet: no flags are changed\n\ -and no rounding is performed. As an exception, the C version may raise\n\ -InvalidOperation if the second operand cannot be converted exactly.\n\ -\n"); - PyDoc_STRVAR(doc_scaleb, "scaleb($self, /, other, context=None)\n--\n\n\ Return the first operand with the exponent adjusted the second. Equivalently,\n\ @@ -427,16 +326,6 @@ Return the square root of the argument to full precision. The result is\n\ correctly rounded using the ROUND_HALF_EVEN rounding mode.\n\ \n"); -PyDoc_STRVAR(doc_to_eng_string, -"to_eng_string($self, /, context=None)\n--\n\n\ -Convert to an engineering-type string. Engineering notation has an exponent\n\ -which is a multiple of 3, so there are up to 3 digits left of the decimal\n\ -place. For example, Decimal('123E+1') is converted to Decimal('1.23E+3').\n\ -\n\ -The value of context.capitals determines whether the exponent sign is lower\n\ -or upper case. Otherwise, the context does not affect the operation.\n\ -\n"); - PyDoc_STRVAR(doc_to_integral_value, "to_integral_value($self, /, rounding=None, context=None)\n--\n\n\ Round to the nearest integer without signaling Inexact or Rounded. The\n\ From b161565ee008e20d8b645b0c57d212663a574e9f Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sun, 10 Aug 2025 23:06:58 +0100 Subject: [PATCH 04/16] Reduce docstring diff --- Modules/_decimal/_decimal.c | 47 +++++++++++++--------------- Modules/_decimal/clinic/_decimal.c.h | 31 +++++++++--------- 2 files changed, 35 insertions(+), 43 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 67c67576f406d6..94f26c52b43c15 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -2899,12 +2899,11 @@ Decimal.from_float(0.1) is not the same as Decimal('0.1'). Decimal('Infinity') >>> Decimal.from_float(float('-inf')) Decimal('-Infinity') - [clinic start generated code]*/ static PyObject * _decimal_Decimal_from_float_impl(PyTypeObject *type, PyObject *pyfloat) -/*[clinic end generated code: output=e62775271ac469e6 input=31302a9a4c1d9c99]*/ +/*[clinic end generated code: output=e62775271ac469e6 input=052036648342f8c8]*/ { PyObject *context; PyObject *result; @@ -3807,15 +3806,15 @@ dec_as_long(PyObject *dec, PyObject *context, int round) /*[clinic input] _decimal.Decimal.as_integer_ratio -Return a pair of integers, whose ratio is exactly equal to the original. +Return a pair of integers whose ratio is exactly equal to the original. -The ratio is in lowest terms and with a positive denominator. Raise -OverflowError on infinities and a ValueError on NaNs. +The ratio is in lowest terms and with a positive denominator. +Raise OverflowError on infinities and a ValueError on NaNs. [clinic start generated code]*/ static PyObject * _decimal_Decimal_as_integer_ratio_impl(PyObject *self) -/*[clinic end generated code: output=c5d88e900080c264 input=3a4819b9484919d5]*/ +/*[clinic end generated code: output=c5d88e900080c264 input=7861cb643f01525a]*/ { PyObject *numerator = NULL; PyObject *denominator = NULL; @@ -3971,9 +3970,9 @@ _decimal.Decimal.to_integral_exact rounding: object = None context: object = None -Rounds to a nearby integer. +Round to the nearest integer. -Round to the nearest integer, signaling Inexact or Rounded as appropriate if +Decimal.to_integral_exact() signals Inexact or Rounded as appropriate if rounding occurs. The rounding mode is determined by the rounding parameter if given, else by the given context. If neither parameter is given, then the rounding mode of the current default context is used. @@ -3982,7 +3981,7 @@ rounding mode of the current default context is used. static PyObject * _decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=8b004f9b45ac7746 input=e98e6aabbc97a92c]*/ +/*[clinic end generated code: output=8b004f9b45ac7746 input=edd30a9f06aed70b]*/ { PyObject *result; uint32_t status = 0; @@ -4661,13 +4660,13 @@ _decimal.Decimal.radix Return Decimal(10). -I.e. return the radix (base) in which the Decimal class does +This is the radix (base) in which the Decimal class does all its arithmetic. Included for compatibility with the specification. [clinic start generated code]*/ static PyObject * _decimal_Decimal_radix_impl(PyObject *self) -/*[clinic end generated code: output=6b1db4c3fcdb5ee1 input=c25ca314723040ed]*/ +/*[clinic end generated code: output=6b1db4c3fcdb5ee1 input=18b72393549ca8fd]*/ { decimal_state *state = get_module_state_by_def(Py_TYPE(self)); return _dec_mpd_radix(state); @@ -4784,14 +4783,13 @@ Engineering notation has an exponent which is a multiple of 3, so there are up to 3 digits left of the decimal place. For example, Decimal('123E+1') is converted to Decimal('1.23E+3'). -The value of context.capitals determines whether the exponent sign is lower or -upper case. Otherwise, the context does not affect the operation. - +The value of context.capitals determines whether the exponent sign is lower +or upper case. Otherwise, the context does not affect the operation. [clinic start generated code]*/ static PyObject * _decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=d386194c25ffffa7 input=fac5029cbf436bd5]*/ +/*[clinic end generated code: output=d386194c25ffffa7 input=36436cb7973dd5d0]*/ { PyObject *result; mpd_ssize_t size; @@ -4822,7 +4820,7 @@ _decimal.Decimal.copy_sign other: object context: object = None -Returns self with the sign of other. +Return a copy of *self* with the sign set to be the same as the sign of *other*. For example: @@ -4830,14 +4828,14 @@ For example: Decimal('-2.3') This operation is unaffected by context and is quiet: no flags are changed -and no rounding is performed. As an exception, the C version may raise +and no rounding is performed. As an exception, the C version may raise InvalidOperation if the second operand cannot be converted exactly. [clinic start generated code]*/ static PyObject * _decimal_Decimal_copy_sign_impl(PyObject *self, PyObject *other, PyObject *context) -/*[clinic end generated code: output=72c62177763e012e input=f02ebb5d7489c502]*/ +/*[clinic end generated code: output=72c62177763e012e input=96b620d142ed80a9]*/ { PyObject *a, *b; PyObject *result; @@ -4873,15 +4871,15 @@ _decimal.Decimal.same_quantum Test whether self and other have the same exponent or whether both are NaN. -This operation is unaffected by context and is quiet: no flags are changed and -no rounding is performed. As an exception, the C version may raise +This operation is unaffected by context and is quiet: no flags are changed +and no rounding is performed. As an exception, the C version may raise InvalidOperation if the second operand cannot be converted exactly. [clinic start generated code]*/ static PyObject * _decimal_Decimal_same_quantum_impl(PyObject *self, PyObject *other, PyObject *context) -/*[clinic end generated code: output=c0a3a046c662a7e2 input=0930e11241231ac2]*/ +/*[clinic end generated code: output=c0a3a046c662a7e2 input=d583092dec58453e]*/ { PyObject *a, *b; PyObject *result; @@ -4913,10 +4911,7 @@ _decimal.Decimal.quantize rounding: object = None context: object = None -Quantize self so its exponent is the same as that of exp. - -Return a value equal to the first operand after rounding and having the -exponent of the second operand. +Return a value equal to *self* after rounding, with the exponent of *other*. >>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414') @@ -4938,7 +4933,7 @@ argument is given, the rounding mode of the current thread's context is used. static PyObject * _decimal_Decimal_quantize_impl(PyObject *self, PyObject *w, PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=5e84581f96dc685c input=eed2fdd8d65fce21]*/ +/*[clinic end generated code: output=5e84581f96dc685c input=2053ebf488a665dc]*/ { PyObject *a, *b; PyObject *result; diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index 5d04fe0989d6d8..ae9b84dd19d49d 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -75,10 +75,10 @@ PyDoc_STRVAR(_decimal_Decimal_as_integer_ratio__doc__, "as_integer_ratio($self, /)\n" "--\n" "\n" -"Return a pair of integers, whose ratio is exactly equal to the original.\n" +"Return a pair of integers whose ratio is exactly equal to the original.\n" "\n" -"The ratio is in lowest terms and with a positive denominator. Raise\n" -"OverflowError on infinities and a ValueError on NaNs."); +"The ratio is in lowest terms and with a positive denominator.\n" +"Raise OverflowError on infinities and a ValueError on NaNs."); #define _DECIMAL_DECIMAL_AS_INTEGER_RATIO_METHODDEF \ {"as_integer_ratio", (PyCFunction)_decimal_Decimal_as_integer_ratio, METH_NOARGS, _decimal_Decimal_as_integer_ratio__doc__}, @@ -169,9 +169,9 @@ PyDoc_STRVAR(_decimal_Decimal_to_integral_exact__doc__, "to_integral_exact($self, /, rounding=None, context=None)\n" "--\n" "\n" -"Rounds to a nearby integer.\n" +"Round to the nearest integer.\n" "\n" -"Round to the nearest integer, signaling Inexact or Rounded as appropriate if\n" +"Decimal.to_integral_exact() signals Inexact or Rounded as appropriate if\n" "rounding occurs. The rounding mode is determined by the rounding parameter\n" "if given, else by the given context. If neither parameter is given, then the\n" "rounding mode of the current default context is used."); @@ -322,7 +322,7 @@ PyDoc_STRVAR(_decimal_Decimal_radix__doc__, "\n" "Return Decimal(10).\n" "\n" -"I.e. return the radix (base) in which the Decimal class does\n" +"This is the radix (base) in which the Decimal class does\n" "all its arithmetic. Included for compatibility with the specification."); #define _DECIMAL_DECIMAL_RADIX_METHODDEF \ @@ -465,8 +465,8 @@ PyDoc_STRVAR(_decimal_Decimal_to_eng_string__doc__, "to 3 digits left of the decimal place. For example, Decimal(\'123E+1\') is\n" "converted to Decimal(\'1.23E+3\').\n" "\n" -"The value of context.capitals determines whether the exponent sign is lower or\n" -"upper case. Otherwise, the context does not affect the operation."); +"The value of context.capitals determines whether the exponent sign is lower\n" +"or upper case. Otherwise, the context does not affect the operation."); #define _DECIMAL_DECIMAL_TO_ENG_STRING_METHODDEF \ {"to_eng_string", _PyCFunction_CAST(_decimal_Decimal_to_eng_string), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_eng_string__doc__}, @@ -529,7 +529,7 @@ PyDoc_STRVAR(_decimal_Decimal_copy_sign__doc__, "copy_sign($self, /, other, context=None)\n" "--\n" "\n" -"Returns self with the sign of other.\n" +"Return a copy of *self* with the sign set to be the same as the sign of *other*.\n" "\n" "For example:\n" "\n" @@ -537,7 +537,7 @@ PyDoc_STRVAR(_decimal_Decimal_copy_sign__doc__, " Decimal(\'-2.3\')\n" "\n" "This operation is unaffected by context and is quiet: no flags are changed\n" -"and no rounding is performed. As an exception, the C version may raise\n" +"and no rounding is performed. As an exception, the C version may raise\n" "InvalidOperation if the second operand cannot be converted exactly."); #define _DECIMAL_DECIMAL_COPY_SIGN_METHODDEF \ @@ -606,8 +606,8 @@ PyDoc_STRVAR(_decimal_Decimal_same_quantum__doc__, "\n" "Test whether self and other have the same exponent or whether both are NaN.\n" "\n" -"This operation is unaffected by context and is quiet: no flags are changed and\n" -"no rounding is performed. As an exception, the C version may raise\n" +"This operation is unaffected by context and is quiet: no flags are changed\n" +"and no rounding is performed. As an exception, the C version may raise\n" "InvalidOperation if the second operand cannot be converted exactly."); #define _DECIMAL_DECIMAL_SAME_QUANTUM_METHODDEF \ @@ -674,10 +674,7 @@ PyDoc_STRVAR(_decimal_Decimal_quantize__doc__, "quantize($self, /, exp, rounding=None, context=None)\n" "--\n" "\n" -"Quantize self so its exponent is the same as that of exp.\n" -"\n" -"Return a value equal to the first operand after rounding and having the\n" -"exponent of the second operand.\n" +"Return a value equal to *self* after rounding, with the exponent of *other*.\n" "\n" " >>> Decimal(\'1.41421356\').quantize(Decimal(\'1.000\'))\n" " Decimal(\'1.414\')\n" @@ -761,4 +758,4 @@ _decimal_Decimal_quantize(PyObject *self, PyObject *const *args, Py_ssize_t narg exit: return return_value; } -/*[clinic end generated code: output=1a75fdce7878ecb4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=304ce135eee594cc input=a9049054013a1b77]*/ From 2c53b4869eb194378346f2de26fd2d079076e7fc Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 11 Aug 2025 04:09:47 +0300 Subject: [PATCH 05/16] Apply suggestions from code review Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Modules/_decimal/_decimal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 94f26c52b43c15..3804018fc5a0d5 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -2912,7 +2912,8 @@ _decimal_Decimal_from_float_impl(PyTypeObject *type, PyObject *pyfloat) CURRENT_CONTEXT(state, context); result = PyDecType_FromFloatExact(state->PyDec_Type, pyfloat, context); if (type != state->PyDec_Type && result != NULL) { - Py_SETREF(result, PyObject_CallFunctionObjArgs((PyObject *)type, result, NULL)); + Py_SETREF(result, + PyObject_CallFunctionObjArgs((PyObject *)type, result, NULL)); } return result; @@ -2976,7 +2977,8 @@ _decimal_Decimal_from_number_impl(PyTypeObject *type, PyObject *number) CURRENT_CONTEXT(state, context); result = PyDecType_FromNumberExact(state->PyDec_Type, number, context); if (type != state->PyDec_Type && result != NULL) { - Py_SETREF(result, PyObject_CallFunctionObjArgs((PyObject *)type, result, NULL)); + Py_SETREF(result, + PyObject_CallFunctionObjArgs((PyObject *)type, result, NULL)); } return result; From 354d8dbdb5255e926a8970823b94c0b5f2233f21 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 11 Aug 2025 02:10:00 +0300 Subject: [PATCH 06/16] +1 --- Modules/_decimal/_decimal.c | 595 +++++++- Modules/_decimal/clinic/_decimal.c.h | 2092 ++++++++++++++++++++++++-- Modules/_decimal/docstrings.h | 127 -- 3 files changed, 2479 insertions(+), 335 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 3804018fc5a0d5..15670a1e5d582f 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -4017,6 +4017,27 @@ _decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, return result; } +/*[clinic input] +_decimal.Decimal.to_integral_value + + rounding: object = None + context: object = None + +Round to the nearest integer without signaling Inexact or Rounded. + +The rounding mode is determined by the rounding parameter if given, else by +the given context. If neither parameter is given, then the rounding mode of +the current default context is used. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, + PyObject *context) +/*[clinic end generated code: output=7301465765f48b6b input=5778168222cadf71]*/ +{ + return _decimal_Decimal_to_integral_impl(self, rounding, context); +} + static PyObject * PyDec_AsFloat(PyObject *dec) { @@ -4289,17 +4310,10 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ /* Unary function with an optional context arg. */ #define Dec_UnaryFuncVA(MPDFUNC) \ static PyObject * \ -dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +dec_##MPDFUNC(PyObject *self, PyObject *context) \ { \ - static char *kwlist[] = {"context", NULL}; \ PyObject *result; \ - PyObject *context = Py_None; \ uint32_t status = 0; \ - \ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \ - &context)) { \ - return NULL; \ - } \ decimal_state *state = \ get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ @@ -4320,19 +4334,11 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ /* Binary function with an optional context arg. */ #define Dec_BinaryFuncVA(MPDFUNC) \ static PyObject * \ -dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +dec_##MPDFUNC(PyObject *self, PyObject *other, PyObject *context)\ { \ - static char *kwlist[] = {"other", "context", NULL}; \ - PyObject *other; \ PyObject *a, *b; \ PyObject *result; \ - PyObject *context = Py_None; \ uint32_t status = 0; \ - \ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \ - &other, &context)) { \ - return NULL; \ - } \ decimal_state *state = \ get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ @@ -4360,18 +4366,10 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ if the second operand cannot be converted exactly. */ #define Dec_BinaryFuncVA_NO_CTX(MPDFUNC) \ static PyObject * \ -dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +dec_##MPDFUNC(PyObject *self, PyObject *other, PyObject *context)\ { \ - static char *kwlist[] = {"other", "context", NULL}; \ - PyObject *context = Py_None; \ - PyObject *other; \ PyObject *a, *b; \ PyObject *result; \ - \ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \ - &other, &context)) { \ - return NULL; \ - } \ decimal_state *state = \ get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ @@ -4563,6 +4561,127 @@ Dec_UnaryFuncVA(mpd_qnext_plus) Dec_UnaryFuncVA(mpd_qreduce) Dec_UnaryFuncVA(mpd_qsqrt) +/*[clinic input] +_decimal.Decimal.exp + + context: object = None + +Return the value of the (natural) exponential function e**x at the given number. + +The function always uses the ROUND_HALF_EVEN mode and the result is correctly +rounded. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_exp_impl(PyObject *self, PyObject *context) +/*[clinic end generated code: output=c0833b6e9b8c836f input=8d6adbec7d01dc04]*/ +{ + return dec_mpd_qexp(self, context); +} + +/*[clinic input] +_decimal.Decimal.ln + + context: object = None + +Return the natural (base e) logarithm of the operand. + +The function always uses the ROUND_HALF_EVEN mode and the result is correctly +rounded. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_ln_impl(PyObject *self, PyObject *context) +/*[clinic end generated code: output=5191f4ef739b04b0 input=d5c1e0cd49764ccf]*/ +{ + return dec_mpd_qln(self, context); +} + +/*[clinic input] +_decimal.Decimal.log10 + + context: object = None + +Return the base ten logarithm of the operand. + +The function always uses the ROUND_HALF_EVEN mode and the result is correctly +rounded. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_log10_impl(PyObject *self, PyObject *context) +/*[clinic end generated code: output=d5da63df75900275 input=b46068288e21d403]*/ +{ + return dec_mpd_qlog10(self, context); +} + +/*[clinic input] +_decimal.Decimal.next_minus + + context: object = None + +Returns the largest representable number smaller than itself. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_next_minus_impl(PyObject *self, PyObject *context) +/*[clinic end generated code: output=aacbd758399f883f input=75666c6dc3cc8da9]*/ +{ + return dec_mpd_qnext_minus(self, context); +} + +/*[clinic input] +_decimal.Decimal.next_plus + + context: object = None + +Returns the smallest representable number larger than itself. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_next_plus_impl(PyObject *self, PyObject *context) +/*[clinic end generated code: output=f3a7029a213c553c input=adcccf3f94e8da3f]*/ +{ + return dec_mpd_qnext_plus(self, context); +} + +/*[clinic input] +_decimal.Decimal.normalize + + context: object = None + +Normalize the number by stripping trailing 0s, change anything equal to 0 to 0e0. + +Used for producing canonical values for members of an equivalence class. For +example, Decimal('32.100') and Decimal('0.321000e+2') both normalize to the +equivalent value Decimal('32.1'). +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_normalize_impl(PyObject *self, PyObject *context) +/*[clinic end generated code: output=db2c8b3c8eccff36 input=16585b21c91500d1]*/ +{ + return dec_mpd_qreduce(self, context); +} + +/*[clinic input] +_decimal.Decimal.sqrt + + context: object = None + +Return the square root of the argument to full precision. + +The result is correctly rounded using the ROUND_HALF_EVEN rounding mode. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_sqrt_impl(PyObject *self, PyObject *context) +/*[clinic end generated code: output=420722a199dd9c2b input=16df570867daf0d6]*/ +{ + return dec_mpd_qsqrt(self, context); +} + + /* Binary arithmetic functions, optional context arg */ Dec_BinaryFuncVA(mpd_qcompare) Dec_BinaryFuncVA(mpd_qcompare_signal) @@ -4573,6 +4692,166 @@ Dec_BinaryFuncVA(mpd_qmin_mag) Dec_BinaryFuncVA(mpd_qnext_toward) Dec_BinaryFuncVA(mpd_qrem_near) +/*[clinic input] +_decimal.Decimal.compare + + other: object + context: object = None + +Compare self to other. + +Return a decimal value: + + a or b is a NaN ==> Decimal('NaN') + a < b ==> Decimal('-1') + a == b ==> Decimal('0') + a > b ==> Decimal('1') +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_compare_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=d6967aa3578b9d48 input=1b7b75a2a154e520]*/ +{ + return dec_mpd_qcompare(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.compare_signal + + other: object + context: object = None + +Identical to compare, except that all NaNs signal. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_compare_signal_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=0b8d0ff43f6c8a95 input=daf40eeaec81606f]*/ +{ + return dec_mpd_qcompare_signal(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.max + + other: object + context: object = None + +Maximum of self and other. + +If one operand is a quiet NaN and the other is numeric, the numeric operand is +returned. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_max_impl(PyObject *self, PyObject *other, PyObject *context) +/*[clinic end generated code: output=f3a5c5d76761c9ff input=3e53509008bde8c6]*/ +{ + return dec_mpd_qmax(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.max_mag + + other: object + context: object = None + +Similar to the max() method, but the comparison is done using the absolute values of the operands. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_max_mag_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=52b0451987bac65f input=3c2233f8d7a39fa5]*/ +{ + return dec_mpd_qmax_mag(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.min + + other: object + context: object = None + +Minimum of self and other. + +If one operand is a quiet NaN and the other is numeric, the numeric operand is +returned. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_min_impl(PyObject *self, PyObject *other, PyObject *context) +/*[clinic end generated code: output=d2f38ecb9d6f0493 input=264e6259b6ccd831]*/ +{ + return dec_mpd_qmin(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.min_mag + + other: object + context: object = None + +Similar to the min() method, but the comparison is done using the absolute values of the operands. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_min_mag_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=aa3391935f6c8fc9 input=06a65c02e17013c8]*/ +{ + return dec_mpd_qmin_mag(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.next_toward + + other: object + context: object = None + +Returns the number closest to self, in the direction towards other. + +If the two operands are unequal, return the number closest to the first +operand in the direction of the second operand. If both operands are +numerically equal, return a copy of the first operand with the sign set +to be the same as the sign of the second operand. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_next_toward_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=edb933755644af69 input=b03dc5ae977012a5]*/ +{ + return dec_mpd_qnext_toward(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.remainder_near + + other: object + context: object = None + +Return the remainder from dividing self by other. + +This differs from self % other in that the sign of the remainder is chosen so +as to minimize its absolute value. More precisely, the return value is self - +n * other where n is the integer nearest to the exact value of self / other, +and if two integers are equally near then the even one is chosen. + +If the result is zero then its sign will be the sign of self. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_remainder_near_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=6ce0fb3b0faff2f9 input=255acde9a0db84bd]*/ +{ + return dec_mpd_qrem_near(self, other, context); +} + + /* Ternary arithmetic functions, optional context arg */ Dec_TernaryFuncVA(mpd_qfma) @@ -4740,6 +5019,41 @@ _decimal_Decimal_copy_negate_impl(PyObject *self) Dec_UnaryFuncVA(mpd_qinvert) Dec_UnaryFuncVA(mpd_qlogb) +/*[clinic input] +_decimal.Decimal.logical_invert + + context: object = None + +Return the digit-wise inversion of the (logical) operand. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_logical_invert_impl(PyObject *self, PyObject *context) +/*[clinic end generated code: output=59beb9b1b51b9f34 input=063cc759635d249b]*/ +{ + return dec_mpd_qinvert(self, context); +} + +/*[clinic input] +_decimal.Decimal.logb + + context: object = None + +Return the adjusted exponent of the operand as a Decimal instance. + +If the operand is a zero, then Decimal('-Infinity') is returned and the +DivisionByZero condition is raised. If the operand is an infinity then +Decimal('Infinity') is returned. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_logb_impl(PyObject *self, PyObject *context) +/*[clinic end generated code: output=f278db20b47f301c input=1a0de8e49b101734]*/ +{ + return dec_mpd_qlogb(self, context); +} + + /*[clinic input] _decimal.Decimal.number_class @@ -4816,6 +5130,65 @@ _decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context) Dec_BinaryFuncVA_NO_CTX(mpd_compare_total) Dec_BinaryFuncVA_NO_CTX(mpd_compare_total_mag) +/*[clinic input] +_decimal.Decimal.compare_total + + other: object + context: object = None + +Compare two operands using their abstract representation rather than their numerical value. + +Similar to the compare() method, but the result +gives a total ordering on Decimal instances. Two Decimal instances with +the same numeric value but different representations compare unequal +in this ordering: + + >>> Decimal('12.0').compare_total(Decimal('12')) + Decimal('-1') + +Quiet and signaling NaNs are also included in the total ordering. The result +of this function is Decimal('0') if both operands have the same representation, +Decimal('-1') if the first operand is lower in the total order than the second, +and Decimal('1') if the first operand is higher in the total order than the +second operand. See the specification for details of the total order. + +This operation is unaffected by context and is quiet: no flags are changed +and no rounding is performed. As an exception, the C version may raise +InvalidOperation if the second operand cannot be converted exactly. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_compare_total_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=dca119b5e881a83e input=f44f1cd5b6fd917e]*/ +{ + return dec_mpd_compare_total(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.compare_total_mag + + other: object + context: object = None + +Compare two operands using their abstract representation rather than their value as in compare_total(), but ignoring the sign of each operand. + +x.compare_total_mag(y) is equivalent to x.copy_abs().compare_total(y.copy_abs()). + +This operation is unaffected by context and is quiet: no flags are changed +and no rounding is performed. As an exception, the C version may raise +InvalidOperation if the second operand cannot be converted exactly. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_compare_total_mag_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=6bf1b3419112d0dd input=84a60b486295a661]*/ +{ + return dec_mpd_compare_total_mag(self, other, context); +} + + /*[clinic input] _decimal.Decimal.copy_sign @@ -4906,6 +5279,124 @@ Dec_BinaryFuncVA(mpd_qrotate) Dec_BinaryFuncVA(mpd_qscaleb) Dec_BinaryFuncVA(mpd_qshift) +/*[clinic input] +_decimal.Decimal.logical_and + + other: object + context: object = None + +Return the digit-wise 'and' of the two (logical) operands. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_logical_and_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=1526a357f97eaf71 input=84d2729d67fca057]*/ +{ + return dec_mpd_qand(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.logical_or + + other: object + context: object = None + +Return the digit-wise 'or' of the two (logical) operands. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_logical_or_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=e57a72acf0982f56 input=03c8141eb7ff8020]*/ +{ + return dec_mpd_qor(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.logical_xor + + other: object + context: object = None + +Return the digit-wise 'xor' of the two (logical) operands. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_logical_xor_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=ae3a7aeddde5a1a8 input=d154ad76a12595a7]*/ +{ + return dec_mpd_qxor(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.rotate + + other: object + context: object = None + +Return the result of rotating the digits of the first operand by an amount specified by the second operand. + +The second operand must be an integer in the range -precision through +precision. The absolute value of the second operand gives the number of places +to rotate. If the second operand is positive then rotation is to the left; +otherwise rotation is to the right. The coefficient of the first operand is +padded on the left with zeros to length precision if necessary. The sign and +exponent of the first operand are unchanged. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_rotate_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=e59e757e70a8416a input=96b253ac6414a884]*/ +{ + return dec_mpd_qrotate(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.scaleb + + other: object + context: object = None + +Return the first operand with the exponent adjusted the second. + +Equivalently, return the first operand multiplied by 10**other. The second +operand must be an integer. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_scaleb_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=f01e99600eda34d7 input=79d9bca73749fa06]*/ +{ + return dec_mpd_qscaleb(self, other, context); +} + +/*[clinic input] +_decimal.Decimal.shift + + other: object + context: object = None + +Return the result of shifting the digits of the first operand by an amount specified by the second operand. + +The second operand must be an integer in the range -precision through +precision. The absolute value of the second operand gives the number of places +to shift. If the second operand is positive, then the shift is to the left; +otherwise the shift is to the right. Digits shifted into the coefficient are +zeros. The sign and exponent of the first operand are unchanged. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_shift_impl(PyObject *self, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=f79ff9ce6d5b05ed input=a680ecfa745bd6e4]*/ +{ + return dec_mpd_qshift(self, other, context); +} + /*[clinic input] _decimal.Decimal.quantize @@ -5285,27 +5776,27 @@ static PyGetSetDef dec_getsets [] = static PyMethodDef dec_methods [] = { /* Unary arithmetic functions, optional context arg */ - { "exp", _PyCFunction_CAST(dec_mpd_qexp), METH_VARARGS|METH_KEYWORDS, doc_exp }, - { "ln", _PyCFunction_CAST(dec_mpd_qln), METH_VARARGS|METH_KEYWORDS, doc_ln }, - { "log10", _PyCFunction_CAST(dec_mpd_qlog10), METH_VARARGS|METH_KEYWORDS, doc_log10 }, - { "next_minus", _PyCFunction_CAST(dec_mpd_qnext_minus), METH_VARARGS|METH_KEYWORDS, doc_next_minus }, - { "next_plus", _PyCFunction_CAST(dec_mpd_qnext_plus), METH_VARARGS|METH_KEYWORDS, doc_next_plus }, - { "normalize", _PyCFunction_CAST(dec_mpd_qreduce), METH_VARARGS|METH_KEYWORDS, doc_normalize }, + _DECIMAL_DECIMAL_EXP_METHODDEF + _DECIMAL_DECIMAL_LN_METHODDEF + _DECIMAL_DECIMAL_LOG10_METHODDEF + _DECIMAL_DECIMAL_NEXT_MINUS_METHODDEF + _DECIMAL_DECIMAL_NEXT_PLUS_METHODDEF + _DECIMAL_DECIMAL_NORMALIZE_METHODDEF _DECIMAL_DECIMAL_TO_INTEGRAL_METHODDEF _DECIMAL_DECIMAL_TO_INTEGRAL_EXACT_METHODDEF - { "to_integral_value", _PyCFunction_CAST(_decimal_Decimal_to_integral), METH_FASTCALL|METH_KEYWORDS, doc_to_integral_value }, - { "sqrt", _PyCFunction_CAST(dec_mpd_qsqrt), METH_VARARGS|METH_KEYWORDS, doc_sqrt }, + _DECIMAL_DECIMAL_TO_INTEGRAL_VALUE_METHODDEF + _DECIMAL_DECIMAL_SQRT_METHODDEF /* Binary arithmetic functions, optional context arg */ - { "compare", _PyCFunction_CAST(dec_mpd_qcompare), METH_VARARGS|METH_KEYWORDS, doc_compare }, - { "compare_signal", _PyCFunction_CAST(dec_mpd_qcompare_signal), METH_VARARGS|METH_KEYWORDS, doc_compare_signal }, - { "max", _PyCFunction_CAST(dec_mpd_qmax), METH_VARARGS|METH_KEYWORDS, doc_max }, - { "max_mag", _PyCFunction_CAST(dec_mpd_qmax_mag), METH_VARARGS|METH_KEYWORDS, doc_max_mag }, - { "min", _PyCFunction_CAST(dec_mpd_qmin), METH_VARARGS|METH_KEYWORDS, doc_min }, - { "min_mag", _PyCFunction_CAST(dec_mpd_qmin_mag), METH_VARARGS|METH_KEYWORDS, doc_min_mag }, - { "next_toward", _PyCFunction_CAST(dec_mpd_qnext_toward), METH_VARARGS|METH_KEYWORDS, doc_next_toward }, + _DECIMAL_DECIMAL_COMPARE_METHODDEF + _DECIMAL_DECIMAL_COMPARE_SIGNAL_METHODDEF + _DECIMAL_DECIMAL_MAX_METHODDEF + _DECIMAL_DECIMAL_MAX_MAG_METHODDEF + _DECIMAL_DECIMAL_MIN_METHODDEF + _DECIMAL_DECIMAL_MIN_MAG_METHODDEF + _DECIMAL_DECIMAL_NEXT_TOWARD_METHODDEF _DECIMAL_DECIMAL_QUANTIZE_METHODDEF - { "remainder_near", _PyCFunction_CAST(dec_mpd_qrem_near), METH_VARARGS|METH_KEYWORDS, doc_remainder_near }, + _DECIMAL_DECIMAL_REMAINDER_NEAR_METHODDEF /* Ternary arithmetic functions, optional context arg */ { "fma", _PyCFunction_CAST(dec_mpd_qfma), METH_VARARGS|METH_KEYWORDS, doc_fma }, @@ -5335,24 +5826,24 @@ static PyMethodDef dec_methods [] = _DECIMAL_DECIMAL_COPY_NEGATE_METHODDEF /* Unary functions, optional context arg */ - { "logb", _PyCFunction_CAST(dec_mpd_qlogb), METH_VARARGS|METH_KEYWORDS, doc_logb }, - { "logical_invert", _PyCFunction_CAST(dec_mpd_qinvert), METH_VARARGS|METH_KEYWORDS, doc_logical_invert }, + _DECIMAL_DECIMAL_LOGB_METHODDEF + _DECIMAL_DECIMAL_LOGICAL_INVERT_METHODDEF _DECIMAL_DECIMAL_NUMBER_CLASS_METHODDEF _DECIMAL_DECIMAL_TO_ENG_STRING_METHODDEF /* Binary functions, optional context arg for conversion errors */ - { "compare_total", _PyCFunction_CAST(dec_mpd_compare_total), METH_VARARGS|METH_KEYWORDS, doc_compare_total }, - { "compare_total_mag", _PyCFunction_CAST(dec_mpd_compare_total_mag), METH_VARARGS|METH_KEYWORDS, doc_compare_total_mag }, + _DECIMAL_DECIMAL_COMPARE_TOTAL_METHODDEF + _DECIMAL_DECIMAL_COMPARE_TOTAL_MAG_METHODDEF _DECIMAL_DECIMAL_COPY_SIGN_METHODDEF _DECIMAL_DECIMAL_SAME_QUANTUM_METHODDEF /* Binary functions, optional context arg */ - { "logical_and", _PyCFunction_CAST(dec_mpd_qand), METH_VARARGS|METH_KEYWORDS, doc_logical_and }, - { "logical_or", _PyCFunction_CAST(dec_mpd_qor), METH_VARARGS|METH_KEYWORDS, doc_logical_or }, - { "logical_xor", _PyCFunction_CAST(dec_mpd_qxor), METH_VARARGS|METH_KEYWORDS, doc_logical_xor }, - { "rotate", _PyCFunction_CAST(dec_mpd_qrotate), METH_VARARGS|METH_KEYWORDS, doc_rotate }, - { "scaleb", _PyCFunction_CAST(dec_mpd_qscaleb), METH_VARARGS|METH_KEYWORDS, doc_scaleb }, - { "shift", _PyCFunction_CAST(dec_mpd_qshift), METH_VARARGS|METH_KEYWORDS, doc_shift }, + _DECIMAL_DECIMAL_LOGICAL_AND_METHODDEF + _DECIMAL_DECIMAL_LOGICAL_OR_METHODDEF + _DECIMAL_DECIMAL_LOGICAL_XOR_METHODDEF + _DECIMAL_DECIMAL_ROTATE_METHODDEF + _DECIMAL_DECIMAL_SCALEB_METHODDEF + _DECIMAL_DECIMAL_SHIFT_METHODDEF /* Miscellaneous */ _DECIMAL_DECIMAL_FROM_FLOAT_METHODDEF diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index ae9b84dd19d49d..8ac46dea2a0384 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -241,6 +241,81 @@ _decimal_Decimal_to_integral_exact(PyObject *self, PyObject *const *args, Py_ssi return return_value; } +PyDoc_STRVAR(_decimal_Decimal_to_integral_value__doc__, +"to_integral_value($self, /, rounding=None, context=None)\n" +"--\n" +"\n" +"Round to the nearest integer without signaling Inexact or Rounded.\n" +"\n" +"The rounding mode is determined by the rounding parameter if given, else by\n" +"the given context. If neither parameter is given, then the rounding mode of\n" +"the current default context is used."); + +#define _DECIMAL_DECIMAL_TO_INTEGRAL_VALUE_METHODDEF \ + {"to_integral_value", _PyCFunction_CAST(_decimal_Decimal_to_integral_value), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_value__doc__}, + +static PyObject * +_decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, + PyObject *context); + +static PyObject * +_decimal_Decimal_to_integral_value(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(rounding), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"rounding", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "to_integral_value", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *rounding = Py_None; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + rounding = args[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_to_integral_value_impl(self, rounding, context); + +exit: + return return_value; +} + PyDoc_STRVAR(_decimal_Decimal_as_tuple__doc__, "as_tuple($self, /)\n" "--\n" @@ -259,158 +334,1862 @@ _decimal_Decimal_as_tuple(PyObject *self, PyObject *Py_UNUSED(ignored)) return _decimal_Decimal_as_tuple_impl(self); } -PyDoc_STRVAR(_decimal_Decimal_adjusted__doc__, -"adjusted($self, /)\n" +PyDoc_STRVAR(_decimal_Decimal_exp__doc__, +"exp($self, /, context=None)\n" "--\n" "\n" -"Return the adjusted exponent of the number. Defined as exp + digits - 1."); +"Return the value of the (natural) exponential function e**x at the given number.\n" +"\n" +"The function always uses the ROUND_HALF_EVEN mode and the result is correctly\n" +"rounded."); -#define _DECIMAL_DECIMAL_ADJUSTED_METHODDEF \ - {"adjusted", (PyCFunction)_decimal_Decimal_adjusted, METH_NOARGS, _decimal_Decimal_adjusted__doc__}, +#define _DECIMAL_DECIMAL_EXP_METHODDEF \ + {"exp", _PyCFunction_CAST(_decimal_Decimal_exp), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_exp__doc__}, static PyObject * -_decimal_Decimal_adjusted_impl(PyObject *self); +_decimal_Decimal_exp_impl(PyObject *self, PyObject *context); static PyObject * -_decimal_Decimal_adjusted(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal_exp(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Decimal_adjusted_impl(self); + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "exp", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_exp_impl(self, context); + +exit: + return return_value; } -PyDoc_STRVAR(_decimal_Decimal_canonical__doc__, -"canonical($self, /)\n" +PyDoc_STRVAR(_decimal_Decimal_ln__doc__, +"ln($self, /, context=None)\n" "--\n" "\n" -"Return the canonical encoding of the argument.\n" +"Return the natural (base e) logarithm of the operand.\n" "\n" -"Currently, the encoding of a Decimal instance is always canonical, so this\n" -"operation returns its argument unchanged."); +"The function always uses the ROUND_HALF_EVEN mode and the result is correctly\n" +"rounded."); -#define _DECIMAL_DECIMAL_CANONICAL_METHODDEF \ - {"canonical", (PyCFunction)_decimal_Decimal_canonical, METH_NOARGS, _decimal_Decimal_canonical__doc__}, +#define _DECIMAL_DECIMAL_LN_METHODDEF \ + {"ln", _PyCFunction_CAST(_decimal_Decimal_ln), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_ln__doc__}, static PyObject * -_decimal_Decimal_canonical_impl(PyObject *self); +_decimal_Decimal_ln_impl(PyObject *self, PyObject *context); + +static PyObject * +_decimal_Decimal_ln(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "ln", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_ln_impl(self, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_log10__doc__, +"log10($self, /, context=None)\n" +"--\n" +"\n" +"Return the base ten logarithm of the operand.\n" +"\n" +"The function always uses the ROUND_HALF_EVEN mode and the result is correctly\n" +"rounded."); + +#define _DECIMAL_DECIMAL_LOG10_METHODDEF \ + {"log10", _PyCFunction_CAST(_decimal_Decimal_log10), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_log10__doc__}, + +static PyObject * +_decimal_Decimal_log10_impl(PyObject *self, PyObject *context); + +static PyObject * +_decimal_Decimal_log10(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "log10", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_log10_impl(self, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_next_minus__doc__, +"next_minus($self, /, context=None)\n" +"--\n" +"\n" +"Returns the largest representable number smaller than itself."); + +#define _DECIMAL_DECIMAL_NEXT_MINUS_METHODDEF \ + {"next_minus", _PyCFunction_CAST(_decimal_Decimal_next_minus), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_minus__doc__}, + +static PyObject * +_decimal_Decimal_next_minus_impl(PyObject *self, PyObject *context); + +static PyObject * +_decimal_Decimal_next_minus(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "next_minus", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_next_minus_impl(self, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_next_plus__doc__, +"next_plus($self, /, context=None)\n" +"--\n" +"\n" +"Returns the smallest representable number larger than itself."); + +#define _DECIMAL_DECIMAL_NEXT_PLUS_METHODDEF \ + {"next_plus", _PyCFunction_CAST(_decimal_Decimal_next_plus), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_plus__doc__}, + +static PyObject * +_decimal_Decimal_next_plus_impl(PyObject *self, PyObject *context); + +static PyObject * +_decimal_Decimal_next_plus(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "next_plus", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_next_plus_impl(self, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_normalize__doc__, +"normalize($self, /, context=None)\n" +"--\n" +"\n" +"Normalize the number by stripping trailing 0s, change anything equal to 0 to 0e0.\n" +"\n" +"Used for producing canonical values for members of an equivalence class. For\n" +"example, Decimal(\'32.100\') and Decimal(\'0.321000e+2\') both normalize to the\n" +"equivalent value Decimal(\'32.1\')."); + +#define _DECIMAL_DECIMAL_NORMALIZE_METHODDEF \ + {"normalize", _PyCFunction_CAST(_decimal_Decimal_normalize), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_normalize__doc__}, + +static PyObject * +_decimal_Decimal_normalize_impl(PyObject *self, PyObject *context); + +static PyObject * +_decimal_Decimal_normalize(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "normalize", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_normalize_impl(self, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_sqrt__doc__, +"sqrt($self, /, context=None)\n" +"--\n" +"\n" +"Return the square root of the argument to full precision.\n" +"\n" +"The result is correctly rounded using the ROUND_HALF_EVEN rounding mode."); + +#define _DECIMAL_DECIMAL_SQRT_METHODDEF \ + {"sqrt", _PyCFunction_CAST(_decimal_Decimal_sqrt), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_sqrt__doc__}, + +static PyObject * +_decimal_Decimal_sqrt_impl(PyObject *self, PyObject *context); + +static PyObject * +_decimal_Decimal_sqrt(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "sqrt", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_sqrt_impl(self, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_compare__doc__, +"compare($self, /, other, context=None)\n" +"--\n" +"\n" +"Compare self to other.\n" +"\n" +"Return a decimal value:\n" +"\n" +" a or b is a NaN ==> Decimal(\'NaN\')\n" +" a < b ==> Decimal(\'-1\')\n" +" a == b ==> Decimal(\'0\')\n" +" a > b ==> Decimal(\'1\')"); + +#define _DECIMAL_DECIMAL_COMPARE_METHODDEF \ + {"compare", _PyCFunction_CAST(_decimal_Decimal_compare), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare__doc__}, + +static PyObject * +_decimal_Decimal_compare_impl(PyObject *self, PyObject *other, + PyObject *context); + +static PyObject * +_decimal_Decimal_compare(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "compare", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_compare_impl(self, other, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_compare_signal__doc__, +"compare_signal($self, /, other, context=None)\n" +"--\n" +"\n" +"Identical to compare, except that all NaNs signal."); + +#define _DECIMAL_DECIMAL_COMPARE_SIGNAL_METHODDEF \ + {"compare_signal", _PyCFunction_CAST(_decimal_Decimal_compare_signal), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_signal__doc__}, + +static PyObject * +_decimal_Decimal_compare_signal_impl(PyObject *self, PyObject *other, + PyObject *context); + +static PyObject * +_decimal_Decimal_compare_signal(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "compare_signal", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_compare_signal_impl(self, other, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_max__doc__, +"max($self, /, other, context=None)\n" +"--\n" +"\n" +"Maximum of self and other.\n" +"\n" +"If one operand is a quiet NaN and the other is numeric, the numeric operand is\n" +"returned."); + +#define _DECIMAL_DECIMAL_MAX_METHODDEF \ + {"max", _PyCFunction_CAST(_decimal_Decimal_max), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_max__doc__}, + +static PyObject * +_decimal_Decimal_max_impl(PyObject *self, PyObject *other, PyObject *context); + +static PyObject * +_decimal_Decimal_max(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "max", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_max_impl(self, other, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_max_mag__doc__, +"max_mag($self, /, other, context=None)\n" +"--\n" +"\n" +"Similar to the max() method, but the comparison is done using the absolute values of the operands."); + +#define _DECIMAL_DECIMAL_MAX_MAG_METHODDEF \ + {"max_mag", _PyCFunction_CAST(_decimal_Decimal_max_mag), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_max_mag__doc__}, + +static PyObject * +_decimal_Decimal_max_mag_impl(PyObject *self, PyObject *other, + PyObject *context); + +static PyObject * +_decimal_Decimal_max_mag(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "max_mag", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_max_mag_impl(self, other, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_min__doc__, +"min($self, /, other, context=None)\n" +"--\n" +"\n" +"Minimum of self and other.\n" +"\n" +"If one operand is a quiet NaN and the other is numeric, the numeric operand is\n" +"returned."); + +#define _DECIMAL_DECIMAL_MIN_METHODDEF \ + {"min", _PyCFunction_CAST(_decimal_Decimal_min), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_min__doc__}, + +static PyObject * +_decimal_Decimal_min_impl(PyObject *self, PyObject *other, PyObject *context); + +static PyObject * +_decimal_Decimal_min(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "min", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_min_impl(self, other, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_min_mag__doc__, +"min_mag($self, /, other, context=None)\n" +"--\n" +"\n" +"Similar to the min() method, but the comparison is done using the absolute values of the operands."); + +#define _DECIMAL_DECIMAL_MIN_MAG_METHODDEF \ + {"min_mag", _PyCFunction_CAST(_decimal_Decimal_min_mag), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_min_mag__doc__}, + +static PyObject * +_decimal_Decimal_min_mag_impl(PyObject *self, PyObject *other, + PyObject *context); + +static PyObject * +_decimal_Decimal_min_mag(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "min_mag", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_min_mag_impl(self, other, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_next_toward__doc__, +"next_toward($self, /, other, context=None)\n" +"--\n" +"\n" +"Returns the number closest to self, in the direction towards other.\n" +"\n" +"If the two operands are unequal, return the number closest to the first\n" +"operand in the direction of the second operand. If both operands are\n" +"numerically equal, return a copy of the first operand with the sign set\n" +"to be the same as the sign of the second operand."); + +#define _DECIMAL_DECIMAL_NEXT_TOWARD_METHODDEF \ + {"next_toward", _PyCFunction_CAST(_decimal_Decimal_next_toward), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_toward__doc__}, + +static PyObject * +_decimal_Decimal_next_toward_impl(PyObject *self, PyObject *other, + PyObject *context); + +static PyObject * +_decimal_Decimal_next_toward(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "next_toward", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_next_toward_impl(self, other, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_remainder_near__doc__, +"remainder_near($self, /, other, context=None)\n" +"--\n" +"\n" +"Return the remainder from dividing self by other.\n" +"\n" +"This differs from self % other in that the sign of the remainder is chosen so\n" +"as to minimize its absolute value. More precisely, the return value is self -\n" +"n * other where n is the integer nearest to the exact value of self / other,\n" +"and if two integers are equally near then the even one is chosen.\n" +"\n" +"If the result is zero then its sign will be the sign of self."); + +#define _DECIMAL_DECIMAL_REMAINDER_NEAR_METHODDEF \ + {"remainder_near", _PyCFunction_CAST(_decimal_Decimal_remainder_near), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_remainder_near__doc__}, + +static PyObject * +_decimal_Decimal_remainder_near_impl(PyObject *self, PyObject *other, + PyObject *context); + +static PyObject * +_decimal_Decimal_remainder_near(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "remainder_near", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_remainder_near_impl(self, other, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_adjusted__doc__, +"adjusted($self, /)\n" +"--\n" +"\n" +"Return the adjusted exponent of the number. Defined as exp + digits - 1."); + +#define _DECIMAL_DECIMAL_ADJUSTED_METHODDEF \ + {"adjusted", (PyCFunction)_decimal_Decimal_adjusted, METH_NOARGS, _decimal_Decimal_adjusted__doc__}, + +static PyObject * +_decimal_Decimal_adjusted_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_adjusted(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_adjusted_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_canonical__doc__, +"canonical($self, /)\n" +"--\n" +"\n" +"Return the canonical encoding of the argument.\n" +"\n" +"Currently, the encoding of a Decimal instance is always canonical, so this\n" +"operation returns its argument unchanged."); + +#define _DECIMAL_DECIMAL_CANONICAL_METHODDEF \ + {"canonical", (PyCFunction)_decimal_Decimal_canonical, METH_NOARGS, _decimal_Decimal_canonical__doc__}, + +static PyObject * +_decimal_Decimal_canonical_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_canonical(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_canonical_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_conjugate__doc__, +"conjugate($self, /)\n" +"--\n" +"\n" +"Return self."); + +#define _DECIMAL_DECIMAL_CONJUGATE_METHODDEF \ + {"conjugate", (PyCFunction)_decimal_Decimal_conjugate, METH_NOARGS, _decimal_Decimal_conjugate__doc__}, + +static PyObject * +_decimal_Decimal_conjugate_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_conjugate(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_conjugate_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_radix__doc__, +"radix($self, /)\n" +"--\n" +"\n" +"Return Decimal(10).\n" +"\n" +"This is the radix (base) in which the Decimal class does\n" +"all its arithmetic. Included for compatibility with the specification."); + +#define _DECIMAL_DECIMAL_RADIX_METHODDEF \ + {"radix", (PyCFunction)_decimal_Decimal_radix, METH_NOARGS, _decimal_Decimal_radix__doc__}, + +static PyObject * +_decimal_Decimal_radix_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_radix(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_radix_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_copy_abs__doc__, +"copy_abs($self, /)\n" +"--\n" +"\n" +"Return the absolute value of the argument.\n" +"\n" +"This operation is unaffected by context and is quiet: no flags are changed and\n" +"no rounding is performed."); + +#define _DECIMAL_DECIMAL_COPY_ABS_METHODDEF \ + {"copy_abs", (PyCFunction)_decimal_Decimal_copy_abs, METH_NOARGS, _decimal_Decimal_copy_abs__doc__}, + +static PyObject * +_decimal_Decimal_copy_abs_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_copy_abs(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_copy_abs_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_copy_negate__doc__, +"copy_negate($self, /)\n" +"--\n" +"\n" +"Return the negation of the argument.\n" +"\n" +"This operation is unaffected by context and is quiet: no flags are changed and\n" +"no rounding is performed."); + +#define _DECIMAL_DECIMAL_COPY_NEGATE_METHODDEF \ + {"copy_negate", (PyCFunction)_decimal_Decimal_copy_negate, METH_NOARGS, _decimal_Decimal_copy_negate__doc__}, + +static PyObject * +_decimal_Decimal_copy_negate_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_copy_negate(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_copy_negate_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_logical_invert__doc__, +"logical_invert($self, /, context=None)\n" +"--\n" +"\n" +"Return the digit-wise inversion of the (logical) operand."); + +#define _DECIMAL_DECIMAL_LOGICAL_INVERT_METHODDEF \ + {"logical_invert", _PyCFunction_CAST(_decimal_Decimal_logical_invert), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_invert__doc__}, + +static PyObject * +_decimal_Decimal_logical_invert_impl(PyObject *self, PyObject *context); + +static PyObject * +_decimal_Decimal_logical_invert(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "logical_invert", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_logical_invert_impl(self, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_logb__doc__, +"logb($self, /, context=None)\n" +"--\n" +"\n" +"Return the adjusted exponent of the operand as a Decimal instance.\n" +"\n" +"If the operand is a zero, then Decimal(\'-Infinity\') is returned and the\n" +"DivisionByZero condition is raised. If the operand is an infinity then\n" +"Decimal(\'Infinity\') is returned."); + +#define _DECIMAL_DECIMAL_LOGB_METHODDEF \ + {"logb", _PyCFunction_CAST(_decimal_Decimal_logb), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logb__doc__}, + +static PyObject * +_decimal_Decimal_logb_impl(PyObject *self, PyObject *context); + +static PyObject * +_decimal_Decimal_logb(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "logb", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_logb_impl(self, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_number_class__doc__, +"number_class($self, /, context=None)\n" +"--\n" +"\n" +"Return a string describing the class of the operand.\n" +"\n" +"The returned value is one of the following ten strings:\n" +"\n" +" * \'-Infinity\', indicating that the operand is negative infinity.\n" +" * \'-Normal\', indicating that the operand is a negative normal number.\n" +" * \'-Subnormal\', indicating that the operand is negative and subnormal.\n" +" * \'-Zero\', indicating that the operand is a negative zero.\n" +" * \'+Zero\', indicating that the operand is a positive zero.\n" +" * \'+Subnormal\', indicating that the operand is positive and subnormal.\n" +" * \'+Normal\', indicating that the operand is a positive normal number.\n" +" * \'+Infinity\', indicating that the operand is positive infinity.\n" +" * \'NaN\', indicating that the operand is a quiet NaN (Not a Number).\n" +" * \'sNaN\', indicating that the operand is a signaling NaN."); + +#define _DECIMAL_DECIMAL_NUMBER_CLASS_METHODDEF \ + {"number_class", _PyCFunction_CAST(_decimal_Decimal_number_class), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_number_class__doc__}, + +static PyObject * +_decimal_Decimal_number_class_impl(PyObject *self, PyObject *context); + +static PyObject * +_decimal_Decimal_number_class(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "number_class", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_number_class_impl(self, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_to_eng_string__doc__, +"to_eng_string($self, /, context=None)\n" +"--\n" +"\n" +"Convert to an engineering-type string.\n" +"\n" +"Engineering notation has an exponent which is a multiple of 3, so there are up\n" +"to 3 digits left of the decimal place. For example, Decimal(\'123E+1\') is\n" +"converted to Decimal(\'1.23E+3\').\n" +"\n" +"The value of context.capitals determines whether the exponent sign is lower\n" +"or upper case. Otherwise, the context does not affect the operation."); + +#define _DECIMAL_DECIMAL_TO_ENG_STRING_METHODDEF \ + {"to_eng_string", _PyCFunction_CAST(_decimal_Decimal_to_eng_string), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_eng_string__doc__}, + +static PyObject * +_decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context); + +static PyObject * +_decimal_Decimal_to_eng_string(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "to_eng_string", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + context = args[0]; +skip_optional_pos: + return_value = _decimal_Decimal_to_eng_string_impl(self, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_compare_total__doc__, +"compare_total($self, /, other, context=None)\n" +"--\n" +"\n" +"Compare two operands using their abstract representation rather than their numerical value.\n" +"\n" +"Similar to the compare() method, but the result\n" +"gives a total ordering on Decimal instances. Two Decimal instances with\n" +"the same numeric value but different representations compare unequal\n" +"in this ordering:\n" +"\n" +" >>> Decimal(\'12.0\').compare_total(Decimal(\'12\'))\n" +" Decimal(\'-1\')\n" +"\n" +"Quiet and signaling NaNs are also included in the total ordering. The result\n" +"of this function is Decimal(\'0\') if both operands have the same representation,\n" +"Decimal(\'-1\') if the first operand is lower in the total order than the second,\n" +"and Decimal(\'1\') if the first operand is higher in the total order than the\n" +"second operand. See the specification for details of the total order.\n" +"\n" +"This operation is unaffected by context and is quiet: no flags are changed\n" +"and no rounding is performed. As an exception, the C version may raise\n" +"InvalidOperation if the second operand cannot be converted exactly."); + +#define _DECIMAL_DECIMAL_COMPARE_TOTAL_METHODDEF \ + {"compare_total", _PyCFunction_CAST(_decimal_Decimal_compare_total), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_total__doc__}, + +static PyObject * +_decimal_Decimal_compare_total_impl(PyObject *self, PyObject *other, + PyObject *context); + +static PyObject * +_decimal_Decimal_compare_total(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "compare_total", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_compare_total_impl(self, other, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_compare_total_mag__doc__, +"compare_total_mag($self, /, other, context=None)\n" +"--\n" +"\n" +"Compare two operands using their abstract representation rather than their value as in compare_total(), but ignoring the sign of each operand.\n" +"\n" +"x.compare_total_mag(y) is equivalent to x.copy_abs().compare_total(y.copy_abs()).\n" +"\n" +"This operation is unaffected by context and is quiet: no flags are changed\n" +"and no rounding is performed. As an exception, the C version may raise\n" +"InvalidOperation if the second operand cannot be converted exactly."); + +#define _DECIMAL_DECIMAL_COMPARE_TOTAL_MAG_METHODDEF \ + {"compare_total_mag", _PyCFunction_CAST(_decimal_Decimal_compare_total_mag), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_total_mag__doc__}, + +static PyObject * +_decimal_Decimal_compare_total_mag_impl(PyObject *self, PyObject *other, + PyObject *context); + +static PyObject * +_decimal_Decimal_compare_total_mag(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "compare_total_mag", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_compare_total_mag_impl(self, other, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_copy_sign__doc__, +"copy_sign($self, /, other, context=None)\n" +"--\n" +"\n" +"Return a copy of *self* with the sign set to be the same as the sign of *other*.\n" +"\n" +"For example:\n" +"\n" +" >>> Decimal(\'2.3\').copy_sign(Decimal(\'-1.5\'))\n" +" Decimal(\'-2.3\')\n" +"\n" +"This operation is unaffected by context and is quiet: no flags are changed\n" +"and no rounding is performed. As an exception, the C version may raise\n" +"InvalidOperation if the second operand cannot be converted exactly."); + +#define _DECIMAL_DECIMAL_COPY_SIGN_METHODDEF \ + {"copy_sign", _PyCFunction_CAST(_decimal_Decimal_copy_sign), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_copy_sign__doc__}, + +static PyObject * +_decimal_Decimal_copy_sign_impl(PyObject *self, PyObject *other, + PyObject *context); + +static PyObject * +_decimal_Decimal_copy_sign(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "copy_sign", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_copy_sign_impl(self, other, context); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Decimal_same_quantum__doc__, +"same_quantum($self, /, other, context=None)\n" +"--\n" +"\n" +"Test whether self and other have the same exponent or whether both are NaN.\n" +"\n" +"This operation is unaffected by context and is quiet: no flags are changed\n" +"and no rounding is performed. As an exception, the C version may raise\n" +"InvalidOperation if the second operand cannot be converted exactly."); + +#define _DECIMAL_DECIMAL_SAME_QUANTUM_METHODDEF \ + {"same_quantum", _PyCFunction_CAST(_decimal_Decimal_same_quantum), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_same_quantum__doc__}, + +static PyObject * +_decimal_Decimal_same_quantum_impl(PyObject *self, PyObject *other, + PyObject *context); + +static PyObject * +_decimal_Decimal_same_quantum(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "same_quantum", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_same_quantum_impl(self, other, context); -static PyObject * -_decimal_Decimal_canonical(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _decimal_Decimal_canonical_impl(self); +exit: + return return_value; } -PyDoc_STRVAR(_decimal_Decimal_conjugate__doc__, -"conjugate($self, /)\n" +PyDoc_STRVAR(_decimal_Decimal_logical_and__doc__, +"logical_and($self, /, other, context=None)\n" "--\n" "\n" -"Return self."); +"Return the digit-wise \'and\' of the two (logical) operands."); -#define _DECIMAL_DECIMAL_CONJUGATE_METHODDEF \ - {"conjugate", (PyCFunction)_decimal_Decimal_conjugate, METH_NOARGS, _decimal_Decimal_conjugate__doc__}, +#define _DECIMAL_DECIMAL_LOGICAL_AND_METHODDEF \ + {"logical_and", _PyCFunction_CAST(_decimal_Decimal_logical_and), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_and__doc__}, static PyObject * -_decimal_Decimal_conjugate_impl(PyObject *self); +_decimal_Decimal_logical_and_impl(PyObject *self, PyObject *other, + PyObject *context); static PyObject * -_decimal_Decimal_conjugate(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal_logical_and(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Decimal_conjugate_impl(self); -} + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -PyDoc_STRVAR(_decimal_Decimal_radix__doc__, -"radix($self, /)\n" -"--\n" -"\n" -"Return Decimal(10).\n" -"\n" -"This is the radix (base) in which the Decimal class does\n" -"all its arithmetic. Included for compatibility with the specification."); + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) -#define _DECIMAL_DECIMAL_RADIX_METHODDEF \ - {"radix", (PyCFunction)_decimal_Decimal_radix, METH_NOARGS, _decimal_Decimal_radix__doc__}, + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE -static PyObject * -_decimal_Decimal_radix_impl(PyObject *self); + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "logical_and", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; -static PyObject * -_decimal_Decimal_radix(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _decimal_Decimal_radix_impl(self); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_logical_and_impl(self, other, context); + +exit: + return return_value; } -PyDoc_STRVAR(_decimal_Decimal_copy_abs__doc__, -"copy_abs($self, /)\n" +PyDoc_STRVAR(_decimal_Decimal_logical_or__doc__, +"logical_or($self, /, other, context=None)\n" "--\n" "\n" -"Return the absolute value of the argument.\n" -"\n" -"This operation is unaffected by context and is quiet: no flags are changed and\n" -"no rounding is performed."); +"Return the digit-wise \'or\' of the two (logical) operands."); -#define _DECIMAL_DECIMAL_COPY_ABS_METHODDEF \ - {"copy_abs", (PyCFunction)_decimal_Decimal_copy_abs, METH_NOARGS, _decimal_Decimal_copy_abs__doc__}, +#define _DECIMAL_DECIMAL_LOGICAL_OR_METHODDEF \ + {"logical_or", _PyCFunction_CAST(_decimal_Decimal_logical_or), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_or__doc__}, static PyObject * -_decimal_Decimal_copy_abs_impl(PyObject *self); +_decimal_Decimal_logical_or_impl(PyObject *self, PyObject *other, + PyObject *context); static PyObject * -_decimal_Decimal_copy_abs(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal_logical_or(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Decimal_copy_abs_impl(self); -} + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -PyDoc_STRVAR(_decimal_Decimal_copy_negate__doc__, -"copy_negate($self, /)\n" -"--\n" -"\n" -"Return the negation of the argument.\n" -"\n" -"This operation is unaffected by context and is quiet: no flags are changed and\n" -"no rounding is performed."); + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) -#define _DECIMAL_DECIMAL_COPY_NEGATE_METHODDEF \ - {"copy_negate", (PyCFunction)_decimal_Decimal_copy_negate, METH_NOARGS, _decimal_Decimal_copy_negate__doc__}, + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE -static PyObject * -_decimal_Decimal_copy_negate_impl(PyObject *self); + static const char * const _keywords[] = {"other", "context", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "logical_or", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; + PyObject *context = Py_None; -static PyObject * -_decimal_Decimal_copy_negate(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _decimal_Decimal_copy_negate_impl(self); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + other = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + context = args[1]; +skip_optional_pos: + return_value = _decimal_Decimal_logical_or_impl(self, other, context); + +exit: + return return_value; } -PyDoc_STRVAR(_decimal_Decimal_number_class__doc__, -"number_class($self, /, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_logical_xor__doc__, +"logical_xor($self, /, other, context=None)\n" "--\n" "\n" -"Return a string describing the class of the operand.\n" -"\n" -"The returned value is one of the following ten strings:\n" -"\n" -" * \'-Infinity\', indicating that the operand is negative infinity.\n" -" * \'-Normal\', indicating that the operand is a negative normal number.\n" -" * \'-Subnormal\', indicating that the operand is negative and subnormal.\n" -" * \'-Zero\', indicating that the operand is a negative zero.\n" -" * \'+Zero\', indicating that the operand is a positive zero.\n" -" * \'+Subnormal\', indicating that the operand is positive and subnormal.\n" -" * \'+Normal\', indicating that the operand is a positive normal number.\n" -" * \'+Infinity\', indicating that the operand is positive infinity.\n" -" * \'NaN\', indicating that the operand is a quiet NaN (Not a Number).\n" -" * \'sNaN\', indicating that the operand is a signaling NaN."); +"Return the digit-wise \'xor\' of the two (logical) operands."); -#define _DECIMAL_DECIMAL_NUMBER_CLASS_METHODDEF \ - {"number_class", _PyCFunction_CAST(_decimal_Decimal_number_class), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_number_class__doc__}, +#define _DECIMAL_DECIMAL_LOGICAL_XOR_METHODDEF \ + {"logical_xor", _PyCFunction_CAST(_decimal_Decimal_logical_xor), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_xor__doc__}, static PyObject * -_decimal_Decimal_number_class_impl(PyObject *self, PyObject *context); +_decimal_Decimal_logical_xor_impl(PyObject *self, PyObject *other, + PyObject *context); static PyObject * -_decimal_Decimal_number_class(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_logical_xor(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 1 + #define NUM_KEYWORDS 2 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD @@ -419,7 +2198,7 @@ _decimal_Decimal_number_class(PyObject *self, PyObject *const *args, Py_ssize_t } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -428,59 +2207,62 @@ _decimal_Decimal_number_class(PyObject *self, PyObject *const *args, Py_ssize_t # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"context", NULL}; + static const char * const _keywords[] = {"other", "context", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "number_class", + .fname = "logical_xor", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; PyObject *context = Py_None; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } + other = args[0]; if (!noptargs) { goto skip_optional_pos; } - context = args[0]; + context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_number_class_impl(self, context); + return_value = _decimal_Decimal_logical_xor_impl(self, other, context); exit: return return_value; } -PyDoc_STRVAR(_decimal_Decimal_to_eng_string__doc__, -"to_eng_string($self, /, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_rotate__doc__, +"rotate($self, /, other, context=None)\n" "--\n" "\n" -"Convert to an engineering-type string.\n" -"\n" -"Engineering notation has an exponent which is a multiple of 3, so there are up\n" -"to 3 digits left of the decimal place. For example, Decimal(\'123E+1\') is\n" -"converted to Decimal(\'1.23E+3\').\n" +"Return the result of rotating the digits of the first operand by an amount specified by the second operand.\n" "\n" -"The value of context.capitals determines whether the exponent sign is lower\n" -"or upper case. Otherwise, the context does not affect the operation."); +"The second operand must be an integer in the range -precision through\n" +"precision. The absolute value of the second operand gives the number of places\n" +"to rotate. If the second operand is positive then rotation is to the left;\n" +"otherwise rotation is to the right. The coefficient of the first operand is\n" +"padded on the left with zeros to length precision if necessary. The sign and\n" +"exponent of the first operand are unchanged."); -#define _DECIMAL_DECIMAL_TO_ENG_STRING_METHODDEF \ - {"to_eng_string", _PyCFunction_CAST(_decimal_Decimal_to_eng_string), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_eng_string__doc__}, +#define _DECIMAL_DECIMAL_ROTATE_METHODDEF \ + {"rotate", _PyCFunction_CAST(_decimal_Decimal_rotate), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_rotate__doc__}, static PyObject * -_decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context); +_decimal_Decimal_rotate_impl(PyObject *self, PyObject *other, + PyObject *context); static PyObject * -_decimal_Decimal_to_eng_string(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_rotate(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 1 + #define NUM_KEYWORDS 2 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD @@ -489,7 +2271,7 @@ _decimal_Decimal_to_eng_string(PyObject *self, PyObject *const *args, Py_ssize_t } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, + .ob_item = { &_Py_ID(other), &_Py_ID(context), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -498,57 +2280,53 @@ _decimal_Decimal_to_eng_string(PyObject *self, PyObject *const *args, Py_ssize_t # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"context", NULL}; + static const char * const _keywords[] = {"other", "context", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "to_eng_string", + .fname = "rotate", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *other; PyObject *context = Py_None; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } + other = args[0]; if (!noptargs) { goto skip_optional_pos; } - context = args[0]; + context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_to_eng_string_impl(self, context); + return_value = _decimal_Decimal_rotate_impl(self, other, context); exit: return return_value; } -PyDoc_STRVAR(_decimal_Decimal_copy_sign__doc__, -"copy_sign($self, /, other, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_scaleb__doc__, +"scaleb($self, /, other, context=None)\n" "--\n" "\n" -"Return a copy of *self* with the sign set to be the same as the sign of *other*.\n" -"\n" -"For example:\n" -"\n" -" >>> Decimal(\'2.3\').copy_sign(Decimal(\'-1.5\'))\n" -" Decimal(\'-2.3\')\n" +"Return the first operand with the exponent adjusted the second.\n" "\n" -"This operation is unaffected by context and is quiet: no flags are changed\n" -"and no rounding is performed. As an exception, the C version may raise\n" -"InvalidOperation if the second operand cannot be converted exactly."); +"Equivalently, return the first operand multiplied by 10**other. The second\n" +"operand must be an integer."); -#define _DECIMAL_DECIMAL_COPY_SIGN_METHODDEF \ - {"copy_sign", _PyCFunction_CAST(_decimal_Decimal_copy_sign), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_copy_sign__doc__}, +#define _DECIMAL_DECIMAL_SCALEB_METHODDEF \ + {"scaleb", _PyCFunction_CAST(_decimal_Decimal_scaleb), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_scaleb__doc__}, static PyObject * -_decimal_Decimal_copy_sign_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_scaleb_impl(PyObject *self, PyObject *other, + PyObject *context); static PyObject * -_decimal_Decimal_copy_sign(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_scaleb(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -574,7 +2352,7 @@ _decimal_Decimal_copy_sign(PyObject *self, PyObject *const *args, Py_ssize_t nar static const char * const _keywords[] = {"other", "context", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "copy_sign", + .fname = "scaleb", .kwtuple = KWTUPLE, }; #undef KWTUPLE @@ -594,31 +2372,33 @@ _decimal_Decimal_copy_sign(PyObject *self, PyObject *const *args, Py_ssize_t nar } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_copy_sign_impl(self, other, context); + return_value = _decimal_Decimal_scaleb_impl(self, other, context); exit: return return_value; } -PyDoc_STRVAR(_decimal_Decimal_same_quantum__doc__, -"same_quantum($self, /, other, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_shift__doc__, +"shift($self, /, other, context=None)\n" "--\n" "\n" -"Test whether self and other have the same exponent or whether both are NaN.\n" +"Return the result of shifting the digits of the first operand by an amount specified by the second operand.\n" "\n" -"This operation is unaffected by context and is quiet: no flags are changed\n" -"and no rounding is performed. As an exception, the C version may raise\n" -"InvalidOperation if the second operand cannot be converted exactly."); +"The second operand must be an integer in the range -precision through\n" +"precision. The absolute value of the second operand gives the number of places\n" +"to shift. If the second operand is positive, then the shift is to the left;\n" +"otherwise the shift is to the right. Digits shifted into the coefficient are\n" +"zeros. The sign and exponent of the first operand are unchanged."); -#define _DECIMAL_DECIMAL_SAME_QUANTUM_METHODDEF \ - {"same_quantum", _PyCFunction_CAST(_decimal_Decimal_same_quantum), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_same_quantum__doc__}, +#define _DECIMAL_DECIMAL_SHIFT_METHODDEF \ + {"shift", _PyCFunction_CAST(_decimal_Decimal_shift), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_shift__doc__}, static PyObject * -_decimal_Decimal_same_quantum_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_shift_impl(PyObject *self, PyObject *other, + PyObject *context); static PyObject * -_decimal_Decimal_same_quantum(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_shift(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -644,7 +2424,7 @@ _decimal_Decimal_same_quantum(PyObject *self, PyObject *const *args, Py_ssize_t static const char * const _keywords[] = {"other", "context", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "same_quantum", + .fname = "shift", .kwtuple = KWTUPLE, }; #undef KWTUPLE @@ -664,7 +2444,7 @@ _decimal_Decimal_same_quantum(PyObject *self, PyObject *const *args, Py_ssize_t } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_same_quantum_impl(self, other, context); + return_value = _decimal_Decimal_shift_impl(self, other, context); exit: return return_value; @@ -758,4 +2538,4 @@ _decimal_Decimal_quantize(PyObject *self, PyObject *const *args, Py_ssize_t narg exit: return return_value; } -/*[clinic end generated code: output=304ce135eee594cc input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2a88992a1081c36d input=a9049054013a1b77]*/ diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h index 95106e3c2f56ea..4c878559b1f4c4 100644 --- a/Modules/_decimal/docstrings.h +++ b/Modules/_decimal/docstrings.h @@ -57,21 +57,6 @@ context does not affect the conversion and is only passed to determine if\n\ the InvalidOperation trap is active.\n\ \n"); -PyDoc_STRVAR(doc_compare, -"compare($self, /, other, context=None)\n--\n\n\ -Compare self to other. Return a decimal value:\n\ -\n\ - a or b is a NaN ==> Decimal('NaN')\n\ - a < b ==> Decimal('-1')\n\ - a == b ==> Decimal('0')\n\ - a > b ==> Decimal('1')\n\ -\n"); - -PyDoc_STRVAR(doc_compare_signal, -"compare_signal($self, /, other, context=None)\n--\n\n\ -Identical to compare, except that all NaNs signal.\n\ -\n"); - PyDoc_STRVAR(doc_compare_total, "compare_total($self, /, other, context=None)\n--\n\n\ Compare two operands using their abstract representation rather than\n\ @@ -106,13 +91,6 @@ and no rounding is performed. As an exception, the C version may raise\n\ InvalidOperation if the second operand cannot be converted exactly.\n\ \n"); -PyDoc_STRVAR(doc_exp, -"exp($self, /, context=None)\n--\n\n\ -Return the value of the (natural) exponential function e**x at the given\n\ -number. The function always uses the ROUND_HALF_EVEN mode and the result\n\ -is correctly rounded.\n\ -\n"); - PyDoc_STRVAR(doc_fma, "fma($self, /, other, third, context=None)\n--\n\n\ Fused multiply-add. Return self*other+third with no rounding of the\n\ @@ -184,36 +162,11 @@ Return True if the argument is a (positive or negative) zero and False\n\ otherwise.\n\ \n"); -PyDoc_STRVAR(doc_ln, -"ln($self, /, context=None)\n--\n\n\ -Return the natural (base e) logarithm of the operand. The function always\n\ -uses the ROUND_HALF_EVEN mode and the result is correctly rounded.\n\ -\n"); - -PyDoc_STRVAR(doc_log10, -"log10($self, /, context=None)\n--\n\n\ -Return the base ten logarithm of the operand. The function always uses the\n\ -ROUND_HALF_EVEN mode and the result is correctly rounded.\n\ -\n"); - -PyDoc_STRVAR(doc_logb, -"logb($self, /, context=None)\n--\n\n\ -For a non-zero number, return the adjusted exponent of the operand as a\n\ -Decimal instance. If the operand is a zero, then Decimal('-Infinity') is\n\ -returned and the DivisionByZero condition is raised. If the operand is\n\ -an infinity then Decimal('Infinity') is returned.\n\ -\n"); - PyDoc_STRVAR(doc_logical_and, "logical_and($self, /, other, context=None)\n--\n\n\ Return the digit-wise 'and' of the two (logical) operands.\n\ \n"); -PyDoc_STRVAR(doc_logical_invert, -"logical_invert($self, /, context=None)\n--\n\n\ -Return the digit-wise inversion of the (logical) operand.\n\ -\n"); - PyDoc_STRVAR(doc_logical_or, "logical_or($self, /, other, context=None)\n--\n\n\ Return the digit-wise 'or' of the two (logical) operands.\n\ @@ -224,72 +177,6 @@ PyDoc_STRVAR(doc_logical_xor, Return the digit-wise 'exclusive or' of the two (logical) operands.\n\ \n"); -PyDoc_STRVAR(doc_max, -"max($self, /, other, context=None)\n--\n\n\ -Maximum of self and other. If one operand is a quiet NaN and the other is\n\ -numeric, the numeric operand is returned.\n\ -\n"); - -PyDoc_STRVAR(doc_max_mag, -"max_mag($self, /, other, context=None)\n--\n\n\ -Similar to the max() method, but the comparison is done using the absolute\n\ -values of the operands.\n\ -\n"); - -PyDoc_STRVAR(doc_min, -"min($self, /, other, context=None)\n--\n\n\ -Minimum of self and other. If one operand is a quiet NaN and the other is\n\ -numeric, the numeric operand is returned.\n\ -\n"); - -PyDoc_STRVAR(doc_min_mag, -"min_mag($self, /, other, context=None)\n--\n\n\ -Similar to the min() method, but the comparison is done using the absolute\n\ -values of the operands.\n\ -\n"); - -PyDoc_STRVAR(doc_next_minus, -"next_minus($self, /, context=None)\n--\n\n\ -Return the largest number representable in the given context (or in the\n\ -current default context if no context is given) that is smaller than the\n\ -given operand.\n\ -\n"); - -PyDoc_STRVAR(doc_next_plus, -"next_plus($self, /, context=None)\n--\n\n\ -Return the smallest number representable in the given context (or in the\n\ -current default context if no context is given) that is larger than the\n\ -given operand.\n\ -\n"); - -PyDoc_STRVAR(doc_next_toward, -"next_toward($self, /, other, context=None)\n--\n\n\ -If the two operands are unequal, return the number closest to the first\n\ -operand in the direction of the second operand. If both operands are\n\ -numerically equal, return a copy of the first operand with the sign set\n\ -to be the same as the sign of the second operand.\n\ -\n"); - -PyDoc_STRVAR(doc_normalize, -"normalize($self, /, context=None)\n--\n\n\ -Normalize the number by stripping the rightmost trailing zeros and\n\ -converting any result equal to Decimal('0') to Decimal('0e0'). Used\n\ -for producing canonical values for members of an equivalence class.\n\ -For example, Decimal('32.100') and Decimal('0.321000e+2') both normalize\n\ -to the equivalent value Decimal('32.1').\n\ -\n"); - -PyDoc_STRVAR(doc_remainder_near, -"remainder_near($self, /, other, context=None)\n--\n\n\ -Return the remainder from dividing self by other. This differs from\n\ -self % other in that the sign of the remainder is chosen so as to minimize\n\ -its absolute value. More precisely, the return value is self - n * other\n\ -where n is the integer nearest to the exact value of self / other, and\n\ -if two integers are equally near then the even one is chosen.\n\ -\n\ -If the result is zero then its sign will be the sign of self.\n\ -\n"); - PyDoc_STRVAR(doc_rotate, "rotate($self, /, other, context=None)\n--\n\n\ Return the result of rotating the digits of the first operand by an amount\n\ @@ -320,20 +207,6 @@ right. Digits shifted into the coefficient are zeros. The sign and exponent\n\ of the first operand are unchanged.\n\ \n"); -PyDoc_STRVAR(doc_sqrt, -"sqrt($self, /, context=None)\n--\n\n\ -Return the square root of the argument to full precision. The result is\n\ -correctly rounded using the ROUND_HALF_EVEN rounding mode.\n\ -\n"); - -PyDoc_STRVAR(doc_to_integral_value, -"to_integral_value($self, /, rounding=None, context=None)\n--\n\n\ -Round to the nearest integer without signaling Inexact or Rounded. The\n\ -rounding mode is determined by the rounding parameter if given, else by\n\ -the given context. If neither parameter is given, then the rounding mode\n\ -of the current default context is used.\n\ -\n"); - /******************************************************************************/ /* Context Object and Methods */ From d78a97f26de76ab6797760d1ca1acb4b3bb7c54a Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 11 Aug 2025 04:54:38 +0300 Subject: [PATCH 07/16] address review: move to_integral_value around --- Modules/_decimal/_decimal.c | 54 ++++++++++---------- Modules/_decimal/clinic/_decimal.c.h | 76 ++++++++++++++-------------- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 15670a1e5d582f..9e6c4cb302b5e8 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -3919,20 +3919,22 @@ _decimal_Decimal_as_integer_ratio_impl(PyObject *self) } /*[clinic input] -_decimal.Decimal.to_integral +_decimal.Decimal.to_integral_value rounding: object = None context: object = None -Identical to the to_integral_value() method. +Round to the nearest integer without signaling Inexact or Rounded. -The to_integral() name has been kept for compatibility with older versions. +The rounding mode is determined by the rounding parameter if given, else by +the given context. If neither parameter is given, then the rounding mode of +the current default context is used. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_to_integral_impl(PyObject *self, PyObject *rounding, - PyObject *context) -/*[clinic end generated code: output=a0c7188686ee7f5c input=a57d62d1d29aed1b]*/ +_decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, + PyObject *context) +/*[clinic end generated code: output=7301465765f48b6b input=5778168222cadf71]*/ { PyObject *result; uint32_t status = 0; @@ -3966,6 +3968,25 @@ _decimal_Decimal_to_integral_impl(PyObject *self, PyObject *rounding, return result; } +/*[clinic input] +_decimal.Decimal.to_integral + + rounding: object = None + context: object = None + +Identical to the to_integral_value() method. + +The to_integral() name has been kept for compatibility with older versions. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_to_integral_impl(PyObject *self, PyObject *rounding, + PyObject *context) +/*[clinic end generated code: output=a0c7188686ee7f5c input=a57d62d1d29aed1b]*/ +{ + return _decimal_Decimal_to_integral_value_impl(self, rounding, context); +} + /*[clinic input] _decimal.Decimal.to_integral_exact @@ -4017,27 +4038,6 @@ _decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, return result; } -/*[clinic input] -_decimal.Decimal.to_integral_value - - rounding: object = None - context: object = None - -Round to the nearest integer without signaling Inexact or Rounded. - -The rounding mode is determined by the rounding parameter if given, else by -the given context. If neither parameter is given, then the rounding mode of -the current default context is used. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, - PyObject *context) -/*[clinic end generated code: output=7301465765f48b6b input=5778168222cadf71]*/ -{ - return _decimal_Decimal_to_integral_impl(self, rounding, context); -} - static PyObject * PyDec_AsFloat(PyObject *dec) { diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index 8ac46dea2a0384..e4c4805e1408b0 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -92,23 +92,25 @@ _decimal_Decimal_as_integer_ratio(PyObject *self, PyObject *Py_UNUSED(ignored)) return _decimal_Decimal_as_integer_ratio_impl(self); } -PyDoc_STRVAR(_decimal_Decimal_to_integral__doc__, -"to_integral($self, /, rounding=None, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_to_integral_value__doc__, +"to_integral_value($self, /, rounding=None, context=None)\n" "--\n" "\n" -"Identical to the to_integral_value() method.\n" +"Round to the nearest integer without signaling Inexact or Rounded.\n" "\n" -"The to_integral() name has been kept for compatibility with older versions."); +"The rounding mode is determined by the rounding parameter if given, else by\n" +"the given context. If neither parameter is given, then the rounding mode of\n" +"the current default context is used."); -#define _DECIMAL_DECIMAL_TO_INTEGRAL_METHODDEF \ - {"to_integral", _PyCFunction_CAST(_decimal_Decimal_to_integral), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral__doc__}, +#define _DECIMAL_DECIMAL_TO_INTEGRAL_VALUE_METHODDEF \ + {"to_integral_value", _PyCFunction_CAST(_decimal_Decimal_to_integral_value), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_value__doc__}, static PyObject * -_decimal_Decimal_to_integral_impl(PyObject *self, PyObject *rounding, - PyObject *context); +_decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, + PyObject *context); static PyObject * -_decimal_Decimal_to_integral(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_to_integral_value(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -134,7 +136,7 @@ _decimal_Decimal_to_integral(PyObject *self, PyObject *const *args, Py_ssize_t n static const char * const _keywords[] = {"rounding", "context", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "to_integral", + .fname = "to_integral_value", .kwtuple = KWTUPLE, }; #undef KWTUPLE @@ -159,32 +161,29 @@ _decimal_Decimal_to_integral(PyObject *self, PyObject *const *args, Py_ssize_t n } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_to_integral_impl(self, rounding, context); + return_value = _decimal_Decimal_to_integral_value_impl(self, rounding, context); exit: return return_value; } -PyDoc_STRVAR(_decimal_Decimal_to_integral_exact__doc__, -"to_integral_exact($self, /, rounding=None, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_to_integral__doc__, +"to_integral($self, /, rounding=None, context=None)\n" "--\n" "\n" -"Round to the nearest integer.\n" +"Identical to the to_integral_value() method.\n" "\n" -"Decimal.to_integral_exact() signals Inexact or Rounded as appropriate if\n" -"rounding occurs. The rounding mode is determined by the rounding parameter\n" -"if given, else by the given context. If neither parameter is given, then the\n" -"rounding mode of the current default context is used."); +"The to_integral() name has been kept for compatibility with older versions."); -#define _DECIMAL_DECIMAL_TO_INTEGRAL_EXACT_METHODDEF \ - {"to_integral_exact", _PyCFunction_CAST(_decimal_Decimal_to_integral_exact), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_exact__doc__}, +#define _DECIMAL_DECIMAL_TO_INTEGRAL_METHODDEF \ + {"to_integral", _PyCFunction_CAST(_decimal_Decimal_to_integral), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral__doc__}, static PyObject * -_decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, - PyObject *context); +_decimal_Decimal_to_integral_impl(PyObject *self, PyObject *rounding, + PyObject *context); static PyObject * -_decimal_Decimal_to_integral_exact(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_to_integral(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -210,7 +209,7 @@ _decimal_Decimal_to_integral_exact(PyObject *self, PyObject *const *args, Py_ssi static const char * const _keywords[] = {"rounding", "context", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "to_integral_exact", + .fname = "to_integral", .kwtuple = KWTUPLE, }; #undef KWTUPLE @@ -235,31 +234,32 @@ _decimal_Decimal_to_integral_exact(PyObject *self, PyObject *const *args, Py_ssi } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_to_integral_exact_impl(self, rounding, context); + return_value = _decimal_Decimal_to_integral_impl(self, rounding, context); exit: return return_value; } -PyDoc_STRVAR(_decimal_Decimal_to_integral_value__doc__, -"to_integral_value($self, /, rounding=None, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_to_integral_exact__doc__, +"to_integral_exact($self, /, rounding=None, context=None)\n" "--\n" "\n" -"Round to the nearest integer without signaling Inexact or Rounded.\n" +"Round to the nearest integer.\n" "\n" -"The rounding mode is determined by the rounding parameter if given, else by\n" -"the given context. If neither parameter is given, then the rounding mode of\n" -"the current default context is used."); +"Decimal.to_integral_exact() signals Inexact or Rounded as appropriate if\n" +"rounding occurs. The rounding mode is determined by the rounding parameter\n" +"if given, else by the given context. If neither parameter is given, then the\n" +"rounding mode of the current default context is used."); -#define _DECIMAL_DECIMAL_TO_INTEGRAL_VALUE_METHODDEF \ - {"to_integral_value", _PyCFunction_CAST(_decimal_Decimal_to_integral_value), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_value__doc__}, +#define _DECIMAL_DECIMAL_TO_INTEGRAL_EXACT_METHODDEF \ + {"to_integral_exact", _PyCFunction_CAST(_decimal_Decimal_to_integral_exact), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_exact__doc__}, static PyObject * -_decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, +_decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, PyObject *context); static PyObject * -_decimal_Decimal_to_integral_value(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_to_integral_exact(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -285,7 +285,7 @@ _decimal_Decimal_to_integral_value(PyObject *self, PyObject *const *args, Py_ssi static const char * const _keywords[] = {"rounding", "context", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "to_integral_value", + .fname = "to_integral_exact", .kwtuple = KWTUPLE, }; #undef KWTUPLE @@ -310,7 +310,7 @@ _decimal_Decimal_to_integral_value(PyObject *self, PyObject *const *args, Py_ssi } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_to_integral_value_impl(self, rounding, context); + return_value = _decimal_Decimal_to_integral_exact_impl(self, rounding, context); exit: return return_value; @@ -2538,4 +2538,4 @@ _decimal_Decimal_quantize(PyObject *self, PyObject *const *args, Py_ssize_t narg exit: return return_value; } -/*[clinic end generated code: output=2a88992a1081c36d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a72c95123d7107e1 input=a9049054013a1b77]*/ From 81cba5948b0105adfcfc07766bf9ddfd5d93341e Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 11 Aug 2025 05:06:56 +0300 Subject: [PATCH 08/16] Revert "+1" This reverts commit 354d8dbdb5255e926a8970823b94c0b5f2233f21. --- Modules/_decimal/_decimal.c | 572 +------- Modules/_decimal/clinic/_decimal.c.h | 2027 ++------------------------ Modules/_decimal/docstrings.h | 127 ++ 3 files changed, 339 insertions(+), 2387 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 9e6c4cb302b5e8..c48d712db4aed2 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -4310,10 +4310,17 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ /* Unary function with an optional context arg. */ #define Dec_UnaryFuncVA(MPDFUNC) \ static PyObject * \ -dec_##MPDFUNC(PyObject *self, PyObject *context) \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ { \ + static char *kwlist[] = {"context", NULL}; \ PyObject *result; \ + PyObject *context = Py_None; \ uint32_t status = 0; \ + \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \ + &context)) { \ + return NULL; \ + } \ decimal_state *state = \ get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ @@ -4334,11 +4341,19 @@ dec_##MPDFUNC(PyObject *self, PyObject *context) \ /* Binary function with an optional context arg. */ #define Dec_BinaryFuncVA(MPDFUNC) \ static PyObject * \ -dec_##MPDFUNC(PyObject *self, PyObject *other, PyObject *context)\ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ { \ + static char *kwlist[] = {"other", "context", NULL}; \ + PyObject *other; \ PyObject *a, *b; \ PyObject *result; \ + PyObject *context = Py_None; \ uint32_t status = 0; \ + \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \ + &other, &context)) { \ + return NULL; \ + } \ decimal_state *state = \ get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ @@ -4366,10 +4381,18 @@ dec_##MPDFUNC(PyObject *self, PyObject *other, PyObject *context)\ if the second operand cannot be converted exactly. */ #define Dec_BinaryFuncVA_NO_CTX(MPDFUNC) \ static PyObject * \ -dec_##MPDFUNC(PyObject *self, PyObject *other, PyObject *context)\ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ { \ + static char *kwlist[] = {"other", "context", NULL}; \ + PyObject *context = Py_None; \ + PyObject *other; \ PyObject *a, *b; \ PyObject *result; \ + \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \ + &other, &context)) { \ + return NULL; \ + } \ decimal_state *state = \ get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ @@ -4561,127 +4584,6 @@ Dec_UnaryFuncVA(mpd_qnext_plus) Dec_UnaryFuncVA(mpd_qreduce) Dec_UnaryFuncVA(mpd_qsqrt) -/*[clinic input] -_decimal.Decimal.exp - - context: object = None - -Return the value of the (natural) exponential function e**x at the given number. - -The function always uses the ROUND_HALF_EVEN mode and the result is correctly -rounded. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_exp_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=c0833b6e9b8c836f input=8d6adbec7d01dc04]*/ -{ - return dec_mpd_qexp(self, context); -} - -/*[clinic input] -_decimal.Decimal.ln - - context: object = None - -Return the natural (base e) logarithm of the operand. - -The function always uses the ROUND_HALF_EVEN mode and the result is correctly -rounded. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_ln_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=5191f4ef739b04b0 input=d5c1e0cd49764ccf]*/ -{ - return dec_mpd_qln(self, context); -} - -/*[clinic input] -_decimal.Decimal.log10 - - context: object = None - -Return the base ten logarithm of the operand. - -The function always uses the ROUND_HALF_EVEN mode and the result is correctly -rounded. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_log10_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=d5da63df75900275 input=b46068288e21d403]*/ -{ - return dec_mpd_qlog10(self, context); -} - -/*[clinic input] -_decimal.Decimal.next_minus - - context: object = None - -Returns the largest representable number smaller than itself. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_next_minus_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=aacbd758399f883f input=75666c6dc3cc8da9]*/ -{ - return dec_mpd_qnext_minus(self, context); -} - -/*[clinic input] -_decimal.Decimal.next_plus - - context: object = None - -Returns the smallest representable number larger than itself. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_next_plus_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=f3a7029a213c553c input=adcccf3f94e8da3f]*/ -{ - return dec_mpd_qnext_plus(self, context); -} - -/*[clinic input] -_decimal.Decimal.normalize - - context: object = None - -Normalize the number by stripping trailing 0s, change anything equal to 0 to 0e0. - -Used for producing canonical values for members of an equivalence class. For -example, Decimal('32.100') and Decimal('0.321000e+2') both normalize to the -equivalent value Decimal('32.1'). -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_normalize_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=db2c8b3c8eccff36 input=16585b21c91500d1]*/ -{ - return dec_mpd_qreduce(self, context); -} - -/*[clinic input] -_decimal.Decimal.sqrt - - context: object = None - -Return the square root of the argument to full precision. - -The result is correctly rounded using the ROUND_HALF_EVEN rounding mode. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_sqrt_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=420722a199dd9c2b input=16df570867daf0d6]*/ -{ - return dec_mpd_qsqrt(self, context); -} - - /* Binary arithmetic functions, optional context arg */ Dec_BinaryFuncVA(mpd_qcompare) Dec_BinaryFuncVA(mpd_qcompare_signal) @@ -4692,166 +4594,6 @@ Dec_BinaryFuncVA(mpd_qmin_mag) Dec_BinaryFuncVA(mpd_qnext_toward) Dec_BinaryFuncVA(mpd_qrem_near) -/*[clinic input] -_decimal.Decimal.compare - - other: object - context: object = None - -Compare self to other. - -Return a decimal value: - - a or b is a NaN ==> Decimal('NaN') - a < b ==> Decimal('-1') - a == b ==> Decimal('0') - a > b ==> Decimal('1') -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_compare_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=d6967aa3578b9d48 input=1b7b75a2a154e520]*/ -{ - return dec_mpd_qcompare(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.compare_signal - - other: object - context: object = None - -Identical to compare, except that all NaNs signal. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_compare_signal_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=0b8d0ff43f6c8a95 input=daf40eeaec81606f]*/ -{ - return dec_mpd_qcompare_signal(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.max - - other: object - context: object = None - -Maximum of self and other. - -If one operand is a quiet NaN and the other is numeric, the numeric operand is -returned. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_max_impl(PyObject *self, PyObject *other, PyObject *context) -/*[clinic end generated code: output=f3a5c5d76761c9ff input=3e53509008bde8c6]*/ -{ - return dec_mpd_qmax(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.max_mag - - other: object - context: object = None - -Similar to the max() method, but the comparison is done using the absolute values of the operands. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_max_mag_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=52b0451987bac65f input=3c2233f8d7a39fa5]*/ -{ - return dec_mpd_qmax_mag(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.min - - other: object - context: object = None - -Minimum of self and other. - -If one operand is a quiet NaN and the other is numeric, the numeric operand is -returned. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_min_impl(PyObject *self, PyObject *other, PyObject *context) -/*[clinic end generated code: output=d2f38ecb9d6f0493 input=264e6259b6ccd831]*/ -{ - return dec_mpd_qmin(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.min_mag - - other: object - context: object = None - -Similar to the min() method, but the comparison is done using the absolute values of the operands. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_min_mag_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=aa3391935f6c8fc9 input=06a65c02e17013c8]*/ -{ - return dec_mpd_qmin_mag(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.next_toward - - other: object - context: object = None - -Returns the number closest to self, in the direction towards other. - -If the two operands are unequal, return the number closest to the first -operand in the direction of the second operand. If both operands are -numerically equal, return a copy of the first operand with the sign set -to be the same as the sign of the second operand. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_next_toward_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=edb933755644af69 input=b03dc5ae977012a5]*/ -{ - return dec_mpd_qnext_toward(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.remainder_near - - other: object - context: object = None - -Return the remainder from dividing self by other. - -This differs from self % other in that the sign of the remainder is chosen so -as to minimize its absolute value. More precisely, the return value is self - -n * other where n is the integer nearest to the exact value of self / other, -and if two integers are equally near then the even one is chosen. - -If the result is zero then its sign will be the sign of self. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_remainder_near_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=6ce0fb3b0faff2f9 input=255acde9a0db84bd]*/ -{ - return dec_mpd_qrem_near(self, other, context); -} - - /* Ternary arithmetic functions, optional context arg */ Dec_TernaryFuncVA(mpd_qfma) @@ -5019,41 +4761,6 @@ _decimal_Decimal_copy_negate_impl(PyObject *self) Dec_UnaryFuncVA(mpd_qinvert) Dec_UnaryFuncVA(mpd_qlogb) -/*[clinic input] -_decimal.Decimal.logical_invert - - context: object = None - -Return the digit-wise inversion of the (logical) operand. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_logical_invert_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=59beb9b1b51b9f34 input=063cc759635d249b]*/ -{ - return dec_mpd_qinvert(self, context); -} - -/*[clinic input] -_decimal.Decimal.logb - - context: object = None - -Return the adjusted exponent of the operand as a Decimal instance. - -If the operand is a zero, then Decimal('-Infinity') is returned and the -DivisionByZero condition is raised. If the operand is an infinity then -Decimal('Infinity') is returned. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_logb_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=f278db20b47f301c input=1a0de8e49b101734]*/ -{ - return dec_mpd_qlogb(self, context); -} - - /*[clinic input] _decimal.Decimal.number_class @@ -5130,65 +4837,6 @@ _decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context) Dec_BinaryFuncVA_NO_CTX(mpd_compare_total) Dec_BinaryFuncVA_NO_CTX(mpd_compare_total_mag) -/*[clinic input] -_decimal.Decimal.compare_total - - other: object - context: object = None - -Compare two operands using their abstract representation rather than their numerical value. - -Similar to the compare() method, but the result -gives a total ordering on Decimal instances. Two Decimal instances with -the same numeric value but different representations compare unequal -in this ordering: - - >>> Decimal('12.0').compare_total(Decimal('12')) - Decimal('-1') - -Quiet and signaling NaNs are also included in the total ordering. The result -of this function is Decimal('0') if both operands have the same representation, -Decimal('-1') if the first operand is lower in the total order than the second, -and Decimal('1') if the first operand is higher in the total order than the -second operand. See the specification for details of the total order. - -This operation is unaffected by context and is quiet: no flags are changed -and no rounding is performed. As an exception, the C version may raise -InvalidOperation if the second operand cannot be converted exactly. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_compare_total_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=dca119b5e881a83e input=f44f1cd5b6fd917e]*/ -{ - return dec_mpd_compare_total(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.compare_total_mag - - other: object - context: object = None - -Compare two operands using their abstract representation rather than their value as in compare_total(), but ignoring the sign of each operand. - -x.compare_total_mag(y) is equivalent to x.copy_abs().compare_total(y.copy_abs()). - -This operation is unaffected by context and is quiet: no flags are changed -and no rounding is performed. As an exception, the C version may raise -InvalidOperation if the second operand cannot be converted exactly. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_compare_total_mag_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=6bf1b3419112d0dd input=84a60b486295a661]*/ -{ - return dec_mpd_compare_total_mag(self, other, context); -} - - /*[clinic input] _decimal.Decimal.copy_sign @@ -5279,124 +4927,6 @@ Dec_BinaryFuncVA(mpd_qrotate) Dec_BinaryFuncVA(mpd_qscaleb) Dec_BinaryFuncVA(mpd_qshift) -/*[clinic input] -_decimal.Decimal.logical_and - - other: object - context: object = None - -Return the digit-wise 'and' of the two (logical) operands. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_logical_and_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=1526a357f97eaf71 input=84d2729d67fca057]*/ -{ - return dec_mpd_qand(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.logical_or - - other: object - context: object = None - -Return the digit-wise 'or' of the two (logical) operands. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_logical_or_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=e57a72acf0982f56 input=03c8141eb7ff8020]*/ -{ - return dec_mpd_qor(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.logical_xor - - other: object - context: object = None - -Return the digit-wise 'xor' of the two (logical) operands. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_logical_xor_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=ae3a7aeddde5a1a8 input=d154ad76a12595a7]*/ -{ - return dec_mpd_qxor(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.rotate - - other: object - context: object = None - -Return the result of rotating the digits of the first operand by an amount specified by the second operand. - -The second operand must be an integer in the range -precision through -precision. The absolute value of the second operand gives the number of places -to rotate. If the second operand is positive then rotation is to the left; -otherwise rotation is to the right. The coefficient of the first operand is -padded on the left with zeros to length precision if necessary. The sign and -exponent of the first operand are unchanged. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_rotate_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=e59e757e70a8416a input=96b253ac6414a884]*/ -{ - return dec_mpd_qrotate(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.scaleb - - other: object - context: object = None - -Return the first operand with the exponent adjusted the second. - -Equivalently, return the first operand multiplied by 10**other. The second -operand must be an integer. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_scaleb_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=f01e99600eda34d7 input=79d9bca73749fa06]*/ -{ - return dec_mpd_qscaleb(self, other, context); -} - -/*[clinic input] -_decimal.Decimal.shift - - other: object - context: object = None - -Return the result of shifting the digits of the first operand by an amount specified by the second operand. - -The second operand must be an integer in the range -precision through -precision. The absolute value of the second operand gives the number of places -to shift. If the second operand is positive, then the shift is to the left; -otherwise the shift is to the right. Digits shifted into the coefficient are -zeros. The sign and exponent of the first operand are unchanged. -[clinic start generated code]*/ - -static PyObject * -_decimal_Decimal_shift_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=f79ff9ce6d5b05ed input=a680ecfa745bd6e4]*/ -{ - return dec_mpd_qshift(self, other, context); -} - /*[clinic input] _decimal.Decimal.quantize @@ -5776,27 +5306,27 @@ static PyGetSetDef dec_getsets [] = static PyMethodDef dec_methods [] = { /* Unary arithmetic functions, optional context arg */ - _DECIMAL_DECIMAL_EXP_METHODDEF - _DECIMAL_DECIMAL_LN_METHODDEF - _DECIMAL_DECIMAL_LOG10_METHODDEF - _DECIMAL_DECIMAL_NEXT_MINUS_METHODDEF - _DECIMAL_DECIMAL_NEXT_PLUS_METHODDEF - _DECIMAL_DECIMAL_NORMALIZE_METHODDEF + { "exp", _PyCFunction_CAST(dec_mpd_qexp), METH_VARARGS|METH_KEYWORDS, doc_exp }, + { "ln", _PyCFunction_CAST(dec_mpd_qln), METH_VARARGS|METH_KEYWORDS, doc_ln }, + { "log10", _PyCFunction_CAST(dec_mpd_qlog10), METH_VARARGS|METH_KEYWORDS, doc_log10 }, + { "next_minus", _PyCFunction_CAST(dec_mpd_qnext_minus), METH_VARARGS|METH_KEYWORDS, doc_next_minus }, + { "next_plus", _PyCFunction_CAST(dec_mpd_qnext_plus), METH_VARARGS|METH_KEYWORDS, doc_next_plus }, + { "normalize", _PyCFunction_CAST(dec_mpd_qreduce), METH_VARARGS|METH_KEYWORDS, doc_normalize }, _DECIMAL_DECIMAL_TO_INTEGRAL_METHODDEF _DECIMAL_DECIMAL_TO_INTEGRAL_EXACT_METHODDEF _DECIMAL_DECIMAL_TO_INTEGRAL_VALUE_METHODDEF - _DECIMAL_DECIMAL_SQRT_METHODDEF + { "sqrt", _PyCFunction_CAST(dec_mpd_qsqrt), METH_VARARGS|METH_KEYWORDS, doc_sqrt }, /* Binary arithmetic functions, optional context arg */ - _DECIMAL_DECIMAL_COMPARE_METHODDEF - _DECIMAL_DECIMAL_COMPARE_SIGNAL_METHODDEF - _DECIMAL_DECIMAL_MAX_METHODDEF - _DECIMAL_DECIMAL_MAX_MAG_METHODDEF - _DECIMAL_DECIMAL_MIN_METHODDEF - _DECIMAL_DECIMAL_MIN_MAG_METHODDEF - _DECIMAL_DECIMAL_NEXT_TOWARD_METHODDEF + { "compare", _PyCFunction_CAST(dec_mpd_qcompare), METH_VARARGS|METH_KEYWORDS, doc_compare }, + { "compare_signal", _PyCFunction_CAST(dec_mpd_qcompare_signal), METH_VARARGS|METH_KEYWORDS, doc_compare_signal }, + { "max", _PyCFunction_CAST(dec_mpd_qmax), METH_VARARGS|METH_KEYWORDS, doc_max }, + { "max_mag", _PyCFunction_CAST(dec_mpd_qmax_mag), METH_VARARGS|METH_KEYWORDS, doc_max_mag }, + { "min", _PyCFunction_CAST(dec_mpd_qmin), METH_VARARGS|METH_KEYWORDS, doc_min }, + { "min_mag", _PyCFunction_CAST(dec_mpd_qmin_mag), METH_VARARGS|METH_KEYWORDS, doc_min_mag }, + { "next_toward", _PyCFunction_CAST(dec_mpd_qnext_toward), METH_VARARGS|METH_KEYWORDS, doc_next_toward }, _DECIMAL_DECIMAL_QUANTIZE_METHODDEF - _DECIMAL_DECIMAL_REMAINDER_NEAR_METHODDEF + { "remainder_near", _PyCFunction_CAST(dec_mpd_qrem_near), METH_VARARGS|METH_KEYWORDS, doc_remainder_near }, /* Ternary arithmetic functions, optional context arg */ { "fma", _PyCFunction_CAST(dec_mpd_qfma), METH_VARARGS|METH_KEYWORDS, doc_fma }, @@ -5826,24 +5356,24 @@ static PyMethodDef dec_methods [] = _DECIMAL_DECIMAL_COPY_NEGATE_METHODDEF /* Unary functions, optional context arg */ - _DECIMAL_DECIMAL_LOGB_METHODDEF - _DECIMAL_DECIMAL_LOGICAL_INVERT_METHODDEF + { "logb", _PyCFunction_CAST(dec_mpd_qlogb), METH_VARARGS|METH_KEYWORDS, doc_logb }, + { "logical_invert", _PyCFunction_CAST(dec_mpd_qinvert), METH_VARARGS|METH_KEYWORDS, doc_logical_invert }, _DECIMAL_DECIMAL_NUMBER_CLASS_METHODDEF _DECIMAL_DECIMAL_TO_ENG_STRING_METHODDEF /* Binary functions, optional context arg for conversion errors */ - _DECIMAL_DECIMAL_COMPARE_TOTAL_METHODDEF - _DECIMAL_DECIMAL_COMPARE_TOTAL_MAG_METHODDEF + { "compare_total", _PyCFunction_CAST(dec_mpd_compare_total), METH_VARARGS|METH_KEYWORDS, doc_compare_total }, + { "compare_total_mag", _PyCFunction_CAST(dec_mpd_compare_total_mag), METH_VARARGS|METH_KEYWORDS, doc_compare_total_mag }, _DECIMAL_DECIMAL_COPY_SIGN_METHODDEF _DECIMAL_DECIMAL_SAME_QUANTUM_METHODDEF /* Binary functions, optional context arg */ - _DECIMAL_DECIMAL_LOGICAL_AND_METHODDEF - _DECIMAL_DECIMAL_LOGICAL_OR_METHODDEF - _DECIMAL_DECIMAL_LOGICAL_XOR_METHODDEF - _DECIMAL_DECIMAL_ROTATE_METHODDEF - _DECIMAL_DECIMAL_SCALEB_METHODDEF - _DECIMAL_DECIMAL_SHIFT_METHODDEF + { "logical_and", _PyCFunction_CAST(dec_mpd_qand), METH_VARARGS|METH_KEYWORDS, doc_logical_and }, + { "logical_or", _PyCFunction_CAST(dec_mpd_qor), METH_VARARGS|METH_KEYWORDS, doc_logical_or }, + { "logical_xor", _PyCFunction_CAST(dec_mpd_qxor), METH_VARARGS|METH_KEYWORDS, doc_logical_xor }, + { "rotate", _PyCFunction_CAST(dec_mpd_qrotate), METH_VARARGS|METH_KEYWORDS, doc_rotate }, + { "scaleb", _PyCFunction_CAST(dec_mpd_qscaleb), METH_VARARGS|METH_KEYWORDS, doc_scaleb }, + { "shift", _PyCFunction_CAST(dec_mpd_qshift), METH_VARARGS|METH_KEYWORDS, doc_shift }, /* Miscellaneous */ _DECIMAL_DECIMAL_FROM_FLOAT_METHODDEF diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index e4c4805e1408b0..de805437724df0 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -334,1862 +334,158 @@ _decimal_Decimal_as_tuple(PyObject *self, PyObject *Py_UNUSED(ignored)) return _decimal_Decimal_as_tuple_impl(self); } -PyDoc_STRVAR(_decimal_Decimal_exp__doc__, -"exp($self, /, context=None)\n" -"--\n" -"\n" -"Return the value of the (natural) exponential function e**x at the given number.\n" -"\n" -"The function always uses the ROUND_HALF_EVEN mode and the result is correctly\n" -"rounded."); - -#define _DECIMAL_DECIMAL_EXP_METHODDEF \ - {"exp", _PyCFunction_CAST(_decimal_Decimal_exp), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_exp__doc__}, - -static PyObject * -_decimal_Decimal_exp_impl(PyObject *self, PyObject *context); - -static PyObject * -_decimal_Decimal_exp(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "exp", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - context = args[0]; -skip_optional_pos: - return_value = _decimal_Decimal_exp_impl(self, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_ln__doc__, -"ln($self, /, context=None)\n" -"--\n" -"\n" -"Return the natural (base e) logarithm of the operand.\n" -"\n" -"The function always uses the ROUND_HALF_EVEN mode and the result is correctly\n" -"rounded."); - -#define _DECIMAL_DECIMAL_LN_METHODDEF \ - {"ln", _PyCFunction_CAST(_decimal_Decimal_ln), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_ln__doc__}, - -static PyObject * -_decimal_Decimal_ln_impl(PyObject *self, PyObject *context); - -static PyObject * -_decimal_Decimal_ln(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "ln", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - context = args[0]; -skip_optional_pos: - return_value = _decimal_Decimal_ln_impl(self, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_log10__doc__, -"log10($self, /, context=None)\n" -"--\n" -"\n" -"Return the base ten logarithm of the operand.\n" -"\n" -"The function always uses the ROUND_HALF_EVEN mode and the result is correctly\n" -"rounded."); - -#define _DECIMAL_DECIMAL_LOG10_METHODDEF \ - {"log10", _PyCFunction_CAST(_decimal_Decimal_log10), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_log10__doc__}, - -static PyObject * -_decimal_Decimal_log10_impl(PyObject *self, PyObject *context); - -static PyObject * -_decimal_Decimal_log10(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "log10", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - context = args[0]; -skip_optional_pos: - return_value = _decimal_Decimal_log10_impl(self, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_next_minus__doc__, -"next_minus($self, /, context=None)\n" -"--\n" -"\n" -"Returns the largest representable number smaller than itself."); - -#define _DECIMAL_DECIMAL_NEXT_MINUS_METHODDEF \ - {"next_minus", _PyCFunction_CAST(_decimal_Decimal_next_minus), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_minus__doc__}, - -static PyObject * -_decimal_Decimal_next_minus_impl(PyObject *self, PyObject *context); - -static PyObject * -_decimal_Decimal_next_minus(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "next_minus", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - context = args[0]; -skip_optional_pos: - return_value = _decimal_Decimal_next_minus_impl(self, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_next_plus__doc__, -"next_plus($self, /, context=None)\n" -"--\n" -"\n" -"Returns the smallest representable number larger than itself."); - -#define _DECIMAL_DECIMAL_NEXT_PLUS_METHODDEF \ - {"next_plus", _PyCFunction_CAST(_decimal_Decimal_next_plus), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_plus__doc__}, - -static PyObject * -_decimal_Decimal_next_plus_impl(PyObject *self, PyObject *context); - -static PyObject * -_decimal_Decimal_next_plus(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "next_plus", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - context = args[0]; -skip_optional_pos: - return_value = _decimal_Decimal_next_plus_impl(self, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_normalize__doc__, -"normalize($self, /, context=None)\n" -"--\n" -"\n" -"Normalize the number by stripping trailing 0s, change anything equal to 0 to 0e0.\n" -"\n" -"Used for producing canonical values for members of an equivalence class. For\n" -"example, Decimal(\'32.100\') and Decimal(\'0.321000e+2\') both normalize to the\n" -"equivalent value Decimal(\'32.1\')."); - -#define _DECIMAL_DECIMAL_NORMALIZE_METHODDEF \ - {"normalize", _PyCFunction_CAST(_decimal_Decimal_normalize), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_normalize__doc__}, - -static PyObject * -_decimal_Decimal_normalize_impl(PyObject *self, PyObject *context); - -static PyObject * -_decimal_Decimal_normalize(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "normalize", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - context = args[0]; -skip_optional_pos: - return_value = _decimal_Decimal_normalize_impl(self, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_sqrt__doc__, -"sqrt($self, /, context=None)\n" -"--\n" -"\n" -"Return the square root of the argument to full precision.\n" -"\n" -"The result is correctly rounded using the ROUND_HALF_EVEN rounding mode."); - -#define _DECIMAL_DECIMAL_SQRT_METHODDEF \ - {"sqrt", _PyCFunction_CAST(_decimal_Decimal_sqrt), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_sqrt__doc__}, - -static PyObject * -_decimal_Decimal_sqrt_impl(PyObject *self, PyObject *context); - -static PyObject * -_decimal_Decimal_sqrt(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "sqrt", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - context = args[0]; -skip_optional_pos: - return_value = _decimal_Decimal_sqrt_impl(self, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_compare__doc__, -"compare($self, /, other, context=None)\n" -"--\n" -"\n" -"Compare self to other.\n" -"\n" -"Return a decimal value:\n" -"\n" -" a or b is a NaN ==> Decimal(\'NaN\')\n" -" a < b ==> Decimal(\'-1\')\n" -" a == b ==> Decimal(\'0\')\n" -" a > b ==> Decimal(\'1\')"); - -#define _DECIMAL_DECIMAL_COMPARE_METHODDEF \ - {"compare", _PyCFunction_CAST(_decimal_Decimal_compare), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare__doc__}, - -static PyObject * -_decimal_Decimal_compare_impl(PyObject *self, PyObject *other, - PyObject *context); - -static PyObject * -_decimal_Decimal_compare(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "compare", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_compare_impl(self, other, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_compare_signal__doc__, -"compare_signal($self, /, other, context=None)\n" -"--\n" -"\n" -"Identical to compare, except that all NaNs signal."); - -#define _DECIMAL_DECIMAL_COMPARE_SIGNAL_METHODDEF \ - {"compare_signal", _PyCFunction_CAST(_decimal_Decimal_compare_signal), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_signal__doc__}, - -static PyObject * -_decimal_Decimal_compare_signal_impl(PyObject *self, PyObject *other, - PyObject *context); - -static PyObject * -_decimal_Decimal_compare_signal(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "compare_signal", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_compare_signal_impl(self, other, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_max__doc__, -"max($self, /, other, context=None)\n" -"--\n" -"\n" -"Maximum of self and other.\n" -"\n" -"If one operand is a quiet NaN and the other is numeric, the numeric operand is\n" -"returned."); - -#define _DECIMAL_DECIMAL_MAX_METHODDEF \ - {"max", _PyCFunction_CAST(_decimal_Decimal_max), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_max__doc__}, - -static PyObject * -_decimal_Decimal_max_impl(PyObject *self, PyObject *other, PyObject *context); - -static PyObject * -_decimal_Decimal_max(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "max", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_max_impl(self, other, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_max_mag__doc__, -"max_mag($self, /, other, context=None)\n" -"--\n" -"\n" -"Similar to the max() method, but the comparison is done using the absolute values of the operands."); - -#define _DECIMAL_DECIMAL_MAX_MAG_METHODDEF \ - {"max_mag", _PyCFunction_CAST(_decimal_Decimal_max_mag), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_max_mag__doc__}, - -static PyObject * -_decimal_Decimal_max_mag_impl(PyObject *self, PyObject *other, - PyObject *context); - -static PyObject * -_decimal_Decimal_max_mag(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "max_mag", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_max_mag_impl(self, other, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_min__doc__, -"min($self, /, other, context=None)\n" -"--\n" -"\n" -"Minimum of self and other.\n" -"\n" -"If one operand is a quiet NaN and the other is numeric, the numeric operand is\n" -"returned."); - -#define _DECIMAL_DECIMAL_MIN_METHODDEF \ - {"min", _PyCFunction_CAST(_decimal_Decimal_min), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_min__doc__}, - -static PyObject * -_decimal_Decimal_min_impl(PyObject *self, PyObject *other, PyObject *context); - -static PyObject * -_decimal_Decimal_min(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "min", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_min_impl(self, other, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_min_mag__doc__, -"min_mag($self, /, other, context=None)\n" -"--\n" -"\n" -"Similar to the min() method, but the comparison is done using the absolute values of the operands."); - -#define _DECIMAL_DECIMAL_MIN_MAG_METHODDEF \ - {"min_mag", _PyCFunction_CAST(_decimal_Decimal_min_mag), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_min_mag__doc__}, - -static PyObject * -_decimal_Decimal_min_mag_impl(PyObject *self, PyObject *other, - PyObject *context); - -static PyObject * -_decimal_Decimal_min_mag(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "min_mag", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_min_mag_impl(self, other, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_next_toward__doc__, -"next_toward($self, /, other, context=None)\n" -"--\n" -"\n" -"Returns the number closest to self, in the direction towards other.\n" -"\n" -"If the two operands are unequal, return the number closest to the first\n" -"operand in the direction of the second operand. If both operands are\n" -"numerically equal, return a copy of the first operand with the sign set\n" -"to be the same as the sign of the second operand."); - -#define _DECIMAL_DECIMAL_NEXT_TOWARD_METHODDEF \ - {"next_toward", _PyCFunction_CAST(_decimal_Decimal_next_toward), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_toward__doc__}, - -static PyObject * -_decimal_Decimal_next_toward_impl(PyObject *self, PyObject *other, - PyObject *context); - -static PyObject * -_decimal_Decimal_next_toward(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "next_toward", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_next_toward_impl(self, other, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_remainder_near__doc__, -"remainder_near($self, /, other, context=None)\n" -"--\n" -"\n" -"Return the remainder from dividing self by other.\n" -"\n" -"This differs from self % other in that the sign of the remainder is chosen so\n" -"as to minimize its absolute value. More precisely, the return value is self -\n" -"n * other where n is the integer nearest to the exact value of self / other,\n" -"and if two integers are equally near then the even one is chosen.\n" -"\n" -"If the result is zero then its sign will be the sign of self."); - -#define _DECIMAL_DECIMAL_REMAINDER_NEAR_METHODDEF \ - {"remainder_near", _PyCFunction_CAST(_decimal_Decimal_remainder_near), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_remainder_near__doc__}, - -static PyObject * -_decimal_Decimal_remainder_near_impl(PyObject *self, PyObject *other, - PyObject *context); - -static PyObject * -_decimal_Decimal_remainder_near(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "remainder_near", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_remainder_near_impl(self, other, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_adjusted__doc__, -"adjusted($self, /)\n" -"--\n" -"\n" -"Return the adjusted exponent of the number. Defined as exp + digits - 1."); - -#define _DECIMAL_DECIMAL_ADJUSTED_METHODDEF \ - {"adjusted", (PyCFunction)_decimal_Decimal_adjusted, METH_NOARGS, _decimal_Decimal_adjusted__doc__}, - -static PyObject * -_decimal_Decimal_adjusted_impl(PyObject *self); - -static PyObject * -_decimal_Decimal_adjusted(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _decimal_Decimal_adjusted_impl(self); -} - -PyDoc_STRVAR(_decimal_Decimal_canonical__doc__, -"canonical($self, /)\n" -"--\n" -"\n" -"Return the canonical encoding of the argument.\n" -"\n" -"Currently, the encoding of a Decimal instance is always canonical, so this\n" -"operation returns its argument unchanged."); - -#define _DECIMAL_DECIMAL_CANONICAL_METHODDEF \ - {"canonical", (PyCFunction)_decimal_Decimal_canonical, METH_NOARGS, _decimal_Decimal_canonical__doc__}, - -static PyObject * -_decimal_Decimal_canonical_impl(PyObject *self); - -static PyObject * -_decimal_Decimal_canonical(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _decimal_Decimal_canonical_impl(self); -} - -PyDoc_STRVAR(_decimal_Decimal_conjugate__doc__, -"conjugate($self, /)\n" -"--\n" -"\n" -"Return self."); - -#define _DECIMAL_DECIMAL_CONJUGATE_METHODDEF \ - {"conjugate", (PyCFunction)_decimal_Decimal_conjugate, METH_NOARGS, _decimal_Decimal_conjugate__doc__}, - -static PyObject * -_decimal_Decimal_conjugate_impl(PyObject *self); - -static PyObject * -_decimal_Decimal_conjugate(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _decimal_Decimal_conjugate_impl(self); -} - -PyDoc_STRVAR(_decimal_Decimal_radix__doc__, -"radix($self, /)\n" -"--\n" -"\n" -"Return Decimal(10).\n" -"\n" -"This is the radix (base) in which the Decimal class does\n" -"all its arithmetic. Included for compatibility with the specification."); - -#define _DECIMAL_DECIMAL_RADIX_METHODDEF \ - {"radix", (PyCFunction)_decimal_Decimal_radix, METH_NOARGS, _decimal_Decimal_radix__doc__}, - -static PyObject * -_decimal_Decimal_radix_impl(PyObject *self); - -static PyObject * -_decimal_Decimal_radix(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _decimal_Decimal_radix_impl(self); -} - -PyDoc_STRVAR(_decimal_Decimal_copy_abs__doc__, -"copy_abs($self, /)\n" -"--\n" -"\n" -"Return the absolute value of the argument.\n" -"\n" -"This operation is unaffected by context and is quiet: no flags are changed and\n" -"no rounding is performed."); - -#define _DECIMAL_DECIMAL_COPY_ABS_METHODDEF \ - {"copy_abs", (PyCFunction)_decimal_Decimal_copy_abs, METH_NOARGS, _decimal_Decimal_copy_abs__doc__}, - -static PyObject * -_decimal_Decimal_copy_abs_impl(PyObject *self); - -static PyObject * -_decimal_Decimal_copy_abs(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _decimal_Decimal_copy_abs_impl(self); -} - -PyDoc_STRVAR(_decimal_Decimal_copy_negate__doc__, -"copy_negate($self, /)\n" -"--\n" -"\n" -"Return the negation of the argument.\n" -"\n" -"This operation is unaffected by context and is quiet: no flags are changed and\n" -"no rounding is performed."); - -#define _DECIMAL_DECIMAL_COPY_NEGATE_METHODDEF \ - {"copy_negate", (PyCFunction)_decimal_Decimal_copy_negate, METH_NOARGS, _decimal_Decimal_copy_negate__doc__}, - -static PyObject * -_decimal_Decimal_copy_negate_impl(PyObject *self); - -static PyObject * -_decimal_Decimal_copy_negate(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _decimal_Decimal_copy_negate_impl(self); -} - -PyDoc_STRVAR(_decimal_Decimal_logical_invert__doc__, -"logical_invert($self, /, context=None)\n" -"--\n" -"\n" -"Return the digit-wise inversion of the (logical) operand."); - -#define _DECIMAL_DECIMAL_LOGICAL_INVERT_METHODDEF \ - {"logical_invert", _PyCFunction_CAST(_decimal_Decimal_logical_invert), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_invert__doc__}, - -static PyObject * -_decimal_Decimal_logical_invert_impl(PyObject *self, PyObject *context); - -static PyObject * -_decimal_Decimal_logical_invert(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "logical_invert", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - context = args[0]; -skip_optional_pos: - return_value = _decimal_Decimal_logical_invert_impl(self, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_logb__doc__, -"logb($self, /, context=None)\n" -"--\n" -"\n" -"Return the adjusted exponent of the operand as a Decimal instance.\n" -"\n" -"If the operand is a zero, then Decimal(\'-Infinity\') is returned and the\n" -"DivisionByZero condition is raised. If the operand is an infinity then\n" -"Decimal(\'Infinity\') is returned."); - -#define _DECIMAL_DECIMAL_LOGB_METHODDEF \ - {"logb", _PyCFunction_CAST(_decimal_Decimal_logb), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logb__doc__}, - -static PyObject * -_decimal_Decimal_logb_impl(PyObject *self, PyObject *context); - -static PyObject * -_decimal_Decimal_logb(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "logb", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - context = args[0]; -skip_optional_pos: - return_value = _decimal_Decimal_logb_impl(self, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_number_class__doc__, -"number_class($self, /, context=None)\n" -"--\n" -"\n" -"Return a string describing the class of the operand.\n" -"\n" -"The returned value is one of the following ten strings:\n" -"\n" -" * \'-Infinity\', indicating that the operand is negative infinity.\n" -" * \'-Normal\', indicating that the operand is a negative normal number.\n" -" * \'-Subnormal\', indicating that the operand is negative and subnormal.\n" -" * \'-Zero\', indicating that the operand is a negative zero.\n" -" * \'+Zero\', indicating that the operand is a positive zero.\n" -" * \'+Subnormal\', indicating that the operand is positive and subnormal.\n" -" * \'+Normal\', indicating that the operand is a positive normal number.\n" -" * \'+Infinity\', indicating that the operand is positive infinity.\n" -" * \'NaN\', indicating that the operand is a quiet NaN (Not a Number).\n" -" * \'sNaN\', indicating that the operand is a signaling NaN."); - -#define _DECIMAL_DECIMAL_NUMBER_CLASS_METHODDEF \ - {"number_class", _PyCFunction_CAST(_decimal_Decimal_number_class), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_number_class__doc__}, - -static PyObject * -_decimal_Decimal_number_class_impl(PyObject *self, PyObject *context); - -static PyObject * -_decimal_Decimal_number_class(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "number_class", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - context = args[0]; -skip_optional_pos: - return_value = _decimal_Decimal_number_class_impl(self, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_to_eng_string__doc__, -"to_eng_string($self, /, context=None)\n" -"--\n" -"\n" -"Convert to an engineering-type string.\n" -"\n" -"Engineering notation has an exponent which is a multiple of 3, so there are up\n" -"to 3 digits left of the decimal place. For example, Decimal(\'123E+1\') is\n" -"converted to Decimal(\'1.23E+3\').\n" -"\n" -"The value of context.capitals determines whether the exponent sign is lower\n" -"or upper case. Otherwise, the context does not affect the operation."); - -#define _DECIMAL_DECIMAL_TO_ENG_STRING_METHODDEF \ - {"to_eng_string", _PyCFunction_CAST(_decimal_Decimal_to_eng_string), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_eng_string__doc__}, - -static PyObject * -_decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context); - -static PyObject * -_decimal_Decimal_to_eng_string(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "to_eng_string", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - context = args[0]; -skip_optional_pos: - return_value = _decimal_Decimal_to_eng_string_impl(self, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_compare_total__doc__, -"compare_total($self, /, other, context=None)\n" -"--\n" -"\n" -"Compare two operands using their abstract representation rather than their numerical value.\n" -"\n" -"Similar to the compare() method, but the result\n" -"gives a total ordering on Decimal instances. Two Decimal instances with\n" -"the same numeric value but different representations compare unequal\n" -"in this ordering:\n" -"\n" -" >>> Decimal(\'12.0\').compare_total(Decimal(\'12\'))\n" -" Decimal(\'-1\')\n" -"\n" -"Quiet and signaling NaNs are also included in the total ordering. The result\n" -"of this function is Decimal(\'0\') if both operands have the same representation,\n" -"Decimal(\'-1\') if the first operand is lower in the total order than the second,\n" -"and Decimal(\'1\') if the first operand is higher in the total order than the\n" -"second operand. See the specification for details of the total order.\n" -"\n" -"This operation is unaffected by context and is quiet: no flags are changed\n" -"and no rounding is performed. As an exception, the C version may raise\n" -"InvalidOperation if the second operand cannot be converted exactly."); - -#define _DECIMAL_DECIMAL_COMPARE_TOTAL_METHODDEF \ - {"compare_total", _PyCFunction_CAST(_decimal_Decimal_compare_total), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_total__doc__}, - -static PyObject * -_decimal_Decimal_compare_total_impl(PyObject *self, PyObject *other, - PyObject *context); - -static PyObject * -_decimal_Decimal_compare_total(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "compare_total", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_compare_total_impl(self, other, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_compare_total_mag__doc__, -"compare_total_mag($self, /, other, context=None)\n" -"--\n" -"\n" -"Compare two operands using their abstract representation rather than their value as in compare_total(), but ignoring the sign of each operand.\n" -"\n" -"x.compare_total_mag(y) is equivalent to x.copy_abs().compare_total(y.copy_abs()).\n" -"\n" -"This operation is unaffected by context and is quiet: no flags are changed\n" -"and no rounding is performed. As an exception, the C version may raise\n" -"InvalidOperation if the second operand cannot be converted exactly."); - -#define _DECIMAL_DECIMAL_COMPARE_TOTAL_MAG_METHODDEF \ - {"compare_total_mag", _PyCFunction_CAST(_decimal_Decimal_compare_total_mag), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_total_mag__doc__}, - -static PyObject * -_decimal_Decimal_compare_total_mag_impl(PyObject *self, PyObject *other, - PyObject *context); - -static PyObject * -_decimal_Decimal_compare_total_mag(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "compare_total_mag", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_compare_total_mag_impl(self, other, context); - -exit: - return return_value; -} - -PyDoc_STRVAR(_decimal_Decimal_copy_sign__doc__, -"copy_sign($self, /, other, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_adjusted__doc__, +"adjusted($self, /)\n" "--\n" "\n" -"Return a copy of *self* with the sign set to be the same as the sign of *other*.\n" -"\n" -"For example:\n" -"\n" -" >>> Decimal(\'2.3\').copy_sign(Decimal(\'-1.5\'))\n" -" Decimal(\'-2.3\')\n" -"\n" -"This operation is unaffected by context and is quiet: no flags are changed\n" -"and no rounding is performed. As an exception, the C version may raise\n" -"InvalidOperation if the second operand cannot be converted exactly."); +"Return the adjusted exponent of the number. Defined as exp + digits - 1."); -#define _DECIMAL_DECIMAL_COPY_SIGN_METHODDEF \ - {"copy_sign", _PyCFunction_CAST(_decimal_Decimal_copy_sign), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_copy_sign__doc__}, +#define _DECIMAL_DECIMAL_ADJUSTED_METHODDEF \ + {"adjusted", (PyCFunction)_decimal_Decimal_adjusted, METH_NOARGS, _decimal_Decimal_adjusted__doc__}, static PyObject * -_decimal_Decimal_copy_sign_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_adjusted_impl(PyObject *self); static PyObject * -_decimal_Decimal_copy_sign(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_adjusted(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "copy_sign", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_copy_sign_impl(self, other, context); - -exit: - return return_value; + return _decimal_Decimal_adjusted_impl(self); } -PyDoc_STRVAR(_decimal_Decimal_same_quantum__doc__, -"same_quantum($self, /, other, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_canonical__doc__, +"canonical($self, /)\n" "--\n" -"\n" -"Test whether self and other have the same exponent or whether both are NaN.\n" -"\n" -"This operation is unaffected by context and is quiet: no flags are changed\n" -"and no rounding is performed. As an exception, the C version may raise\n" -"InvalidOperation if the second operand cannot be converted exactly."); - -#define _DECIMAL_DECIMAL_SAME_QUANTUM_METHODDEF \ - {"same_quantum", _PyCFunction_CAST(_decimal_Decimal_same_quantum), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_same_quantum__doc__}, - -static PyObject * -_decimal_Decimal_same_quantum_impl(PyObject *self, PyObject *other, - PyObject *context); - -static PyObject * -_decimal_Decimal_same_quantum(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "same_quantum", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_same_quantum_impl(self, other, context); +"\n" +"Return the canonical encoding of the argument.\n" +"\n" +"Currently, the encoding of a Decimal instance is always canonical, so this\n" +"operation returns its argument unchanged."); -exit: - return return_value; +#define _DECIMAL_DECIMAL_CANONICAL_METHODDEF \ + {"canonical", (PyCFunction)_decimal_Decimal_canonical, METH_NOARGS, _decimal_Decimal_canonical__doc__}, + +static PyObject * +_decimal_Decimal_canonical_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_canonical(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_canonical_impl(self); } -PyDoc_STRVAR(_decimal_Decimal_logical_and__doc__, -"logical_and($self, /, other, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_conjugate__doc__, +"conjugate($self, /)\n" "--\n" "\n" -"Return the digit-wise \'and\' of the two (logical) operands."); +"Return self."); -#define _DECIMAL_DECIMAL_LOGICAL_AND_METHODDEF \ - {"logical_and", _PyCFunction_CAST(_decimal_Decimal_logical_and), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_and__doc__}, +#define _DECIMAL_DECIMAL_CONJUGATE_METHODDEF \ + {"conjugate", (PyCFunction)_decimal_Decimal_conjugate, METH_NOARGS, _decimal_Decimal_conjugate__doc__}, static PyObject * -_decimal_Decimal_logical_and_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_conjugate_impl(PyObject *self); static PyObject * -_decimal_Decimal_logical_and(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_conjugate(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) + return _decimal_Decimal_conjugate_impl(self); +} - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE +PyDoc_STRVAR(_decimal_Decimal_radix__doc__, +"radix($self, /)\n" +"--\n" +"\n" +"Return Decimal(10).\n" +"\n" +"This is the radix (base) in which the Decimal class does\n" +"all its arithmetic. Included for compatibility with the specification."); - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "logical_and", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; +#define _DECIMAL_DECIMAL_RADIX_METHODDEF \ + {"radix", (PyCFunction)_decimal_Decimal_radix, METH_NOARGS, _decimal_Decimal_radix__doc__}, - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_logical_and_impl(self, other, context); +static PyObject * +_decimal_Decimal_radix_impl(PyObject *self); -exit: - return return_value; +static PyObject * +_decimal_Decimal_radix(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_radix_impl(self); } -PyDoc_STRVAR(_decimal_Decimal_logical_or__doc__, -"logical_or($self, /, other, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_copy_abs__doc__, +"copy_abs($self, /)\n" "--\n" "\n" -"Return the digit-wise \'or\' of the two (logical) operands."); +"Return the absolute value of the argument.\n" +"\n" +"This operation is unaffected by context and is quiet: no flags are changed and\n" +"no rounding is performed."); -#define _DECIMAL_DECIMAL_LOGICAL_OR_METHODDEF \ - {"logical_or", _PyCFunction_CAST(_decimal_Decimal_logical_or), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_or__doc__}, +#define _DECIMAL_DECIMAL_COPY_ABS_METHODDEF \ + {"copy_abs", (PyCFunction)_decimal_Decimal_copy_abs, METH_NOARGS, _decimal_Decimal_copy_abs__doc__}, static PyObject * -_decimal_Decimal_logical_or_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_copy_abs_impl(PyObject *self); static PyObject * -_decimal_Decimal_logical_or(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_copy_abs(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) + return _decimal_Decimal_copy_abs_impl(self); +} - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE +PyDoc_STRVAR(_decimal_Decimal_copy_negate__doc__, +"copy_negate($self, /)\n" +"--\n" +"\n" +"Return the negation of the argument.\n" +"\n" +"This operation is unaffected by context and is quiet: no flags are changed and\n" +"no rounding is performed."); - static const char * const _keywords[] = {"other", "context", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "logical_or", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; - PyObject *context = Py_None; +#define _DECIMAL_DECIMAL_COPY_NEGATE_METHODDEF \ + {"copy_negate", (PyCFunction)_decimal_Decimal_copy_negate, METH_NOARGS, _decimal_Decimal_copy_negate__doc__}, - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - other = args[0]; - if (!noptargs) { - goto skip_optional_pos; - } - context = args[1]; -skip_optional_pos: - return_value = _decimal_Decimal_logical_or_impl(self, other, context); +static PyObject * +_decimal_Decimal_copy_negate_impl(PyObject *self); -exit: - return return_value; +static PyObject * +_decimal_Decimal_copy_negate(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_copy_negate_impl(self); } -PyDoc_STRVAR(_decimal_Decimal_logical_xor__doc__, -"logical_xor($self, /, other, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_number_class__doc__, +"number_class($self, /, context=None)\n" "--\n" "\n" -"Return the digit-wise \'xor\' of the two (logical) operands."); +"Return a string describing the class of the operand.\n" +"\n" +"The returned value is one of the following ten strings:\n" +"\n" +" * \'-Infinity\', indicating that the operand is negative infinity.\n" +" * \'-Normal\', indicating that the operand is a negative normal number.\n" +" * \'-Subnormal\', indicating that the operand is negative and subnormal.\n" +" * \'-Zero\', indicating that the operand is a negative zero.\n" +" * \'+Zero\', indicating that the operand is a positive zero.\n" +" * \'+Subnormal\', indicating that the operand is positive and subnormal.\n" +" * \'+Normal\', indicating that the operand is a positive normal number.\n" +" * \'+Infinity\', indicating that the operand is positive infinity.\n" +" * \'NaN\', indicating that the operand is a quiet NaN (Not a Number).\n" +" * \'sNaN\', indicating that the operand is a signaling NaN."); -#define _DECIMAL_DECIMAL_LOGICAL_XOR_METHODDEF \ - {"logical_xor", _PyCFunction_CAST(_decimal_Decimal_logical_xor), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_xor__doc__}, +#define _DECIMAL_DECIMAL_NUMBER_CLASS_METHODDEF \ + {"number_class", _PyCFunction_CAST(_decimal_Decimal_number_class), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_number_class__doc__}, static PyObject * -_decimal_Decimal_logical_xor_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_number_class_impl(PyObject *self, PyObject *context); static PyObject * -_decimal_Decimal_logical_xor(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_number_class(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 2 + #define NUM_KEYWORDS 1 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD @@ -2198,7 +494,7 @@ _decimal_Decimal_logical_xor(PyObject *self, PyObject *const *args, Py_ssize_t n } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + .ob_item = { &_Py_ID(context), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2207,62 +503,59 @@ _decimal_Decimal_logical_xor(PyObject *self, PyObject *const *args, Py_ssize_t n # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"other", "context", NULL}; + static const char * const _keywords[] = {"context", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "logical_xor", + .fname = "number_class", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; PyObject *context = Py_None; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } - other = args[0]; if (!noptargs) { goto skip_optional_pos; } - context = args[1]; + context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_logical_xor_impl(self, other, context); + return_value = _decimal_Decimal_number_class_impl(self, context); exit: return return_value; } -PyDoc_STRVAR(_decimal_Decimal_rotate__doc__, -"rotate($self, /, other, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_to_eng_string__doc__, +"to_eng_string($self, /, context=None)\n" "--\n" "\n" -"Return the result of rotating the digits of the first operand by an amount specified by the second operand.\n" +"Convert to an engineering-type string.\n" +"\n" +"Engineering notation has an exponent which is a multiple of 3, so there are up\n" +"to 3 digits left of the decimal place. For example, Decimal(\'123E+1\') is\n" +"converted to Decimal(\'1.23E+3\').\n" "\n" -"The second operand must be an integer in the range -precision through\n" -"precision. The absolute value of the second operand gives the number of places\n" -"to rotate. If the second operand is positive then rotation is to the left;\n" -"otherwise rotation is to the right. The coefficient of the first operand is\n" -"padded on the left with zeros to length precision if necessary. The sign and\n" -"exponent of the first operand are unchanged."); +"The value of context.capitals determines whether the exponent sign is lower\n" +"or upper case. Otherwise, the context does not affect the operation."); -#define _DECIMAL_DECIMAL_ROTATE_METHODDEF \ - {"rotate", _PyCFunction_CAST(_decimal_Decimal_rotate), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_rotate__doc__}, +#define _DECIMAL_DECIMAL_TO_ENG_STRING_METHODDEF \ + {"to_eng_string", _PyCFunction_CAST(_decimal_Decimal_to_eng_string), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_eng_string__doc__}, static PyObject * -_decimal_Decimal_rotate_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context); static PyObject * -_decimal_Decimal_rotate(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_to_eng_string(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 2 + #define NUM_KEYWORDS 1 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD @@ -2271,7 +564,7 @@ _decimal_Decimal_rotate(PyObject *self, PyObject *const *args, Py_ssize_t nargs, } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(other), &_Py_ID(context), }, + .ob_item = { &_Py_ID(context), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2280,53 +573,57 @@ _decimal_Decimal_rotate(PyObject *self, PyObject *const *args, Py_ssize_t nargs, # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"other", "context", NULL}; + static const char * const _keywords[] = {"context", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "rotate", + .fname = "to_eng_string", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - PyObject *other; + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; PyObject *context = Py_None; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } - other = args[0]; if (!noptargs) { goto skip_optional_pos; } - context = args[1]; + context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_rotate_impl(self, other, context); + return_value = _decimal_Decimal_to_eng_string_impl(self, context); exit: return return_value; } -PyDoc_STRVAR(_decimal_Decimal_scaleb__doc__, -"scaleb($self, /, other, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_copy_sign__doc__, +"copy_sign($self, /, other, context=None)\n" "--\n" "\n" -"Return the first operand with the exponent adjusted the second.\n" +"Return a copy of *self* with the sign set to be the same as the sign of *other*.\n" +"\n" +"For example:\n" +"\n" +" >>> Decimal(\'2.3\').copy_sign(Decimal(\'-1.5\'))\n" +" Decimal(\'-2.3\')\n" "\n" -"Equivalently, return the first operand multiplied by 10**other. The second\n" -"operand must be an integer."); +"This operation is unaffected by context and is quiet: no flags are changed\n" +"and no rounding is performed. As an exception, the C version may raise\n" +"InvalidOperation if the second operand cannot be converted exactly."); -#define _DECIMAL_DECIMAL_SCALEB_METHODDEF \ - {"scaleb", _PyCFunction_CAST(_decimal_Decimal_scaleb), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_scaleb__doc__}, +#define _DECIMAL_DECIMAL_COPY_SIGN_METHODDEF \ + {"copy_sign", _PyCFunction_CAST(_decimal_Decimal_copy_sign), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_copy_sign__doc__}, static PyObject * -_decimal_Decimal_scaleb_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_copy_sign_impl(PyObject *self, PyObject *other, + PyObject *context); static PyObject * -_decimal_Decimal_scaleb(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_copy_sign(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -2352,7 +649,7 @@ _decimal_Decimal_scaleb(PyObject *self, PyObject *const *args, Py_ssize_t nargs, static const char * const _keywords[] = {"other", "context", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "scaleb", + .fname = "copy_sign", .kwtuple = KWTUPLE, }; #undef KWTUPLE @@ -2372,33 +669,31 @@ _decimal_Decimal_scaleb(PyObject *self, PyObject *const *args, Py_ssize_t nargs, } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_scaleb_impl(self, other, context); + return_value = _decimal_Decimal_copy_sign_impl(self, other, context); exit: return return_value; } -PyDoc_STRVAR(_decimal_Decimal_shift__doc__, -"shift($self, /, other, context=None)\n" +PyDoc_STRVAR(_decimal_Decimal_same_quantum__doc__, +"same_quantum($self, /, other, context=None)\n" "--\n" "\n" -"Return the result of shifting the digits of the first operand by an amount specified by the second operand.\n" +"Test whether self and other have the same exponent or whether both are NaN.\n" "\n" -"The second operand must be an integer in the range -precision through\n" -"precision. The absolute value of the second operand gives the number of places\n" -"to shift. If the second operand is positive, then the shift is to the left;\n" -"otherwise the shift is to the right. Digits shifted into the coefficient are\n" -"zeros. The sign and exponent of the first operand are unchanged."); +"This operation is unaffected by context and is quiet: no flags are changed\n" +"and no rounding is performed. As an exception, the C version may raise\n" +"InvalidOperation if the second operand cannot be converted exactly."); -#define _DECIMAL_DECIMAL_SHIFT_METHODDEF \ - {"shift", _PyCFunction_CAST(_decimal_Decimal_shift), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_shift__doc__}, +#define _DECIMAL_DECIMAL_SAME_QUANTUM_METHODDEF \ + {"same_quantum", _PyCFunction_CAST(_decimal_Decimal_same_quantum), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_same_quantum__doc__}, static PyObject * -_decimal_Decimal_shift_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_same_quantum_impl(PyObject *self, PyObject *other, + PyObject *context); static PyObject * -_decimal_Decimal_shift(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_same_quantum(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -2424,7 +719,7 @@ _decimal_Decimal_shift(PyObject *self, PyObject *const *args, Py_ssize_t nargs, static const char * const _keywords[] = {"other", "context", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .fname = "shift", + .fname = "same_quantum", .kwtuple = KWTUPLE, }; #undef KWTUPLE @@ -2444,7 +739,7 @@ _decimal_Decimal_shift(PyObject *self, PyObject *const *args, Py_ssize_t nargs, } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_shift_impl(self, other, context); + return_value = _decimal_Decimal_same_quantum_impl(self, other, context); exit: return return_value; @@ -2538,4 +833,4 @@ _decimal_Decimal_quantize(PyObject *self, PyObject *const *args, Py_ssize_t narg exit: return return_value; } -/*[clinic end generated code: output=a72c95123d7107e1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=641ac1cc6c557f2d input=a9049054013a1b77]*/ diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h index 4c878559b1f4c4..95106e3c2f56ea 100644 --- a/Modules/_decimal/docstrings.h +++ b/Modules/_decimal/docstrings.h @@ -57,6 +57,21 @@ context does not affect the conversion and is only passed to determine if\n\ the InvalidOperation trap is active.\n\ \n"); +PyDoc_STRVAR(doc_compare, +"compare($self, /, other, context=None)\n--\n\n\ +Compare self to other. Return a decimal value:\n\ +\n\ + a or b is a NaN ==> Decimal('NaN')\n\ + a < b ==> Decimal('-1')\n\ + a == b ==> Decimal('0')\n\ + a > b ==> Decimal('1')\n\ +\n"); + +PyDoc_STRVAR(doc_compare_signal, +"compare_signal($self, /, other, context=None)\n--\n\n\ +Identical to compare, except that all NaNs signal.\n\ +\n"); + PyDoc_STRVAR(doc_compare_total, "compare_total($self, /, other, context=None)\n--\n\n\ Compare two operands using their abstract representation rather than\n\ @@ -91,6 +106,13 @@ and no rounding is performed. As an exception, the C version may raise\n\ InvalidOperation if the second operand cannot be converted exactly.\n\ \n"); +PyDoc_STRVAR(doc_exp, +"exp($self, /, context=None)\n--\n\n\ +Return the value of the (natural) exponential function e**x at the given\n\ +number. The function always uses the ROUND_HALF_EVEN mode and the result\n\ +is correctly rounded.\n\ +\n"); + PyDoc_STRVAR(doc_fma, "fma($self, /, other, third, context=None)\n--\n\n\ Fused multiply-add. Return self*other+third with no rounding of the\n\ @@ -162,11 +184,36 @@ Return True if the argument is a (positive or negative) zero and False\n\ otherwise.\n\ \n"); +PyDoc_STRVAR(doc_ln, +"ln($self, /, context=None)\n--\n\n\ +Return the natural (base e) logarithm of the operand. The function always\n\ +uses the ROUND_HALF_EVEN mode and the result is correctly rounded.\n\ +\n"); + +PyDoc_STRVAR(doc_log10, +"log10($self, /, context=None)\n--\n\n\ +Return the base ten logarithm of the operand. The function always uses the\n\ +ROUND_HALF_EVEN mode and the result is correctly rounded.\n\ +\n"); + +PyDoc_STRVAR(doc_logb, +"logb($self, /, context=None)\n--\n\n\ +For a non-zero number, return the adjusted exponent of the operand as a\n\ +Decimal instance. If the operand is a zero, then Decimal('-Infinity') is\n\ +returned and the DivisionByZero condition is raised. If the operand is\n\ +an infinity then Decimal('Infinity') is returned.\n\ +\n"); + PyDoc_STRVAR(doc_logical_and, "logical_and($self, /, other, context=None)\n--\n\n\ Return the digit-wise 'and' of the two (logical) operands.\n\ \n"); +PyDoc_STRVAR(doc_logical_invert, +"logical_invert($self, /, context=None)\n--\n\n\ +Return the digit-wise inversion of the (logical) operand.\n\ +\n"); + PyDoc_STRVAR(doc_logical_or, "logical_or($self, /, other, context=None)\n--\n\n\ Return the digit-wise 'or' of the two (logical) operands.\n\ @@ -177,6 +224,72 @@ PyDoc_STRVAR(doc_logical_xor, Return the digit-wise 'exclusive or' of the two (logical) operands.\n\ \n"); +PyDoc_STRVAR(doc_max, +"max($self, /, other, context=None)\n--\n\n\ +Maximum of self and other. If one operand is a quiet NaN and the other is\n\ +numeric, the numeric operand is returned.\n\ +\n"); + +PyDoc_STRVAR(doc_max_mag, +"max_mag($self, /, other, context=None)\n--\n\n\ +Similar to the max() method, but the comparison is done using the absolute\n\ +values of the operands.\n\ +\n"); + +PyDoc_STRVAR(doc_min, +"min($self, /, other, context=None)\n--\n\n\ +Minimum of self and other. If one operand is a quiet NaN and the other is\n\ +numeric, the numeric operand is returned.\n\ +\n"); + +PyDoc_STRVAR(doc_min_mag, +"min_mag($self, /, other, context=None)\n--\n\n\ +Similar to the min() method, but the comparison is done using the absolute\n\ +values of the operands.\n\ +\n"); + +PyDoc_STRVAR(doc_next_minus, +"next_minus($self, /, context=None)\n--\n\n\ +Return the largest number representable in the given context (or in the\n\ +current default context if no context is given) that is smaller than the\n\ +given operand.\n\ +\n"); + +PyDoc_STRVAR(doc_next_plus, +"next_plus($self, /, context=None)\n--\n\n\ +Return the smallest number representable in the given context (or in the\n\ +current default context if no context is given) that is larger than the\n\ +given operand.\n\ +\n"); + +PyDoc_STRVAR(doc_next_toward, +"next_toward($self, /, other, context=None)\n--\n\n\ +If the two operands are unequal, return the number closest to the first\n\ +operand in the direction of the second operand. If both operands are\n\ +numerically equal, return a copy of the first operand with the sign set\n\ +to be the same as the sign of the second operand.\n\ +\n"); + +PyDoc_STRVAR(doc_normalize, +"normalize($self, /, context=None)\n--\n\n\ +Normalize the number by stripping the rightmost trailing zeros and\n\ +converting any result equal to Decimal('0') to Decimal('0e0'). Used\n\ +for producing canonical values for members of an equivalence class.\n\ +For example, Decimal('32.100') and Decimal('0.321000e+2') both normalize\n\ +to the equivalent value Decimal('32.1').\n\ +\n"); + +PyDoc_STRVAR(doc_remainder_near, +"remainder_near($self, /, other, context=None)\n--\n\n\ +Return the remainder from dividing self by other. This differs from\n\ +self % other in that the sign of the remainder is chosen so as to minimize\n\ +its absolute value. More precisely, the return value is self - n * other\n\ +where n is the integer nearest to the exact value of self / other, and\n\ +if two integers are equally near then the even one is chosen.\n\ +\n\ +If the result is zero then its sign will be the sign of self.\n\ +\n"); + PyDoc_STRVAR(doc_rotate, "rotate($self, /, other, context=None)\n--\n\n\ Return the result of rotating the digits of the first operand by an amount\n\ @@ -207,6 +320,20 @@ right. Digits shifted into the coefficient are zeros. The sign and exponent\n\ of the first operand are unchanged.\n\ \n"); +PyDoc_STRVAR(doc_sqrt, +"sqrt($self, /, context=None)\n--\n\n\ +Return the square root of the argument to full precision. The result is\n\ +correctly rounded using the ROUND_HALF_EVEN rounding mode.\n\ +\n"); + +PyDoc_STRVAR(doc_to_integral_value, +"to_integral_value($self, /, rounding=None, context=None)\n--\n\n\ +Round to the nearest integer without signaling Inexact or Rounded. The\n\ +rounding mode is determined by the rounding parameter if given, else by\n\ +the given context. If neither parameter is given, then the rounding mode\n\ +of the current default context is used.\n\ +\n"); + /******************************************************************************/ /* Context Object and Methods */ From 8b757da33ee19dc4ff472262577338aa0b7ddc03 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 11 Aug 2025 05:52:37 +0300 Subject: [PATCH 09/16] address review: rename some self --- Modules/_decimal/_decimal.c | 43 ++++++++++++++++------------ Modules/_decimal/clinic/_decimal.c.h | 28 +++++++++--------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index c48d712db4aed2..a2b51668b1e806 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -3921,6 +3921,7 @@ _decimal_Decimal_as_integer_ratio_impl(PyObject *self) /*[clinic input] _decimal.Decimal.to_integral_value + self as dec: self rounding: object = None context: object = None @@ -3932,15 +3933,15 @@ the current default context is used. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, +_decimal_Decimal_to_integral_value_impl(PyObject *dec, PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=7301465765f48b6b input=5778168222cadf71]*/ +/*[clinic end generated code: output=1517d948029dbecc input=0fd8dd3bc5248b21]*/ { PyObject *result; uint32_t status = 0; mpd_context_t workctx; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); @@ -3959,7 +3960,7 @@ _decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, return NULL; } - mpd_qround_to_int(MPD(result), MPD(self), &workctx, &status); + mpd_qround_to_int(MPD(result), MPD(dec), &workctx, &status); if (dec_addstatus(context, status)) { Py_DECREF(result); return NULL; @@ -3990,6 +3991,7 @@ _decimal_Decimal_to_integral_impl(PyObject *self, PyObject *rounding, /*[clinic input] _decimal.Decimal.to_integral_exact + self as dec: self rounding: object = None context: object = None @@ -4002,15 +4004,15 @@ rounding mode of the current default context is used. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, +_decimal_Decimal_to_integral_exact_impl(PyObject *dec, PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=8b004f9b45ac7746 input=edd30a9f06aed70b]*/ +/*[clinic end generated code: output=bfcd6d3ac47460d7 input=095a7cc7368dcfbb]*/ { PyObject *result; uint32_t status = 0; mpd_context_t workctx; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); @@ -4029,7 +4031,7 @@ _decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, return NULL; } - mpd_qround_to_intx(MPD(result), MPD(self), &workctx, &status); + mpd_qround_to_intx(MPD(result), MPD(dec), &workctx, &status); if (dec_addstatus(context, status)) { Py_DECREF(result); return NULL; @@ -4123,12 +4125,14 @@ PyDec_Round(PyObject *dec, PyObject *args) /*[clinic input] _decimal.Decimal.as_tuple + self as dec: self + Return a tuple representation of the number. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_as_tuple_impl(PyObject *self) -/*[clinic end generated code: output=c6e8e2420c515eca input=e26f2151d78ff59d]*/ +_decimal_Decimal_as_tuple_impl(PyObject *dec) +/*[clinic end generated code: output=b1a619dfdbf89220 input=e334c01206f0e62e]*/ { PyObject *result = NULL; PyObject *sign = NULL; @@ -4140,13 +4144,13 @@ _decimal_Decimal_as_tuple_impl(PyObject *self) Py_ssize_t intlen, i; - x = mpd_qncopy(MPD(self)); + x = mpd_qncopy(MPD(dec)); if (x == NULL) { PyErr_NoMemory(); goto out; } - sign = PyLong_FromUnsignedLong(mpd_sign(MPD(self))); + sign = PyLong_FromUnsignedLong(mpd_sign(MPD(dec))); if (sign == NULL) { goto out; } @@ -4167,7 +4171,7 @@ _decimal_Decimal_as_tuple_impl(PyObject *self) expt = PyUnicode_FromString(mpd_isqnan(x)?"n":"N"); } else { - expt = PyLong_FromSsize_t(MPD(self)->exp); + expt = PyLong_FromSsize_t(MPD(dec)->exp); } if (expt == NULL) { goto out; @@ -4208,7 +4212,7 @@ _decimal_Decimal_as_tuple_impl(PyObject *self) } } - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); result = PyObject_CallFunctionObjArgs((PyObject *)state->DecimalTuple, sign, coeff, expt, NULL); @@ -4930,6 +4934,7 @@ Dec_BinaryFuncVA(mpd_qshift) /*[clinic input] _decimal.Decimal.quantize + self as v: self exp as w: object rounding: object = None context: object = None @@ -4954,16 +4959,16 @@ argument is given, the rounding mode of the current thread's context is used. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_quantize_impl(PyObject *self, PyObject *w, - PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=5e84581f96dc685c input=2053ebf488a665dc]*/ +_decimal_Decimal_quantize_impl(PyObject *v, PyObject *w, PyObject *rounding, + PyObject *context) +/*[clinic end generated code: output=6ebc907ee3000c1f input=223b9dd92655b4bd]*/ { PyObject *a, *b; PyObject *result; uint32_t status = 0; mpd_context_t workctx; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = get_module_state_by_def(Py_TYPE(v)); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); @@ -4977,7 +4982,7 @@ _decimal_Decimal_quantize_impl(PyObject *self, PyObject *w, } } - CONVERT_BINOP_RAISE(&a, &b, self, w, context); + CONVERT_BINOP_RAISE(&a, &b, v, w, context); result = dec_alloc(state); if (result == NULL) { diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index de805437724df0..07400ec07e520c 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -106,11 +106,11 @@ PyDoc_STRVAR(_decimal_Decimal_to_integral_value__doc__, {"to_integral_value", _PyCFunction_CAST(_decimal_Decimal_to_integral_value), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_value__doc__}, static PyObject * -_decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, +_decimal_Decimal_to_integral_value_impl(PyObject *dec, PyObject *rounding, PyObject *context); static PyObject * -_decimal_Decimal_to_integral_value(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_to_integral_value(PyObject *dec, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -161,7 +161,7 @@ _decimal_Decimal_to_integral_value(PyObject *self, PyObject *const *args, Py_ssi } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_to_integral_value_impl(self, rounding, context); + return_value = _decimal_Decimal_to_integral_value_impl(dec, rounding, context); exit: return return_value; @@ -255,11 +255,11 @@ PyDoc_STRVAR(_decimal_Decimal_to_integral_exact__doc__, {"to_integral_exact", _PyCFunction_CAST(_decimal_Decimal_to_integral_exact), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_exact__doc__}, static PyObject * -_decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, +_decimal_Decimal_to_integral_exact_impl(PyObject *dec, PyObject *rounding, PyObject *context); static PyObject * -_decimal_Decimal_to_integral_exact(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_to_integral_exact(PyObject *dec, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -310,7 +310,7 @@ _decimal_Decimal_to_integral_exact(PyObject *self, PyObject *const *args, Py_ssi } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_to_integral_exact_impl(self, rounding, context); + return_value = _decimal_Decimal_to_integral_exact_impl(dec, rounding, context); exit: return return_value; @@ -326,12 +326,12 @@ PyDoc_STRVAR(_decimal_Decimal_as_tuple__doc__, {"as_tuple", (PyCFunction)_decimal_Decimal_as_tuple, METH_NOARGS, _decimal_Decimal_as_tuple__doc__}, static PyObject * -_decimal_Decimal_as_tuple_impl(PyObject *self); +_decimal_Decimal_as_tuple_impl(PyObject *dec); static PyObject * -_decimal_Decimal_as_tuple(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal_as_tuple(PyObject *dec, PyObject *Py_UNUSED(ignored)) { - return _decimal_Decimal_as_tuple_impl(self); + return _decimal_Decimal_as_tuple_impl(dec); } PyDoc_STRVAR(_decimal_Decimal_adjusted__doc__, @@ -771,11 +771,11 @@ PyDoc_STRVAR(_decimal_Decimal_quantize__doc__, {"quantize", _PyCFunction_CAST(_decimal_Decimal_quantize), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_quantize__doc__}, static PyObject * -_decimal_Decimal_quantize_impl(PyObject *self, PyObject *w, - PyObject *rounding, PyObject *context); +_decimal_Decimal_quantize_impl(PyObject *v, PyObject *w, PyObject *rounding, + PyObject *context); static PyObject * -_decimal_Decimal_quantize(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_quantize(PyObject *v, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -828,9 +828,9 @@ _decimal_Decimal_quantize(PyObject *self, PyObject *const *args, Py_ssize_t narg } context = args[2]; skip_optional_pos: - return_value = _decimal_Decimal_quantize_impl(self, w, rounding, context); + return_value = _decimal_Decimal_quantize_impl(v, w, rounding, context); exit: return return_value; } -/*[clinic end generated code: output=641ac1cc6c557f2d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9dca0c61c40ce23b input=a9049054013a1b77]*/ From 306980ae40de285e6fd53f86e176a4fd8d04a711 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 11 Aug 2025 05:53:28 +0300 Subject: [PATCH 10/16] address review: remove old doc_to_integral_value --- Modules/_decimal/docstrings.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h index 95106e3c2f56ea..bd1c1d5295d717 100644 --- a/Modules/_decimal/docstrings.h +++ b/Modules/_decimal/docstrings.h @@ -326,14 +326,6 @@ Return the square root of the argument to full precision. The result is\n\ correctly rounded using the ROUND_HALF_EVEN rounding mode.\n\ \n"); -PyDoc_STRVAR(doc_to_integral_value, -"to_integral_value($self, /, rounding=None, context=None)\n--\n\n\ -Round to the nearest integer without signaling Inexact or Rounded. The\n\ -rounding mode is determined by the rounding parameter if given, else by\n\ -the given context. If neither parameter is given, then the rounding mode\n\ -of the current default context is used.\n\ -\n"); - /******************************************************************************/ /* Context Object and Methods */ From 98b0e38204b786555b252883692a3de7ec2fa464 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 11 Aug 2025 10:22:01 +0300 Subject: [PATCH 11/16] add news --- .../next/Library/2025-08-11-10-21-57.gh-issue-73487.tof66A.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-08-11-10-21-57.gh-issue-73487.tof66A.rst diff --git a/Misc/NEWS.d/next/Library/2025-08-11-10-21-57.gh-issue-73487.tof66A.rst b/Misc/NEWS.d/next/Library/2025-08-11-10-21-57.gh-issue-73487.tof66A.rst new file mode 100644 index 00000000000000..32aadc8d7078f1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-08-11-10-21-57.gh-issue-73487.tof66A.rst @@ -0,0 +1,2 @@ +The :mod:`decimal` converted to use the Argument Clinic, that speedup +processing arguments up to 1.5x faster. Patch by Sergey B Kirpichev. From 15860bd1baf7a3e9cd322cd80b28b120ea20b8fc Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 12 Aug 2025 07:58:23 +0300 Subject: [PATCH 12/16] drop redundant comments --- Modules/_decimal/_decimal.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index a2b51668b1e806..3fc6d9030fc916 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -2877,8 +2877,6 @@ PyDecType_FromSequenceExact(PyTypeObject *type, PyObject *v, #define PyDec_FromSequenceExact(st, sequence, context) \ PyDecType_FromSequenceExact((st)->PyDec_Type, sequence, context) -/* class method */ - /*[clinic input] @classmethod _decimal.Decimal.from_float @@ -2947,8 +2945,6 @@ PyDecType_FromNumberExact(PyTypeObject *type, PyObject *v, PyObject *context) } } -/* class method */ - /*[clinic input] @classmethod _decimal.Decimal.from_number @@ -3803,8 +3799,6 @@ dec_as_long(PyObject *dec, PyObject *context, int round) return PyLongWriter_Finish(writer); } -/* Convert a Decimal to its exact integer ratio representation. */ - /*[clinic input] _decimal.Decimal.as_integer_ratio @@ -4120,8 +4114,6 @@ PyDec_Round(PyObject *dec, PyObject *args) } } -/* Return the DecimalTuple representation of a PyDecObject. */ - /*[clinic input] _decimal.Decimal.as_tuple From a4f7f0c54449ad4de0e53bde9c269429101b2aa9 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 13 Aug 2025 05:27:42 +0300 Subject: [PATCH 13/16] adjust docstrings after #137624 --- Modules/_decimal/_decimal.c | 123 +++++++++++++++------------ Modules/_decimal/clinic/_decimal.c.h | 101 ++++++++++++---------- 2 files changed, 125 insertions(+), 99 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 3fc6d9030fc916..572f610c2f4be2 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -3921,15 +3921,15 @@ _decimal.Decimal.to_integral_value Round to the nearest integer without signaling Inexact or Rounded. -The rounding mode is determined by the rounding parameter if given, else by -the given context. If neither parameter is given, then the rounding mode of -the current default context is used. +The rounding mode is determined by the rounding parameter if given, +else by the given context. If neither parameter is given, then the +rounding mode of the current default context is used. [clinic start generated code]*/ static PyObject * _decimal_Decimal_to_integral_value_impl(PyObject *dec, PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=1517d948029dbecc input=0fd8dd3bc5248b21]*/ +/*[clinic end generated code: output=1517d948029dbecc input=0afac3e278bdb511]*/ { PyObject *result; uint32_t status = 0; @@ -3971,13 +3971,14 @@ _decimal.Decimal.to_integral Identical to the to_integral_value() method. -The to_integral() name has been kept for compatibility with older versions. +The to_integral() name has been kept for compatibility with older +versions. [clinic start generated code]*/ static PyObject * _decimal_Decimal_to_integral_impl(PyObject *self, PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=a0c7188686ee7f5c input=a57d62d1d29aed1b]*/ +/*[clinic end generated code: output=a0c7188686ee7f5c input=8eac6def038d13b9]*/ { return _decimal_Decimal_to_integral_value_impl(self, rounding, context); } @@ -3991,16 +3992,16 @@ _decimal.Decimal.to_integral_exact Round to the nearest integer. -Decimal.to_integral_exact() signals Inexact or Rounded as appropriate if -rounding occurs. The rounding mode is determined by the rounding parameter -if given, else by the given context. If neither parameter is given, then the -rounding mode of the current default context is used. +Decimal.to_integral_exact() signals Inexact or Rounded as appropriate +if rounding occurs. The rounding mode is determined by the rounding +parameter if given, else by the given context. If neither parameter is +given, then the rounding mode of the current default context is used. [clinic start generated code]*/ static PyObject * _decimal_Decimal_to_integral_exact_impl(PyObject *dec, PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=bfcd6d3ac47460d7 input=095a7cc7368dcfbb]*/ +/*[clinic end generated code: output=bfcd6d3ac47460d7 input=8cb083bc2b4fb1c3]*/ { PyObject *result; uint32_t status = 0; @@ -4612,12 +4613,12 @@ Dec_BoolFuncVA(mpd_issubnormal) /*[clinic input] _decimal.Decimal.adjusted -Return the adjusted exponent of the number. Defined as exp + digits - 1. +Return the adjusted exponent (exp + digits - 1) of the number. [clinic start generated code]*/ static PyObject * _decimal_Decimal_adjusted_impl(PyObject *self) -/*[clinic end generated code: output=21ea2c9f23994c52 input=775a14d44f31f787]*/ +/*[clinic end generated code: output=21ea2c9f23994c52 input=8ba2029d8d906b18]*/ { mpd_ssize_t retval; @@ -4636,13 +4637,13 @@ _decimal.Decimal.canonical Return the canonical encoding of the argument. -Currently, the encoding of a Decimal instance is always canonical, so this -operation returns its argument unchanged. +Currently, the encoding of a Decimal instance is always canonical, +so this operation returns its argument unchanged. [clinic start generated code]*/ static PyObject * _decimal_Decimal_canonical_impl(PyObject *self) -/*[clinic end generated code: output=3cbeb47d91e6da2d input=9089f031f530238e]*/ +/*[clinic end generated code: output=3cbeb47d91e6da2d input=8a4719d14c52d521]*/ { return Py_NewRef(self); } @@ -4696,13 +4697,13 @@ _decimal.Decimal.copy_abs Return the absolute value of the argument. -This operation is unaffected by context and is quiet: no flags are changed and -no rounding is performed. +This operation is unaffected by context and is quiet: no flags are +changed and no rounding is performed. [clinic start generated code]*/ static PyObject * _decimal_Decimal_copy_abs_impl(PyObject *self) -/*[clinic end generated code: output=fff53742cca94d70 input=fa96ebbfd9191e72]*/ +/*[clinic end generated code: output=fff53742cca94d70 input=a263c2e71d421f1b]*/ { PyObject *result; uint32_t status = 0; @@ -4727,13 +4728,13 @@ _decimal.Decimal.copy_negate Return the negation of the argument. -This operation is unaffected by context and is quiet: no flags are changed and -no rounding is performed. +This operation is unaffected by context and is quiet: no flags are +changed and no rounding is performed. [clinic start generated code]*/ static PyObject * _decimal_Decimal_copy_negate_impl(PyObject *self) -/*[clinic end generated code: output=8551bc26dbc5d01d input=2ca2ce000154fca0]*/ +/*[clinic end generated code: output=8551bc26dbc5d01d input=13d47ed3a5d228b1]*/ { PyObject *result; uint32_t status = 0; @@ -4767,12 +4768,16 @@ Return a string describing the class of the operand. The returned value is one of the following ten strings: * '-Infinity', indicating that the operand is negative infinity. - * '-Normal', indicating that the operand is a negative normal number. - * '-Subnormal', indicating that the operand is negative and subnormal. + * '-Normal', indicating that the operand is a negative normal + number. + * '-Subnormal', indicating that the operand is negative and + subnormal. * '-Zero', indicating that the operand is a negative zero. * '+Zero', indicating that the operand is a positive zero. - * '+Subnormal', indicating that the operand is positive and subnormal. - * '+Normal', indicating that the operand is a positive normal number. + * '+Subnormal', indicating that the operand is positive and + subnormal. + * '+Normal', indicating that the operand is a positive normal + number. * '+Infinity', indicating that the operand is positive infinity. * 'NaN', indicating that the operand is a quiet NaN (Not a Number). * 'sNaN', indicating that the operand is a signaling NaN. @@ -4780,7 +4785,7 @@ The returned value is one of the following ten strings: static PyObject * _decimal_Decimal_number_class_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=3044cd45966b4949 input=80cc37edb4fd663f]*/ +/*[clinic end generated code: output=3044cd45966b4949 input=f3d6cdda603e8b89]*/ { const char *cp; @@ -4798,17 +4803,18 @@ _decimal.Decimal.to_eng_string Convert to an engineering-type string. -Engineering notation has an exponent which is a multiple of 3, so there are up -to 3 digits left of the decimal place. For example, Decimal('123E+1') is -converted to Decimal('1.23E+3'). +Engineering notation has an exponent which is a multiple of 3, so there +are up to 3 digits left of the decimal place. For example, +Decimal('123E+1') is converted to Decimal('1.23E+3'). -The value of context.capitals determines whether the exponent sign is lower -or upper case. Otherwise, the context does not affect the operation. +The value of context.capitals determines whether the exponent sign is +lower or upper case. Otherwise, the context does not affect the +operation. [clinic start generated code]*/ static PyObject * _decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=d386194c25ffffa7 input=36436cb7973dd5d0]*/ +/*[clinic end generated code: output=d386194c25ffffa7 input=2e13e7c7c1bad2ad]*/ { PyObject *result; mpd_ssize_t size; @@ -4839,22 +4845,23 @@ _decimal.Decimal.copy_sign other: object context: object = None -Return a copy of *self* with the sign set to be the same as the sign of *other*. +Return a copy of *self* with the sign of *other*. For example: >>> Decimal('2.3').copy_sign(Decimal('-1.5')) Decimal('-2.3') -This operation is unaffected by context and is quiet: no flags are changed -and no rounding is performed. As an exception, the C version may raise -InvalidOperation if the second operand cannot be converted exactly. +This operation is unaffected by context and is quiet: no flags are +changed and no rounding is performed. As an exception, the C version +may raise InvalidOperation if the second operand cannot be converted +exactly. [clinic start generated code]*/ static PyObject * _decimal_Decimal_copy_sign_impl(PyObject *self, PyObject *other, PyObject *context) -/*[clinic end generated code: output=72c62177763e012e input=96b620d142ed80a9]*/ +/*[clinic end generated code: output=72c62177763e012e input=8410238d533a06eb]*/ { PyObject *a, *b; PyObject *result; @@ -4888,17 +4895,18 @@ _decimal.Decimal.same_quantum other: object context: object = None -Test whether self and other have the same exponent or whether both are NaN. +Test whether self and other have the same exponent or both are NaN. -This operation is unaffected by context and is quiet: no flags are changed -and no rounding is performed. As an exception, the C version may raise -InvalidOperation if the second operand cannot be converted exactly. +This operation is unaffected by context and is quiet: no flags are +changed and no rounding is performed. As an exception, the C version +may raise InvalidOperation if the second operand cannot be converted +exactly. [clinic start generated code]*/ static PyObject * _decimal_Decimal_same_quantum_impl(PyObject *self, PyObject *other, PyObject *context) -/*[clinic end generated code: output=c0a3a046c662a7e2 input=d583092dec58453e]*/ +/*[clinic end generated code: output=c0a3a046c662a7e2 input=3ae45df81d6edb73]*/ { PyObject *a, *b; PyObject *result; @@ -4931,29 +4939,34 @@ _decimal.Decimal.quantize rounding: object = None context: object = None -Return a value equal to *self* after rounding, with the exponent of *other*. +Quantize *self* so its exponent is the same as that of *exp*. + +Return a value equal to *self* after rounding, with the exponent +of *exp*. >>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414') -Unlike other operations, if the length of the coefficient after the quantize -operation would be greater than precision, then an InvalidOperation is signaled. -This guarantees that, unless there is an error condition, the quantized exponent -is always equal to that of the right-hand operand. +Unlike other operations, if the length of the coefficient after the +quantize operation would be greater than precision, then an +InvalidOperation is signaled. This guarantees that, unless there +is an error condition, the quantized exponent is always equal to +that of the right-hand operand. -Also unlike other operations, quantize never signals Underflow, even if the -result is subnormal and inexact. +Also unlike other operations, quantize never signals Underflow, even +if the result is subnormal and inexact. -If the exponent of the second operand is larger than that of the first, then -rounding may be necessary. In this case, the rounding mode is determined by the -rounding argument if given, else by the given context argument; if neither -argument is given, the rounding mode of the current thread's context is used. +If the exponent of the second operand is larger than that of the first, +then rounding may be necessary. In this case, the rounding mode is +determined by the rounding argument if given, else by the given context +argument; if neither argument is given, the rounding mode of the +current thread's context is used. [clinic start generated code]*/ static PyObject * _decimal_Decimal_quantize_impl(PyObject *v, PyObject *w, PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=6ebc907ee3000c1f input=223b9dd92655b4bd]*/ +/*[clinic end generated code: output=6ebc907ee3000c1f input=d1dc20057afe0c7e]*/ { PyObject *a, *b; PyObject *result; diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index 07400ec07e520c..b5d15b2c334071 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -98,9 +98,9 @@ PyDoc_STRVAR(_decimal_Decimal_to_integral_value__doc__, "\n" "Round to the nearest integer without signaling Inexact or Rounded.\n" "\n" -"The rounding mode is determined by the rounding parameter if given, else by\n" -"the given context. If neither parameter is given, then the rounding mode of\n" -"the current default context is used."); +"The rounding mode is determined by the rounding parameter if given,\n" +"else by the given context. If neither parameter is given, then the\n" +"rounding mode of the current default context is used."); #define _DECIMAL_DECIMAL_TO_INTEGRAL_VALUE_METHODDEF \ {"to_integral_value", _PyCFunction_CAST(_decimal_Decimal_to_integral_value), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_value__doc__}, @@ -173,7 +173,8 @@ PyDoc_STRVAR(_decimal_Decimal_to_integral__doc__, "\n" "Identical to the to_integral_value() method.\n" "\n" -"The to_integral() name has been kept for compatibility with older versions."); +"The to_integral() name has been kept for compatibility with older\n" +"versions."); #define _DECIMAL_DECIMAL_TO_INTEGRAL_METHODDEF \ {"to_integral", _PyCFunction_CAST(_decimal_Decimal_to_integral), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral__doc__}, @@ -246,10 +247,10 @@ PyDoc_STRVAR(_decimal_Decimal_to_integral_exact__doc__, "\n" "Round to the nearest integer.\n" "\n" -"Decimal.to_integral_exact() signals Inexact or Rounded as appropriate if\n" -"rounding occurs. The rounding mode is determined by the rounding parameter\n" -"if given, else by the given context. If neither parameter is given, then the\n" -"rounding mode of the current default context is used."); +"Decimal.to_integral_exact() signals Inexact or Rounded as appropriate\n" +"if rounding occurs. The rounding mode is determined by the rounding\n" +"parameter if given, else by the given context. If neither parameter is\n" +"given, then the rounding mode of the current default context is used."); #define _DECIMAL_DECIMAL_TO_INTEGRAL_EXACT_METHODDEF \ {"to_integral_exact", _PyCFunction_CAST(_decimal_Decimal_to_integral_exact), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_exact__doc__}, @@ -338,7 +339,7 @@ PyDoc_STRVAR(_decimal_Decimal_adjusted__doc__, "adjusted($self, /)\n" "--\n" "\n" -"Return the adjusted exponent of the number. Defined as exp + digits - 1."); +"Return the adjusted exponent (exp + digits - 1) of the number."); #define _DECIMAL_DECIMAL_ADJUSTED_METHODDEF \ {"adjusted", (PyCFunction)_decimal_Decimal_adjusted, METH_NOARGS, _decimal_Decimal_adjusted__doc__}, @@ -358,8 +359,8 @@ PyDoc_STRVAR(_decimal_Decimal_canonical__doc__, "\n" "Return the canonical encoding of the argument.\n" "\n" -"Currently, the encoding of a Decimal instance is always canonical, so this\n" -"operation returns its argument unchanged."); +"Currently, the encoding of a Decimal instance is always canonical,\n" +"so this operation returns its argument unchanged."); #define _DECIMAL_DECIMAL_CANONICAL_METHODDEF \ {"canonical", (PyCFunction)_decimal_Decimal_canonical, METH_NOARGS, _decimal_Decimal_canonical__doc__}, @@ -418,8 +419,8 @@ PyDoc_STRVAR(_decimal_Decimal_copy_abs__doc__, "\n" "Return the absolute value of the argument.\n" "\n" -"This operation is unaffected by context and is quiet: no flags are changed and\n" -"no rounding is performed."); +"This operation is unaffected by context and is quiet: no flags are\n" +"changed and no rounding is performed."); #define _DECIMAL_DECIMAL_COPY_ABS_METHODDEF \ {"copy_abs", (PyCFunction)_decimal_Decimal_copy_abs, METH_NOARGS, _decimal_Decimal_copy_abs__doc__}, @@ -439,8 +440,8 @@ PyDoc_STRVAR(_decimal_Decimal_copy_negate__doc__, "\n" "Return the negation of the argument.\n" "\n" -"This operation is unaffected by context and is quiet: no flags are changed and\n" -"no rounding is performed."); +"This operation is unaffected by context and is quiet: no flags are\n" +"changed and no rounding is performed."); #define _DECIMAL_DECIMAL_COPY_NEGATE_METHODDEF \ {"copy_negate", (PyCFunction)_decimal_Decimal_copy_negate, METH_NOARGS, _decimal_Decimal_copy_negate__doc__}, @@ -463,12 +464,16 @@ PyDoc_STRVAR(_decimal_Decimal_number_class__doc__, "The returned value is one of the following ten strings:\n" "\n" " * \'-Infinity\', indicating that the operand is negative infinity.\n" -" * \'-Normal\', indicating that the operand is a negative normal number.\n" -" * \'-Subnormal\', indicating that the operand is negative and subnormal.\n" +" * \'-Normal\', indicating that the operand is a negative normal\n" +" number.\n" +" * \'-Subnormal\', indicating that the operand is negative and\n" +" subnormal.\n" " * \'-Zero\', indicating that the operand is a negative zero.\n" " * \'+Zero\', indicating that the operand is a positive zero.\n" -" * \'+Subnormal\', indicating that the operand is positive and subnormal.\n" -" * \'+Normal\', indicating that the operand is a positive normal number.\n" +" * \'+Subnormal\', indicating that the operand is positive and\n" +" subnormal.\n" +" * \'+Normal\', indicating that the operand is a positive normal\n" +" number.\n" " * \'+Infinity\', indicating that the operand is positive infinity.\n" " * \'NaN\', indicating that the operand is a quiet NaN (Not a Number).\n" " * \'sNaN\', indicating that the operand is a signaling NaN."); @@ -536,12 +541,13 @@ PyDoc_STRVAR(_decimal_Decimal_to_eng_string__doc__, "\n" "Convert to an engineering-type string.\n" "\n" -"Engineering notation has an exponent which is a multiple of 3, so there are up\n" -"to 3 digits left of the decimal place. For example, Decimal(\'123E+1\') is\n" -"converted to Decimal(\'1.23E+3\').\n" +"Engineering notation has an exponent which is a multiple of 3, so there\n" +"are up to 3 digits left of the decimal place. For example,\n" +"Decimal(\'123E+1\') is converted to Decimal(\'1.23E+3\').\n" "\n" -"The value of context.capitals determines whether the exponent sign is lower\n" -"or upper case. Otherwise, the context does not affect the operation."); +"The value of context.capitals determines whether the exponent sign is\n" +"lower or upper case. Otherwise, the context does not affect the\n" +"operation."); #define _DECIMAL_DECIMAL_TO_ENG_STRING_METHODDEF \ {"to_eng_string", _PyCFunction_CAST(_decimal_Decimal_to_eng_string), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_eng_string__doc__}, @@ -604,16 +610,17 @@ PyDoc_STRVAR(_decimal_Decimal_copy_sign__doc__, "copy_sign($self, /, other, context=None)\n" "--\n" "\n" -"Return a copy of *self* with the sign set to be the same as the sign of *other*.\n" +"Return a copy of *self* with the sign of *other*.\n" "\n" "For example:\n" "\n" " >>> Decimal(\'2.3\').copy_sign(Decimal(\'-1.5\'))\n" " Decimal(\'-2.3\')\n" "\n" -"This operation is unaffected by context and is quiet: no flags are changed\n" -"and no rounding is performed. As an exception, the C version may raise\n" -"InvalidOperation if the second operand cannot be converted exactly."); +"This operation is unaffected by context and is quiet: no flags are\n" +"changed and no rounding is performed. As an exception, the C version\n" +"may raise InvalidOperation if the second operand cannot be converted\n" +"exactly."); #define _DECIMAL_DECIMAL_COPY_SIGN_METHODDEF \ {"copy_sign", _PyCFunction_CAST(_decimal_Decimal_copy_sign), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_copy_sign__doc__}, @@ -679,11 +686,12 @@ PyDoc_STRVAR(_decimal_Decimal_same_quantum__doc__, "same_quantum($self, /, other, context=None)\n" "--\n" "\n" -"Test whether self and other have the same exponent or whether both are NaN.\n" +"Test whether self and other have the same exponent or both are NaN.\n" "\n" -"This operation is unaffected by context and is quiet: no flags are changed\n" -"and no rounding is performed. As an exception, the C version may raise\n" -"InvalidOperation if the second operand cannot be converted exactly."); +"This operation is unaffected by context and is quiet: no flags are\n" +"changed and no rounding is performed. As an exception, the C version\n" +"may raise InvalidOperation if the second operand cannot be converted\n" +"exactly."); #define _DECIMAL_DECIMAL_SAME_QUANTUM_METHODDEF \ {"same_quantum", _PyCFunction_CAST(_decimal_Decimal_same_quantum), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_same_quantum__doc__}, @@ -749,23 +757,28 @@ PyDoc_STRVAR(_decimal_Decimal_quantize__doc__, "quantize($self, /, exp, rounding=None, context=None)\n" "--\n" "\n" -"Return a value equal to *self* after rounding, with the exponent of *other*.\n" +"Quantize *self* so its exponent is the same as that of *exp*.\n" +"\n" +"Return a value equal to *self* after rounding, with the exponent\n" +"of *exp*.\n" "\n" " >>> Decimal(\'1.41421356\').quantize(Decimal(\'1.000\'))\n" " Decimal(\'1.414\')\n" "\n" -"Unlike other operations, if the length of the coefficient after the quantize\n" -"operation would be greater than precision, then an InvalidOperation is signaled.\n" -"This guarantees that, unless there is an error condition, the quantized exponent\n" -"is always equal to that of the right-hand operand.\n" +"Unlike other operations, if the length of the coefficient after the\n" +"quantize operation would be greater than precision, then an\n" +"InvalidOperation is signaled. This guarantees that, unless there\n" +"is an error condition, the quantized exponent is always equal to\n" +"that of the right-hand operand.\n" "\n" -"Also unlike other operations, quantize never signals Underflow, even if the\n" -"result is subnormal and inexact.\n" +"Also unlike other operations, quantize never signals Underflow, even\n" +"if the result is subnormal and inexact.\n" "\n" -"If the exponent of the second operand is larger than that of the first, then\n" -"rounding may be necessary. In this case, the rounding mode is determined by the\n" -"rounding argument if given, else by the given context argument; if neither\n" -"argument is given, the rounding mode of the current thread\'s context is used."); +"If the exponent of the second operand is larger than that of the first,\n" +"then rounding may be necessary. In this case, the rounding mode is\n" +"determined by the rounding argument if given, else by the given context\n" +"argument; if neither argument is given, the rounding mode of the\n" +"current thread\'s context is used."); #define _DECIMAL_DECIMAL_QUANTIZE_METHODDEF \ {"quantize", _PyCFunction_CAST(_decimal_Decimal_quantize), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_quantize__doc__}, @@ -833,4 +846,4 @@ _decimal_Decimal_quantize(PyObject *v, PyObject *const *args, Py_ssize_t nargs, exit: return return_value; } -/*[clinic end generated code: output=9dca0c61c40ce23b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=71f76aa153a96808 input=a9049054013a1b77]*/ From 7ca03bdb8413d235d6edb2fcb71727312c55e9f7 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 13 Aug 2025 05:28:46 +0300 Subject: [PATCH 14/16] Revert "add news" This reverts commit 98b0e38204b786555b252883692a3de7ec2fa464. --- .../next/Library/2025-08-11-10-21-57.gh-issue-73487.tof66A.rst | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2025-08-11-10-21-57.gh-issue-73487.tof66A.rst diff --git a/Misc/NEWS.d/next/Library/2025-08-11-10-21-57.gh-issue-73487.tof66A.rst b/Misc/NEWS.d/next/Library/2025-08-11-10-21-57.gh-issue-73487.tof66A.rst deleted file mode 100644 index 32aadc8d7078f1..00000000000000 --- a/Misc/NEWS.d/next/Library/2025-08-11-10-21-57.gh-issue-73487.tof66A.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :mod:`decimal` converted to use the Argument Clinic, that speedup -processing arguments up to 1.5x faster. Patch by Sergey B Kirpichev. From ab6239148d54f86d9946b65708dbc560c59f3f8a Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 13 Aug 2025 10:50:32 +0300 Subject: [PATCH 15/16] address review: re-add news (don't mention AC now) :) --- .../next/Library/2025-08-13-10-50-22.gh-issue-73487.DUHbBq.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-08-13-10-50-22.gh-issue-73487.DUHbBq.rst diff --git a/Misc/NEWS.d/next/Library/2025-08-13-10-50-22.gh-issue-73487.DUHbBq.rst b/Misc/NEWS.d/next/Library/2025-08-13-10-50-22.gh-issue-73487.DUHbBq.rst new file mode 100644 index 00000000000000..8cca50d91cd198 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-08-13-10-50-22.gh-issue-73487.DUHbBq.rst @@ -0,0 +1,3 @@ +Speedup processing arguments (up to 1.5x) in the :mod:`decimal` module +methods, that now using :c:macro:`METH_FASTCALL` calling convention. Patch +by Sergey B Kirpichev. From ec221f1e727f5538c899f15acd50abefbff4c5a7 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 13 Aug 2025 10:54:32 +0300 Subject: [PATCH 16/16] Revert "address review: rename some self" This reverts commit 8b757da33ee19dc4ff472262577338aa0b7ddc03. --- Modules/_decimal/_decimal.c | 43 ++++++++++++---------------- Modules/_decimal/clinic/_decimal.c.h | 28 +++++++++--------- 2 files changed, 33 insertions(+), 38 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 572f610c2f4be2..46cedf83df1f00 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -3915,7 +3915,6 @@ _decimal_Decimal_as_integer_ratio_impl(PyObject *self) /*[clinic input] _decimal.Decimal.to_integral_value - self as dec: self rounding: object = None context: object = None @@ -3927,15 +3926,15 @@ rounding mode of the current default context is used. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_to_integral_value_impl(PyObject *dec, PyObject *rounding, +_decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=1517d948029dbecc input=0afac3e278bdb511]*/ +/*[clinic end generated code: output=7301465765f48b6b input=04e2312d5ed19f77]*/ { PyObject *result; uint32_t status = 0; mpd_context_t workctx; - decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); @@ -3954,7 +3953,7 @@ _decimal_Decimal_to_integral_value_impl(PyObject *dec, PyObject *rounding, return NULL; } - mpd_qround_to_int(MPD(result), MPD(dec), &workctx, &status); + mpd_qround_to_int(MPD(result), MPD(self), &workctx, &status); if (dec_addstatus(context, status)) { Py_DECREF(result); return NULL; @@ -3986,7 +3985,6 @@ _decimal_Decimal_to_integral_impl(PyObject *self, PyObject *rounding, /*[clinic input] _decimal.Decimal.to_integral_exact - self as dec: self rounding: object = None context: object = None @@ -3999,15 +3997,15 @@ given, then the rounding mode of the current default context is used. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_to_integral_exact_impl(PyObject *dec, PyObject *rounding, +_decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=bfcd6d3ac47460d7 input=8cb083bc2b4fb1c3]*/ +/*[clinic end generated code: output=8b004f9b45ac7746 input=c290166f59c1d6ab]*/ { PyObject *result; uint32_t status = 0; mpd_context_t workctx; - decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); @@ -4026,7 +4024,7 @@ _decimal_Decimal_to_integral_exact_impl(PyObject *dec, PyObject *rounding, return NULL; } - mpd_qround_to_intx(MPD(result), MPD(dec), &workctx, &status); + mpd_qround_to_intx(MPD(result), MPD(self), &workctx, &status); if (dec_addstatus(context, status)) { Py_DECREF(result); return NULL; @@ -4118,14 +4116,12 @@ PyDec_Round(PyObject *dec, PyObject *args) /*[clinic input] _decimal.Decimal.as_tuple - self as dec: self - Return a tuple representation of the number. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_as_tuple_impl(PyObject *dec) -/*[clinic end generated code: output=b1a619dfdbf89220 input=e334c01206f0e62e]*/ +_decimal_Decimal_as_tuple_impl(PyObject *self) +/*[clinic end generated code: output=c6e8e2420c515eca input=e26f2151d78ff59d]*/ { PyObject *result = NULL; PyObject *sign = NULL; @@ -4137,13 +4133,13 @@ _decimal_Decimal_as_tuple_impl(PyObject *dec) Py_ssize_t intlen, i; - x = mpd_qncopy(MPD(dec)); + x = mpd_qncopy(MPD(self)); if (x == NULL) { PyErr_NoMemory(); goto out; } - sign = PyLong_FromUnsignedLong(mpd_sign(MPD(dec))); + sign = PyLong_FromUnsignedLong(mpd_sign(MPD(self))); if (sign == NULL) { goto out; } @@ -4164,7 +4160,7 @@ _decimal_Decimal_as_tuple_impl(PyObject *dec) expt = PyUnicode_FromString(mpd_isqnan(x)?"n":"N"); } else { - expt = PyLong_FromSsize_t(MPD(dec)->exp); + expt = PyLong_FromSsize_t(MPD(self)->exp); } if (expt == NULL) { goto out; @@ -4205,7 +4201,7 @@ _decimal_Decimal_as_tuple_impl(PyObject *dec) } } - decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); result = PyObject_CallFunctionObjArgs((PyObject *)state->DecimalTuple, sign, coeff, expt, NULL); @@ -4934,7 +4930,6 @@ Dec_BinaryFuncVA(mpd_qshift) /*[clinic input] _decimal.Decimal.quantize - self as v: self exp as w: object rounding: object = None context: object = None @@ -4964,16 +4959,16 @@ current thread's context is used. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_quantize_impl(PyObject *v, PyObject *w, PyObject *rounding, - PyObject *context) -/*[clinic end generated code: output=6ebc907ee3000c1f input=d1dc20057afe0c7e]*/ +_decimal_Decimal_quantize_impl(PyObject *self, PyObject *w, + PyObject *rounding, PyObject *context) +/*[clinic end generated code: output=5e84581f96dc685c input=4c7d28d36948e9aa]*/ { PyObject *a, *b; PyObject *result; uint32_t status = 0; mpd_context_t workctx; - decimal_state *state = get_module_state_by_def(Py_TYPE(v)); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); @@ -4987,7 +4982,7 @@ _decimal_Decimal_quantize_impl(PyObject *v, PyObject *w, PyObject *rounding, } } - CONVERT_BINOP_RAISE(&a, &b, v, w, context); + CONVERT_BINOP_RAISE(&a, &b, self, w, context); result = dec_alloc(state); if (result == NULL) { diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index b5d15b2c334071..441515edbf60f6 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -106,11 +106,11 @@ PyDoc_STRVAR(_decimal_Decimal_to_integral_value__doc__, {"to_integral_value", _PyCFunction_CAST(_decimal_Decimal_to_integral_value), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_value__doc__}, static PyObject * -_decimal_Decimal_to_integral_value_impl(PyObject *dec, PyObject *rounding, +_decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, PyObject *context); static PyObject * -_decimal_Decimal_to_integral_value(PyObject *dec, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_to_integral_value(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -161,7 +161,7 @@ _decimal_Decimal_to_integral_value(PyObject *dec, PyObject *const *args, Py_ssiz } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_to_integral_value_impl(dec, rounding, context); + return_value = _decimal_Decimal_to_integral_value_impl(self, rounding, context); exit: return return_value; @@ -256,11 +256,11 @@ PyDoc_STRVAR(_decimal_Decimal_to_integral_exact__doc__, {"to_integral_exact", _PyCFunction_CAST(_decimal_Decimal_to_integral_exact), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_exact__doc__}, static PyObject * -_decimal_Decimal_to_integral_exact_impl(PyObject *dec, PyObject *rounding, +_decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, PyObject *context); static PyObject * -_decimal_Decimal_to_integral_exact(PyObject *dec, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_to_integral_exact(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -311,7 +311,7 @@ _decimal_Decimal_to_integral_exact(PyObject *dec, PyObject *const *args, Py_ssiz } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_to_integral_exact_impl(dec, rounding, context); + return_value = _decimal_Decimal_to_integral_exact_impl(self, rounding, context); exit: return return_value; @@ -327,12 +327,12 @@ PyDoc_STRVAR(_decimal_Decimal_as_tuple__doc__, {"as_tuple", (PyCFunction)_decimal_Decimal_as_tuple, METH_NOARGS, _decimal_Decimal_as_tuple__doc__}, static PyObject * -_decimal_Decimal_as_tuple_impl(PyObject *dec); +_decimal_Decimal_as_tuple_impl(PyObject *self); static PyObject * -_decimal_Decimal_as_tuple(PyObject *dec, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal_as_tuple(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return _decimal_Decimal_as_tuple_impl(dec); + return _decimal_Decimal_as_tuple_impl(self); } PyDoc_STRVAR(_decimal_Decimal_adjusted__doc__, @@ -784,11 +784,11 @@ PyDoc_STRVAR(_decimal_Decimal_quantize__doc__, {"quantize", _PyCFunction_CAST(_decimal_Decimal_quantize), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_quantize__doc__}, static PyObject * -_decimal_Decimal_quantize_impl(PyObject *v, PyObject *w, PyObject *rounding, - PyObject *context); +_decimal_Decimal_quantize_impl(PyObject *self, PyObject *w, + PyObject *rounding, PyObject *context); static PyObject * -_decimal_Decimal_quantize(PyObject *v, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_quantize(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -841,9 +841,9 @@ _decimal_Decimal_quantize(PyObject *v, PyObject *const *args, Py_ssize_t nargs, } context = args[2]; skip_optional_pos: - return_value = _decimal_Decimal_quantize_impl(v, w, rounding, context); + return_value = _decimal_Decimal_quantize_impl(self, w, rounding, context); exit: return return_value; } -/*[clinic end generated code: output=71f76aa153a96808 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f33166d1bf53e613 input=a9049054013a1b77]*/