From e4d37755080bad9781c661ac4219fa81120175ce Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 20 Aug 2025 12:32:46 +0300 Subject: [PATCH 1/5] gh-73487: Convert _decimal to use Argument Clinic (part 5) --- Modules/_decimal/_decimal.c | 664 ++++++++++++-- Modules/_decimal/clinic/_decimal.c.h | 1194 +++++++++++++++++++++++++- Modules/_decimal/docstrings.h | 265 ------ 3 files changed, 1743 insertions(+), 380 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 806a3192e2dc96..93cd1b872d1272 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -4348,8 +4348,6 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ /* Boolean function without a context arg. */ #define Dec_BoolFunc(MPDFUNC) \ -static PyObject * \ -dec_##MPDFUNC(PyObject *self, PyObject *Py_UNUSED(dummy)) \ { \ return MPDFUNC(MPD(self)) ? incr_true() : incr_false(); \ } @@ -4423,19 +4421,9 @@ dec_##MPDFUNC(PyObject *self, PyObject *Py_UNUSED(dummy)) \ NOT take a context. The context is used to record InvalidOperation if the second operand cannot be converted exactly. */ #define Dec_BinaryFuncVA_NO_CTX(MPDFUNC) \ -static PyObject * \ -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); \ @@ -4858,13 +4846,98 @@ _decimal_Decimal_fma_impl(PyObject *self, PyObject *other, PyObject *third, Dec_TernaryFuncVA(mpd_qfma) /* Boolean functions, no context arg */ + +/*[clinic input] +_decimal.Decimal.is_canonical + +Return True if the argument is canonical and False otherwise. + +Currently, a Decimal instance is always canonical, so this operation +always returns True. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_is_canonical_impl(PyObject *self) +/*[clinic end generated code: output=b29668684f45443e input=b3b3e6878ccf40b8]*/ Dec_BoolFunc(mpd_iscanonical) + +/*[clinic input] +_decimal.Decimal.is_finite + +Return True if the argument is a finite number, and False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_is_finite_impl(PyObject *self) +/*[clinic end generated code: output=537306fbfc9131f8 input=e9b8b5866704bae6]*/ Dec_BoolFunc(mpd_isfinite) + +/*[clinic input] +_decimal.Decimal.is_infinite + +Return True if the argument is infinite, and False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_is_infinite_impl(PyObject *self) +/*[clinic end generated code: output=31b775ff28f05ce2 input=8f3937a790ee4ec2]*/ Dec_BoolFunc(mpd_isinfinite) + +/*[clinic input] +_decimal.Decimal.is_nan + +Return True if the argument is a (quiet or signaling) NaN, else False. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_is_nan_impl(PyObject *self) +/*[clinic end generated code: output=b704e8b49a164388 input=795e5dac85976994]*/ Dec_BoolFunc(mpd_isnan) + +/*[clinic input] +_decimal.Decimal.is_qnan + +Return True if the argument is a quiet NaN, and False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_is_qnan_impl(PyObject *self) +/*[clinic end generated code: output=85b5241f43798376 input=00485f3c3cfae0af]*/ Dec_BoolFunc(mpd_isqnan) + +/*[clinic input] +_decimal.Decimal.is_snan + +Return True if the argument is a signaling NaN and False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_is_snan_impl(PyObject *self) +/*[clinic end generated code: output=50de9ec6507e4a4f input=f3b0f8592c921879]*/ Dec_BoolFunc(mpd_issnan) + +/*[clinic input] +_decimal.Decimal.is_signed + +Return True if the argument has a negative sign and False otherwise. + +Note that both zeros and NaNs can carry signs. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_is_signed_impl(PyObject *self) +/*[clinic end generated code: output=8ec7bc85d8e755e4 input=97c3437ab5dffecc]*/ Dec_BoolFunc(mpd_issigned) + +/*[clinic input] +_decimal.Decimal.is_zero + +Return True if the argument is a zero and False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Decimal_is_zero_impl(PyObject *self) +/*[clinic end generated code: output=2d87ea1b15879112 input=ae616674cd050a51]*/ Dec_BoolFunc(mpd_iszero) /* Boolean functions, optional context arg */ @@ -5144,7 +5217,57 @@ _decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context) } /* Binary functions, optional context arg for conversion errors */ + +/*[clinic input] +_decimal.Decimal.compare_total = _decimal.Decimal.compare + +Compare two operands using their abstract representation. + +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=6f3111ec5fdbf3c1]*/ Dec_BinaryFuncVA_NO_CTX(mpd_compare_total) + +/*[clinic input] +_decimal.Decimal.compare_total_mag = _decimal.Decimal.compare + +As compare_total(), but ignores 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=eba17c4c24eb2833]*/ Dec_BinaryFuncVA_NO_CTX(mpd_compare_total_mag) /*[clinic input] @@ -5783,14 +5906,14 @@ static PyMethodDef dec_methods [] = _DECIMAL_DECIMAL_FMA_METHODDEF /* Boolean functions, no context arg */ - { "is_canonical", dec_mpd_iscanonical, METH_NOARGS, doc_is_canonical }, - { "is_finite", dec_mpd_isfinite, METH_NOARGS, doc_is_finite }, - { "is_infinite", dec_mpd_isinfinite, METH_NOARGS, doc_is_infinite }, - { "is_nan", dec_mpd_isnan, METH_NOARGS, doc_is_nan }, - { "is_qnan", dec_mpd_isqnan, METH_NOARGS, doc_is_qnan }, - { "is_snan", dec_mpd_issnan, METH_NOARGS, doc_is_snan }, - { "is_signed", dec_mpd_issigned, METH_NOARGS, doc_is_signed }, - { "is_zero", dec_mpd_iszero, METH_NOARGS, doc_is_zero }, + _DECIMAL_DECIMAL_IS_CANONICAL_METHODDEF + _DECIMAL_DECIMAL_IS_FINITE_METHODDEF + _DECIMAL_DECIMAL_IS_INFINITE_METHODDEF + _DECIMAL_DECIMAL_IS_NAN_METHODDEF + _DECIMAL_DECIMAL_IS_QNAN_METHODDEF + _DECIMAL_DECIMAL_IS_SNAN_METHODDEF + _DECIMAL_DECIMAL_IS_SIGNED_METHODDEF + _DECIMAL_DECIMAL_IS_ZERO_METHODDEF /* Boolean functions, optional context arg */ _DECIMAL_DECIMAL_IS_NORMAL_METHODDEF @@ -5813,8 +5936,8 @@ static PyMethodDef dec_methods [] = _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 @@ -5930,13 +6053,11 @@ ctx_##MPDFUNC(PyObject *context, PyObject *v) \ /* Unary context method. */ #define DecCtx_UnaryFunc(MPDFUNC) \ -static PyObject * \ -ctx_##MPDFUNC(PyObject *context, PyObject *v) \ { \ PyObject *result, *a; \ uint32_t status = 0; \ \ - CONVERT_OP_RAISE(&a, v, context); \ + CONVERT_OP_RAISE(&a, x, context); \ decimal_state *state = \ get_module_state_from_ctx(context); \ if ((result = dec_alloc(state)) == NULL) { \ @@ -5956,19 +6077,12 @@ ctx_##MPDFUNC(PyObject *context, PyObject *v) \ /* Binary context method. */ #define DecCtx_BinaryFunc(MPDFUNC) \ -static PyObject * \ -ctx_##MPDFUNC(PyObject *context, PyObject *args) \ { \ - PyObject *v, *w; \ PyObject *a, *b; \ PyObject *result; \ uint32_t status = 0; \ \ - if (!PyArg_ParseTuple(args, "OO", &v, &w)) { \ - return NULL; \ - } \ - \ - CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ + CONVERT_BINOP_RAISE(&a, &b, x, y, context); \ decimal_state *state = \ get_module_state_from_ctx(context); \ if ((result = dec_alloc(state)) == NULL) { \ @@ -6022,19 +6136,12 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ /* Ternary context method. */ #define DecCtx_TernaryFunc(MPDFUNC) \ -static PyObject * \ -ctx_##MPDFUNC(PyObject *context, PyObject *args) \ { \ - PyObject *v, *w, *x; \ PyObject *a, *b, *c; \ PyObject *result; \ uint32_t status = 0; \ \ - if (!PyArg_ParseTuple(args, "OOO", &v, &w, &x)) { \ - return NULL; \ - } \ - \ - CONVERT_TERNOP_RAISE(&a, &b, &c, v, w, x, context); \ + CONVERT_TERNOP_RAISE(&a, &b, &c, x, y, z, context); \ decimal_state *state = get_module_state_from_ctx(context); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ @@ -6057,34 +6164,337 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ /* Unary arithmetic functions */ + +/*[clinic input] +_decimal.Context.abs + + self as context: self + x: object + / + +Return the absolute value of x. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_abs(PyObject *context, PyObject *x) +/*[clinic end generated code: output=5cafb5edf96df9e4 input=8384b327e52d6723]*/ DecCtx_UnaryFunc(mpd_qabs) + +/*[clinic input] +_decimal.Context.exp = _decimal.Context.abs + +Return e ** x. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_exp(PyObject *context, PyObject *x) +/*[clinic end generated code: output=787085815e6a9aa4 input=5b443c4ab153dd2e]*/ DecCtx_UnaryFunc(mpd_qexp) + +/*[clinic input] +_decimal.Context.ln = _decimal.Context.abs + +Return the natural (base e) logarithm of x. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_ln(PyObject *context, PyObject *x) +/*[clinic end generated code: output=9ecce76097f16bbe input=cf43cd98a0fe7425]*/ DecCtx_UnaryFunc(mpd_qln) + +/*[clinic input] +_decimal.Context.log10 = _decimal.Context.abs + +Return the base 10 logarithm of x. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_log10(PyObject *context, PyObject *x) +/*[clinic end generated code: output=08080765645630e4 input=309e57faf42c257d]*/ DecCtx_UnaryFunc(mpd_qlog10) + +/*[clinic input] +_decimal.Context.minus = _decimal.Context.abs + +Minus corresponds to unary prefix minus in Python. + +This operation applies the context to the result. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_minus(PyObject *context, PyObject *x) +/*[clinic end generated code: output=49c1a0d59f4585b6 input=63be4c419d1d554b]*/ DecCtx_UnaryFunc(mpd_qminus) + +/*[clinic input] +_decimal.Context.next_minus = _decimal.Context.abs + +Return the largest representable number smaller than x. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_next_minus(PyObject *context, PyObject *x) +/*[clinic end generated code: output=0c11a0d5fa9103d2 input=969f4d24dfcd5e85]*/ DecCtx_UnaryFunc(mpd_qnext_minus) + +/*[clinic input] +_decimal.Context.next_plus = _decimal.Context.abs + +Return the smallest representable number larger than x. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_next_plus(PyObject *context, PyObject *x) +/*[clinic end generated code: output=fd834e8c58b76031 input=af1a85ee59b56a3c]*/ DecCtx_UnaryFunc(mpd_qnext_plus) -DecCtx_UnaryFunc(mpd_qplus) + +/*[clinic input] +_decimal.Context.normalize = _decimal.Context.abs + +Reduce x to its simplest form. Alias for reduce(x). +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_normalize(PyObject *context, PyObject *x) +/*[clinic end generated code: output=492c6ca375bcf020 input=a65bc39c81a654a9]*/ DecCtx_UnaryFunc(mpd_qreduce) + +/*[clinic input] +_decimal.Context.plus = _decimal.Context.abs + +Plus corresponds to the unary prefix plus operator in Python. + +This operation applies the context to the result. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_plus(PyObject *context, PyObject *x) +/*[clinic end generated code: output=ee089d734941936e input=5d8a75702d20e2f9]*/ +DecCtx_UnaryFunc(mpd_qplus) + +/*[clinic input] +_decimal.Context.to_integral_value = _decimal.Context.abs + +Round to an integer. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_to_integral_value(PyObject *context, PyObject *x) +/*[clinic end generated code: output=ffc6470421c1439b input=3103e147cb9de9ed]*/ DecCtx_UnaryFunc(mpd_qround_to_int) + +/*[clinic input] +_decimal.Context.to_integral_exact = _decimal.Context.abs + +Round to an integer. Signal if the result is rounded or inexact. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_to_integral_exact(PyObject *context, PyObject *x) +/*[clinic end generated code: output=7fac8eca35da9290 input=677dc4b915907b68]*/ DecCtx_UnaryFunc(mpd_qround_to_intx) + +/*[clinic input] +_decimal.Context.to_integral = _decimal.Context.abs + +Identical to to_integral_value(x). +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_to_integral(PyObject *context, PyObject *x) +/*[clinic end generated code: output=2741701ed141df91 input=89d4a4b15495b8c9]*/ +DecCtx_UnaryFunc(mpd_qround_to_int) + +/*[clinic input] +_decimal.Context.sqrt = _decimal.Context.abs + +Square root of a non-negative number to context precision. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_sqrt(PyObject *context, PyObject *x) +/*[clinic end generated code: output=5595ae901120606c input=90bd954b0b8076fb]*/ DecCtx_UnaryFunc(mpd_qsqrt) /* Binary arithmetic functions */ + +/*[clinic input] +_decimal.Context.add + + self as context: self + x: object + y: object + / + +Return the sum of x and y. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_add_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=9957850af48fe295 input=8b8eac286bdf6cb4]*/ DecCtx_BinaryFunc(mpd_qadd) + +/*[clinic input] +_decimal.Context.compare = _decimal.Context.add + +Compare x and y numerically. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_compare_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=646ab96420b9aad7 input=f701cb179c966ec1]*/ DecCtx_BinaryFunc(mpd_qcompare) + +/*[clinic input] +_decimal.Context.compare_signal = _decimal.Context.add + +Compare x and y numerically. All NaNs signal. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_compare_signal_impl(PyObject *context, PyObject *x, + PyObject *y) +/*[clinic end generated code: output=dd56e9e6c3d12216 input=32a1bcef7bbc5179]*/ DecCtx_BinaryFunc(mpd_qcompare_signal) + +/*[clinic input] +_decimal.Context.divide = _decimal.Context.add + +Return x divided by y. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_divide_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=0a07a5e718fe4a2c input=00cd9bc2ba2a1786]*/ DecCtx_BinaryFunc(mpd_qdiv) + +/*[clinic input] +_decimal.Context.divide_int = _decimal.Context.add + +Return x divided by y, truncated to an integer. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_divide_int_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=8c2d505d4339f4ef input=e80ada2f50d9719d]*/ DecCtx_BinaryFunc(mpd_qdivint) + +/*[clinic input] +_decimal.Context.max = _decimal.Context.add + +Compare the values numerically and return the maximum. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_max_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=c8545b7718414761 input=22008ab898c86a8b]*/ DecCtx_BinaryFunc(mpd_qmax) + +/*[clinic input] +_decimal.Context.max_mag = _decimal.Context.add + +Compare the values numerically with their sign ignored. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_max_mag_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=3cd67457cbc4d961 input=f7ce42ef82a7c52e]*/ DecCtx_BinaryFunc(mpd_qmax_mag) + +/*[clinic input] +_decimal.Context.min = _decimal.Context.add + +Compare the values numerically and return the minimum. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_min_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=c1bc3852a7c09707 input=2aeec1167638c5ef]*/ DecCtx_BinaryFunc(mpd_qmin) + +/*[clinic input] +_decimal.Context.min_mag = _decimal.Context.add + +Compare the values numerically with their sign ignored. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_min_mag_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=f662c9d1b49abfd2 input=19d158c29e4fc140]*/ DecCtx_BinaryFunc(mpd_qmin_mag) + +/*[clinic input] +_decimal.Context.multiply = _decimal.Context.add + +Return the product of x and y. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_multiply_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=970be645784d70ad input=2fdd01acdbeef8ba]*/ DecCtx_BinaryFunc(mpd_qmul) + +/*[clinic input] +_decimal.Context.next_toward = _decimal.Context.add + +Return the number closest to x, in the direction towards y. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_next_toward_impl(PyObject *context, PyObject *x, + PyObject *y) +/*[clinic end generated code: output=938f2b4034e83618 input=aac775298e02b68c]*/ DecCtx_BinaryFunc(mpd_qnext_toward) + +/*[clinic input] +_decimal.Context.quantize = _decimal.Context.add + +Return a value equal to x (rounded), having the exponent of y. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_quantize_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=38ae7ac037d093d0 input=43d67a696ab6d895]*/ DecCtx_BinaryFunc(mpd_qquantize) + +/*[clinic input] +_decimal.Context.remainder = _decimal.Context.add + +Return the remainder from integer division. + +The sign of the result, if non-zero, is the same as that of the +original dividend. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_remainder_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=eb158964831b5ca4 input=36d0eb2b392c1215]*/ DecCtx_BinaryFunc(mpd_qrem) + +/*[clinic input] +_decimal.Context.remainder_near = _decimal.Context.add + +Return x - y * n. + +Here n is the integer nearest the exact value of x / y (if the result +is 0 then its sign will be the sign of x). +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_remainder_near_impl(PyObject *context, PyObject *x, + PyObject *y) +/*[clinic end generated code: output=2bcbd9bb031d0d13 input=bafb6327bb314c5c]*/ DecCtx_BinaryFunc(mpd_qrem_near) + +/*[clinic input] +_decimal.Context.subtract = _decimal.Context.add + +Return the difference between x and y. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_subtract_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=fa8847e07b7c2bcc input=6767683ec68f7a1a]*/ DecCtx_BinaryFunc(mpd_qsub) static PyObject * @@ -6206,6 +6616,23 @@ _decimal_Context_power_impl(PyObject *context, PyObject *base, PyObject *exp, } /* Ternary arithmetic functions */ + +/*[clinic input] +_decimal.Context.fma + + self as context: self + x: object + y: object + z: object + / + +Return x multiplied by y, plus z. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_fma_impl(PyObject *context, PyObject *x, PyObject *y, + PyObject *z) +/*[clinic end generated code: output=2d6174716faaf4e1 input=80479612da3333d1]*/ DecCtx_TernaryFunc(mpd_qfma) /* No argument */ @@ -6333,7 +6760,26 @@ ctx_mpd_qcopy_negate(PyObject *context, PyObject *v) return result; } +/*[clinic input] +_decimal.Context.logb = _decimal.Context.abs + +Return the exponent of the magnitude of the operand's MSD. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_logb(PyObject *context, PyObject *x) +/*[clinic end generated code: output=d2d8469f828daa41 input=28d1cd1a8a906b9a]*/ DecCtx_UnaryFunc(mpd_qlogb) + +/*[clinic input] +_decimal.Context.logical_invert = _decimal.Context.abs + +Invert all digits of x. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_logical_invert(PyObject *context, PyObject *x) +/*[clinic end generated code: output=b863a5cdb986f684 input=1fa8dcc59c557fcc]*/ DecCtx_UnaryFunc(mpd_qinvert) static PyObject * @@ -6432,12 +6878,72 @@ ctx_mpd_qcopy_sign(PyObject *context, PyObject *args) return result; } +/*[clinic input] +_decimal.Context.logical_and = _decimal.Context.add + +Digit-wise and of x and y. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_logical_and_impl(PyObject *context, PyObject *x, + PyObject *y) +/*[clinic end generated code: output=f1e9bf7844a395fc input=30ee33b5b365fd80]*/ DecCtx_BinaryFunc(mpd_qand) + +/*[clinic input] +_decimal.Context.logical_or = _decimal.Context.add + +Digit-wise or of x and y. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_logical_or_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=28f7ecd1af3262f0 input=3b1a6725d0262fb9]*/ DecCtx_BinaryFunc(mpd_qor) + +/*[clinic input] +_decimal.Context.logical_xor = _decimal.Context.add + +Digit-wise xor of x and y. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_logical_xor_impl(PyObject *context, PyObject *x, + PyObject *y) +/*[clinic end generated code: output=7d8461ace42d1871 input=5ebbbe8bb35da380]*/ DecCtx_BinaryFunc(mpd_qxor) +/*[clinic input] +_decimal.Context.rotate = _decimal.Context.add + +Return a copy of x, rotated by y places. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_rotate_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=6d8b718f218712a2 input=7ad91845c909eb0a]*/ DecCtx_BinaryFunc(mpd_qrotate) + +/*[clinic input] +_decimal.Context.scaleb = _decimal.Context.add + +Return the first operand after adding the second value to its exp. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_scaleb_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=3c9cb117027c7722 input=c5d2ee7a57f65f8c]*/ DecCtx_BinaryFunc(mpd_qscaleb) + +/*[clinic input] +_decimal.Context.shift = _decimal.Context.add + +Return a copy of x, shifted by y places. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_shift_impl(PyObject *context, PyObject *x, PyObject *y) +/*[clinic end generated code: output=78625878a264b3e5 input=1ab44ff0854420ce]*/ DecCtx_BinaryFunc(mpd_qshift) static PyObject * @@ -6464,43 +6970,43 @@ ctx_mpd_same_quantum(PyObject *context, PyObject *args) static PyMethodDef context_methods [] = { /* Unary arithmetic functions */ - { "abs", ctx_mpd_qabs, METH_O, doc_ctx_abs }, - { "exp", ctx_mpd_qexp, METH_O, doc_ctx_exp }, - { "ln", ctx_mpd_qln, METH_O, doc_ctx_ln }, - { "log10", ctx_mpd_qlog10, METH_O, doc_ctx_log10 }, - { "minus", ctx_mpd_qminus, METH_O, doc_ctx_minus }, - { "next_minus", ctx_mpd_qnext_minus, METH_O, doc_ctx_next_minus }, - { "next_plus", ctx_mpd_qnext_plus, METH_O, doc_ctx_next_plus }, - { "normalize", ctx_mpd_qreduce, METH_O, doc_ctx_normalize }, - { "plus", ctx_mpd_qplus, METH_O, doc_ctx_plus }, - { "to_integral", ctx_mpd_qround_to_int, METH_O, doc_ctx_to_integral }, - { "to_integral_exact", ctx_mpd_qround_to_intx, METH_O, doc_ctx_to_integral_exact }, - { "to_integral_value", ctx_mpd_qround_to_int, METH_O, doc_ctx_to_integral_value }, - { "sqrt", ctx_mpd_qsqrt, METH_O, doc_ctx_sqrt }, + _DECIMAL_CONTEXT_ABS_METHODDEF + _DECIMAL_CONTEXT_EXP_METHODDEF + _DECIMAL_CONTEXT_LN_METHODDEF + _DECIMAL_CONTEXT_LOG10_METHODDEF + _DECIMAL_CONTEXT_MINUS_METHODDEF + _DECIMAL_CONTEXT_NEXT_MINUS_METHODDEF + _DECIMAL_CONTEXT_NEXT_PLUS_METHODDEF + _DECIMAL_CONTEXT_NORMALIZE_METHODDEF + _DECIMAL_CONTEXT_PLUS_METHODDEF + _DECIMAL_CONTEXT_TO_INTEGRAL_METHODDEF + _DECIMAL_CONTEXT_TO_INTEGRAL_EXACT_METHODDEF + _DECIMAL_CONTEXT_TO_INTEGRAL_VALUE_METHODDEF + _DECIMAL_CONTEXT_SQRT_METHODDEF /* Binary arithmetic functions */ - { "add", ctx_mpd_qadd, METH_VARARGS, doc_ctx_add }, - { "compare", ctx_mpd_qcompare, METH_VARARGS, doc_ctx_compare }, - { "compare_signal", ctx_mpd_qcompare_signal, METH_VARARGS, doc_ctx_compare_signal }, - { "divide", ctx_mpd_qdiv, METH_VARARGS, doc_ctx_divide }, - { "divide_int", ctx_mpd_qdivint, METH_VARARGS, doc_ctx_divide_int }, + _DECIMAL_CONTEXT_ADD_METHODDEF + _DECIMAL_CONTEXT_COMPARE_METHODDEF + _DECIMAL_CONTEXT_COMPARE_SIGNAL_METHODDEF + _DECIMAL_CONTEXT_DIVIDE_METHODDEF + _DECIMAL_CONTEXT_DIVIDE_INT_METHODDEF { "divmod", ctx_mpd_qdivmod, METH_VARARGS, doc_ctx_divmod }, - { "max", ctx_mpd_qmax, METH_VARARGS, doc_ctx_max }, - { "max_mag", ctx_mpd_qmax_mag, METH_VARARGS, doc_ctx_max_mag }, - { "min", ctx_mpd_qmin, METH_VARARGS, doc_ctx_min }, - { "min_mag", ctx_mpd_qmin_mag, METH_VARARGS, doc_ctx_min_mag }, - { "multiply", ctx_mpd_qmul, METH_VARARGS, doc_ctx_multiply }, - { "next_toward", ctx_mpd_qnext_toward, METH_VARARGS, doc_ctx_next_toward }, - { "quantize", ctx_mpd_qquantize, METH_VARARGS, doc_ctx_quantize }, - { "remainder", ctx_mpd_qrem, METH_VARARGS, doc_ctx_remainder }, - { "remainder_near", ctx_mpd_qrem_near, METH_VARARGS, doc_ctx_remainder_near }, - { "subtract", ctx_mpd_qsub, METH_VARARGS, doc_ctx_subtract }, + _DECIMAL_CONTEXT_MAX_METHODDEF + _DECIMAL_CONTEXT_MAX_MAG_METHODDEF + _DECIMAL_CONTEXT_MIN_METHODDEF + _DECIMAL_CONTEXT_MIN_MAG_METHODDEF + _DECIMAL_CONTEXT_MULTIPLY_METHODDEF + _DECIMAL_CONTEXT_NEXT_TOWARD_METHODDEF + _DECIMAL_CONTEXT_QUANTIZE_METHODDEF + _DECIMAL_CONTEXT_REMAINDER_METHODDEF + _DECIMAL_CONTEXT_REMAINDER_NEAR_METHODDEF + _DECIMAL_CONTEXT_SUBTRACT_METHODDEF /* Binary or ternary arithmetic functions */ _DECIMAL_CONTEXT_POWER_METHODDEF /* Ternary arithmetic functions */ - { "fma", ctx_mpd_qfma, METH_VARARGS, doc_ctx_fma }, + _DECIMAL_CONTEXT_FMA_METHODDEF /* No argument */ _DECIMAL_CONTEXT_ETINY_METHODDEF @@ -6528,8 +7034,8 @@ static PyMethodDef context_methods [] = { "copy_abs", ctx_mpd_qcopy_abs, METH_O, doc_ctx_copy_abs }, { "copy_decimal", ctx_copy_decimal, METH_O, doc_ctx_copy_decimal }, { "copy_negate", ctx_mpd_qcopy_negate, METH_O, doc_ctx_copy_negate }, - { "logb", ctx_mpd_qlogb, METH_O, doc_ctx_logb }, - { "logical_invert", ctx_mpd_qinvert, METH_O, doc_ctx_logical_invert }, + _DECIMAL_CONTEXT_LOGB_METHODDEF + _DECIMAL_CONTEXT_LOGICAL_INVERT_METHODDEF { "number_class", ctx_mpd_class, METH_O, doc_ctx_number_class }, { "to_sci_string", ctx_mpd_to_sci, METH_O, doc_ctx_to_sci_string }, { "to_eng_string", ctx_mpd_to_eng, METH_O, doc_ctx_to_eng_string }, @@ -6538,13 +7044,13 @@ static PyMethodDef context_methods [] = { "compare_total", ctx_mpd_compare_total, METH_VARARGS, doc_ctx_compare_total }, { "compare_total_mag", ctx_mpd_compare_total_mag, METH_VARARGS, doc_ctx_compare_total_mag }, { "copy_sign", ctx_mpd_qcopy_sign, METH_VARARGS, doc_ctx_copy_sign }, - { "logical_and", ctx_mpd_qand, METH_VARARGS, doc_ctx_logical_and }, - { "logical_or", ctx_mpd_qor, METH_VARARGS, doc_ctx_logical_or }, - { "logical_xor", ctx_mpd_qxor, METH_VARARGS, doc_ctx_logical_xor }, - { "rotate", ctx_mpd_qrotate, METH_VARARGS, doc_ctx_rotate }, + _DECIMAL_CONTEXT_LOGICAL_AND_METHODDEF + _DECIMAL_CONTEXT_LOGICAL_OR_METHODDEF + _DECIMAL_CONTEXT_LOGICAL_XOR_METHODDEF + _DECIMAL_CONTEXT_ROTATE_METHODDEF { "same_quantum", ctx_mpd_same_quantum, METH_VARARGS, doc_ctx_same_quantum }, - { "scaleb", ctx_mpd_qscaleb, METH_VARARGS, doc_ctx_scaleb }, - { "shift", ctx_mpd_qshift, METH_VARARGS, doc_ctx_shift }, + _DECIMAL_CONTEXT_SCALEB_METHODDEF + _DECIMAL_CONTEXT_SHIFT_METHODDEF /* Set context values */ { "clear_flags", context_clear_flags, METH_NOARGS, doc_ctx_clear_flags }, diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index 224c24574554f3..5473b246e7ca70 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -1803,6 +1803,155 @@ _decimal_Decimal_fma(PyObject *self, PyObject *const *args, Py_ssize_t nargs, Py return return_value; } +PyDoc_STRVAR(_decimal_Decimal_is_canonical__doc__, +"is_canonical($self, /)\n" +"--\n" +"\n" +"Return True if the argument is canonical and False otherwise.\n" +"\n" +"Currently, a Decimal instance is always canonical, so this operation\n" +"always returns True."); + +#define _DECIMAL_DECIMAL_IS_CANONICAL_METHODDEF \ + {"is_canonical", (PyCFunction)_decimal_Decimal_is_canonical, METH_NOARGS, _decimal_Decimal_is_canonical__doc__}, + +static PyObject * +_decimal_Decimal_is_canonical_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_is_canonical(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_is_canonical_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_is_finite__doc__, +"is_finite($self, /)\n" +"--\n" +"\n" +"Return True if the argument is a finite number, and False otherwise."); + +#define _DECIMAL_DECIMAL_IS_FINITE_METHODDEF \ + {"is_finite", (PyCFunction)_decimal_Decimal_is_finite, METH_NOARGS, _decimal_Decimal_is_finite__doc__}, + +static PyObject * +_decimal_Decimal_is_finite_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_is_finite(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_is_finite_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_is_infinite__doc__, +"is_infinite($self, /)\n" +"--\n" +"\n" +"Return True if the argument is infinite, and False otherwise."); + +#define _DECIMAL_DECIMAL_IS_INFINITE_METHODDEF \ + {"is_infinite", (PyCFunction)_decimal_Decimal_is_infinite, METH_NOARGS, _decimal_Decimal_is_infinite__doc__}, + +static PyObject * +_decimal_Decimal_is_infinite_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_is_infinite(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_is_infinite_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_is_nan__doc__, +"is_nan($self, /)\n" +"--\n" +"\n" +"Return True if the argument is a (quiet or signaling) NaN, else False."); + +#define _DECIMAL_DECIMAL_IS_NAN_METHODDEF \ + {"is_nan", (PyCFunction)_decimal_Decimal_is_nan, METH_NOARGS, _decimal_Decimal_is_nan__doc__}, + +static PyObject * +_decimal_Decimal_is_nan_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_is_nan(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_is_nan_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_is_qnan__doc__, +"is_qnan($self, /)\n" +"--\n" +"\n" +"Return True if the argument is a quiet NaN, and False otherwise."); + +#define _DECIMAL_DECIMAL_IS_QNAN_METHODDEF \ + {"is_qnan", (PyCFunction)_decimal_Decimal_is_qnan, METH_NOARGS, _decimal_Decimal_is_qnan__doc__}, + +static PyObject * +_decimal_Decimal_is_qnan_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_is_qnan(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_is_qnan_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_is_snan__doc__, +"is_snan($self, /)\n" +"--\n" +"\n" +"Return True if the argument is a signaling NaN and False otherwise."); + +#define _DECIMAL_DECIMAL_IS_SNAN_METHODDEF \ + {"is_snan", (PyCFunction)_decimal_Decimal_is_snan, METH_NOARGS, _decimal_Decimal_is_snan__doc__}, + +static PyObject * +_decimal_Decimal_is_snan_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_is_snan(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_is_snan_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_is_signed__doc__, +"is_signed($self, /)\n" +"--\n" +"\n" +"Return True if the argument has a negative sign and False otherwise.\n" +"\n" +"Note that both zeros and NaNs can carry signs."); + +#define _DECIMAL_DECIMAL_IS_SIGNED_METHODDEF \ + {"is_signed", (PyCFunction)_decimal_Decimal_is_signed, METH_NOARGS, _decimal_Decimal_is_signed__doc__}, + +static PyObject * +_decimal_Decimal_is_signed_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_is_signed(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_is_signed_impl(self); +} + +PyDoc_STRVAR(_decimal_Decimal_is_zero__doc__, +"is_zero($self, /)\n" +"--\n" +"\n" +"Return True if the argument is a zero and False otherwise."); + +#define _DECIMAL_DECIMAL_IS_ZERO_METHODDEF \ + {"is_zero", (PyCFunction)_decimal_Decimal_is_zero, METH_NOARGS, _decimal_Decimal_is_zero__doc__}, + +static PyObject * +_decimal_Decimal_is_zero_impl(PyObject *self); + +static PyObject * +_decimal_Decimal_is_zero(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _decimal_Decimal_is_zero_impl(self); +} + PyDoc_STRVAR(_decimal_Decimal_is_normal__doc__, "is_normal($self, /, context=None)\n" "--\n" @@ -2335,6 +2484,166 @@ _decimal_Decimal_to_eng_string(PyObject *self, PyObject *const *args, Py_ssize_t 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.\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\n" +"result of this function is Decimal(\'0\') if both operands have the same\n" +"representation, Decimal(\'-1\') if the first operand is lower in the\n" +"total order than the second, and Decimal(\'1\') if the first operand is\n" +"higher in the total order than the second operand. See the\n" +"specification for details of the total order.\n" +"\n" +"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_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" +"As compare_total(), but ignores the sign of each operand.\n" +"\n" +"x.compare_total_mag(y) is equivalent to\n" +"x.copy_abs().compare_total(y.copy_abs()).\n" +"\n" +"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_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" @@ -3122,50 +3431,630 @@ _decimal_Decimal___trunc__(PyObject *self, PyObject *Py_UNUSED(ignored)) return _decimal_Decimal___trunc___impl(self); } -PyDoc_STRVAR(_decimal_Context_power__doc__, -"power($self, /, a, b, modulo=None)\n" +PyDoc_STRVAR(_decimal_Context_abs__doc__, +"abs($self, x, /)\n" "--\n" "\n" -"Compute a**b.\n" +"Return the absolute value of x."); + +#define _DECIMAL_CONTEXT_ABS_METHODDEF \ + {"abs", (PyCFunction)_decimal_Context_abs, METH_O, _decimal_Context_abs__doc__}, + +PyDoc_STRVAR(_decimal_Context_exp__doc__, +"exp($self, x, /)\n" +"--\n" "\n" -"If \'a\' is negative, then \'b\' must be integral. The result will be\n" -"inexact unless \'a\' is integral and the result is finite and can be\n" -"expressed exactly in \'precision\' digits. In the Python version the\n" -"result is always correctly rounded, in the C version the result is\n" -"almost always correctly rounded.\n" +"Return e ** x."); + +#define _DECIMAL_CONTEXT_EXP_METHODDEF \ + {"exp", (PyCFunction)_decimal_Context_exp, METH_O, _decimal_Context_exp__doc__}, + +PyDoc_STRVAR(_decimal_Context_ln__doc__, +"ln($self, x, /)\n" +"--\n" "\n" -"If modulo is given, compute (a**b) % modulo. The following\n" -"restrictions hold:\n" +"Return the natural (base e) logarithm of x."); + +#define _DECIMAL_CONTEXT_LN_METHODDEF \ + {"ln", (PyCFunction)_decimal_Context_ln, METH_O, _decimal_Context_ln__doc__}, + +PyDoc_STRVAR(_decimal_Context_log10__doc__, +"log10($self, x, /)\n" +"--\n" "\n" -" * all three arguments must be integral\n" -" * \'b\' must be nonnegative\n" -" * at least one of \'a\' or \'b\' must be nonzero\n" -" * modulo must be nonzero and less than 10**prec in absolute value"); +"Return the base 10 logarithm of x."); -#define _DECIMAL_CONTEXT_POWER_METHODDEF \ - {"power", _PyCFunction_CAST(_decimal_Context_power), METH_FASTCALL|METH_KEYWORDS, _decimal_Context_power__doc__}, +#define _DECIMAL_CONTEXT_LOG10_METHODDEF \ + {"log10", (PyCFunction)_decimal_Context_log10, METH_O, _decimal_Context_log10__doc__}, -static PyObject * -_decimal_Context_power_impl(PyObject *context, PyObject *base, PyObject *exp, - PyObject *mod); +PyDoc_STRVAR(_decimal_Context_minus__doc__, +"minus($self, x, /)\n" +"--\n" +"\n" +"Minus corresponds to unary prefix minus in Python.\n" +"\n" +"This operation applies the context to the result."); -static PyObject * -_decimal_Context_power(PyObject *context, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +#define _DECIMAL_CONTEXT_MINUS_METHODDEF \ + {"minus", (PyCFunction)_decimal_Context_minus, METH_O, _decimal_Context_minus__doc__}, - #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_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), &_Py_ID(modulo), }, - }; +PyDoc_STRVAR(_decimal_Context_next_minus__doc__, +"next_minus($self, x, /)\n" +"--\n" +"\n" +"Return the largest representable number smaller than x."); + +#define _DECIMAL_CONTEXT_NEXT_MINUS_METHODDEF \ + {"next_minus", (PyCFunction)_decimal_Context_next_minus, METH_O, _decimal_Context_next_minus__doc__}, + +PyDoc_STRVAR(_decimal_Context_next_plus__doc__, +"next_plus($self, x, /)\n" +"--\n" +"\n" +"Return the smallest representable number larger than x."); + +#define _DECIMAL_CONTEXT_NEXT_PLUS_METHODDEF \ + {"next_plus", (PyCFunction)_decimal_Context_next_plus, METH_O, _decimal_Context_next_plus__doc__}, + +PyDoc_STRVAR(_decimal_Context_normalize__doc__, +"normalize($self, x, /)\n" +"--\n" +"\n" +"Reduce x to its simplest form. Alias for reduce(x)."); + +#define _DECIMAL_CONTEXT_NORMALIZE_METHODDEF \ + {"normalize", (PyCFunction)_decimal_Context_normalize, METH_O, _decimal_Context_normalize__doc__}, + +PyDoc_STRVAR(_decimal_Context_plus__doc__, +"plus($self, x, /)\n" +"--\n" +"\n" +"Plus corresponds to the unary prefix plus operator in Python.\n" +"\n" +"This operation applies the context to the result."); + +#define _DECIMAL_CONTEXT_PLUS_METHODDEF \ + {"plus", (PyCFunction)_decimal_Context_plus, METH_O, _decimal_Context_plus__doc__}, + +PyDoc_STRVAR(_decimal_Context_to_integral_value__doc__, +"to_integral_value($self, x, /)\n" +"--\n" +"\n" +"Round to an integer."); + +#define _DECIMAL_CONTEXT_TO_INTEGRAL_VALUE_METHODDEF \ + {"to_integral_value", (PyCFunction)_decimal_Context_to_integral_value, METH_O, _decimal_Context_to_integral_value__doc__}, + +PyDoc_STRVAR(_decimal_Context_to_integral_exact__doc__, +"to_integral_exact($self, x, /)\n" +"--\n" +"\n" +"Round to an integer. Signal if the result is rounded or inexact."); + +#define _DECIMAL_CONTEXT_TO_INTEGRAL_EXACT_METHODDEF \ + {"to_integral_exact", (PyCFunction)_decimal_Context_to_integral_exact, METH_O, _decimal_Context_to_integral_exact__doc__}, + +PyDoc_STRVAR(_decimal_Context_to_integral__doc__, +"to_integral($self, x, /)\n" +"--\n" +"\n" +"Identical to to_integral_value(x)."); + +#define _DECIMAL_CONTEXT_TO_INTEGRAL_METHODDEF \ + {"to_integral", (PyCFunction)_decimal_Context_to_integral, METH_O, _decimal_Context_to_integral__doc__}, + +PyDoc_STRVAR(_decimal_Context_sqrt__doc__, +"sqrt($self, x, /)\n" +"--\n" +"\n" +"Square root of a non-negative number to context precision."); + +#define _DECIMAL_CONTEXT_SQRT_METHODDEF \ + {"sqrt", (PyCFunction)_decimal_Context_sqrt, METH_O, _decimal_Context_sqrt__doc__}, + +PyDoc_STRVAR(_decimal_Context_add__doc__, +"add($self, x, y, /)\n" +"--\n" +"\n" +"Return the sum of x and y."); + +#define _DECIMAL_CONTEXT_ADD_METHODDEF \ + {"add", _PyCFunction_CAST(_decimal_Context_add), METH_FASTCALL, _decimal_Context_add__doc__}, + +static PyObject * +_decimal_Context_add_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_add(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("add", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_add_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_compare__doc__, +"compare($self, x, y, /)\n" +"--\n" +"\n" +"Compare x and y numerically."); + +#define _DECIMAL_CONTEXT_COMPARE_METHODDEF \ + {"compare", _PyCFunction_CAST(_decimal_Context_compare), METH_FASTCALL, _decimal_Context_compare__doc__}, + +static PyObject * +_decimal_Context_compare_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_compare(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("compare", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_compare_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_compare_signal__doc__, +"compare_signal($self, x, y, /)\n" +"--\n" +"\n" +"Compare x and y numerically. All NaNs signal."); + +#define _DECIMAL_CONTEXT_COMPARE_SIGNAL_METHODDEF \ + {"compare_signal", _PyCFunction_CAST(_decimal_Context_compare_signal), METH_FASTCALL, _decimal_Context_compare_signal__doc__}, + +static PyObject * +_decimal_Context_compare_signal_impl(PyObject *context, PyObject *x, + PyObject *y); + +static PyObject * +_decimal_Context_compare_signal(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("compare_signal", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_compare_signal_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_divide__doc__, +"divide($self, x, y, /)\n" +"--\n" +"\n" +"Return x divided by y."); + +#define _DECIMAL_CONTEXT_DIVIDE_METHODDEF \ + {"divide", _PyCFunction_CAST(_decimal_Context_divide), METH_FASTCALL, _decimal_Context_divide__doc__}, + +static PyObject * +_decimal_Context_divide_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_divide(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("divide", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_divide_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_divide_int__doc__, +"divide_int($self, x, y, /)\n" +"--\n" +"\n" +"Return x divided by y, truncated to an integer."); + +#define _DECIMAL_CONTEXT_DIVIDE_INT_METHODDEF \ + {"divide_int", _PyCFunction_CAST(_decimal_Context_divide_int), METH_FASTCALL, _decimal_Context_divide_int__doc__}, + +static PyObject * +_decimal_Context_divide_int_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_divide_int(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("divide_int", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_divide_int_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_max__doc__, +"max($self, x, y, /)\n" +"--\n" +"\n" +"Compare the values numerically and return the maximum."); + +#define _DECIMAL_CONTEXT_MAX_METHODDEF \ + {"max", _PyCFunction_CAST(_decimal_Context_max), METH_FASTCALL, _decimal_Context_max__doc__}, + +static PyObject * +_decimal_Context_max_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_max(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("max", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_max_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_max_mag__doc__, +"max_mag($self, x, y, /)\n" +"--\n" +"\n" +"Compare the values numerically with their sign ignored."); + +#define _DECIMAL_CONTEXT_MAX_MAG_METHODDEF \ + {"max_mag", _PyCFunction_CAST(_decimal_Context_max_mag), METH_FASTCALL, _decimal_Context_max_mag__doc__}, + +static PyObject * +_decimal_Context_max_mag_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_max_mag(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("max_mag", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_max_mag_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_min__doc__, +"min($self, x, y, /)\n" +"--\n" +"\n" +"Compare the values numerically and return the minimum."); + +#define _DECIMAL_CONTEXT_MIN_METHODDEF \ + {"min", _PyCFunction_CAST(_decimal_Context_min), METH_FASTCALL, _decimal_Context_min__doc__}, + +static PyObject * +_decimal_Context_min_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_min(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("min", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_min_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_min_mag__doc__, +"min_mag($self, x, y, /)\n" +"--\n" +"\n" +"Compare the values numerically with their sign ignored."); + +#define _DECIMAL_CONTEXT_MIN_MAG_METHODDEF \ + {"min_mag", _PyCFunction_CAST(_decimal_Context_min_mag), METH_FASTCALL, _decimal_Context_min_mag__doc__}, + +static PyObject * +_decimal_Context_min_mag_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_min_mag(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("min_mag", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_min_mag_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_multiply__doc__, +"multiply($self, x, y, /)\n" +"--\n" +"\n" +"Return the product of x and y."); + +#define _DECIMAL_CONTEXT_MULTIPLY_METHODDEF \ + {"multiply", _PyCFunction_CAST(_decimal_Context_multiply), METH_FASTCALL, _decimal_Context_multiply__doc__}, + +static PyObject * +_decimal_Context_multiply_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_multiply(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("multiply", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_multiply_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_next_toward__doc__, +"next_toward($self, x, y, /)\n" +"--\n" +"\n" +"Return the number closest to x, in the direction towards y."); + +#define _DECIMAL_CONTEXT_NEXT_TOWARD_METHODDEF \ + {"next_toward", _PyCFunction_CAST(_decimal_Context_next_toward), METH_FASTCALL, _decimal_Context_next_toward__doc__}, + +static PyObject * +_decimal_Context_next_toward_impl(PyObject *context, PyObject *x, + PyObject *y); + +static PyObject * +_decimal_Context_next_toward(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("next_toward", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_next_toward_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_quantize__doc__, +"quantize($self, x, y, /)\n" +"--\n" +"\n" +"Return a value equal to x (rounded), having the exponent of y."); + +#define _DECIMAL_CONTEXT_QUANTIZE_METHODDEF \ + {"quantize", _PyCFunction_CAST(_decimal_Context_quantize), METH_FASTCALL, _decimal_Context_quantize__doc__}, + +static PyObject * +_decimal_Context_quantize_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_quantize(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("quantize", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_quantize_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_remainder__doc__, +"remainder($self, x, y, /)\n" +"--\n" +"\n" +"Return the remainder from integer division.\n" +"\n" +"The sign of the result, if non-zero, is the same as that of the\n" +"original dividend."); + +#define _DECIMAL_CONTEXT_REMAINDER_METHODDEF \ + {"remainder", _PyCFunction_CAST(_decimal_Context_remainder), METH_FASTCALL, _decimal_Context_remainder__doc__}, + +static PyObject * +_decimal_Context_remainder_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_remainder(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("remainder", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_remainder_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_remainder_near__doc__, +"remainder_near($self, x, y, /)\n" +"--\n" +"\n" +"Return x - y * n.\n" +"\n" +"Here n is the integer nearest the exact value of x / y (if the result\n" +"is 0 then its sign will be the sign of x)."); + +#define _DECIMAL_CONTEXT_REMAINDER_NEAR_METHODDEF \ + {"remainder_near", _PyCFunction_CAST(_decimal_Context_remainder_near), METH_FASTCALL, _decimal_Context_remainder_near__doc__}, + +static PyObject * +_decimal_Context_remainder_near_impl(PyObject *context, PyObject *x, + PyObject *y); + +static PyObject * +_decimal_Context_remainder_near(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("remainder_near", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_remainder_near_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_subtract__doc__, +"subtract($self, x, y, /)\n" +"--\n" +"\n" +"Return the difference between x and y."); + +#define _DECIMAL_CONTEXT_SUBTRACT_METHODDEF \ + {"subtract", _PyCFunction_CAST(_decimal_Context_subtract), METH_FASTCALL, _decimal_Context_subtract__doc__}, + +static PyObject * +_decimal_Context_subtract_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_subtract(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("subtract", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_subtract_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_power__doc__, +"power($self, /, a, b, modulo=None)\n" +"--\n" +"\n" +"Compute a**b.\n" +"\n" +"If \'a\' is negative, then \'b\' must be integral. The result will be\n" +"inexact unless \'a\' is integral and the result is finite and can be\n" +"expressed exactly in \'precision\' digits. In the Python version the\n" +"result is always correctly rounded, in the C version the result is\n" +"almost always correctly rounded.\n" +"\n" +"If modulo is given, compute (a**b) % modulo. The following\n" +"restrictions hold:\n" +"\n" +" * all three arguments must be integral\n" +" * \'b\' must be nonnegative\n" +" * at least one of \'a\' or \'b\' must be nonzero\n" +" * modulo must be nonzero and less than 10**prec in absolute value"); + +#define _DECIMAL_CONTEXT_POWER_METHODDEF \ + {"power", _PyCFunction_CAST(_decimal_Context_power), METH_FASTCALL|METH_KEYWORDS, _decimal_Context_power__doc__}, + +static PyObject * +_decimal_Context_power_impl(PyObject *context, PyObject *base, PyObject *exp, + PyObject *mod); + +static PyObject * +_decimal_Context_power(PyObject *context, 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_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), &_Py_ID(modulo), }, + }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -3204,6 +4093,39 @@ _decimal_Context_power(PyObject *context, PyObject *const *args, Py_ssize_t narg return return_value; } +PyDoc_STRVAR(_decimal_Context_fma__doc__, +"fma($self, x, y, z, /)\n" +"--\n" +"\n" +"Return x multiplied by y, plus z."); + +#define _DECIMAL_CONTEXT_FMA_METHODDEF \ + {"fma", _PyCFunction_CAST(_decimal_Context_fma), METH_FASTCALL, _decimal_Context_fma__doc__}, + +static PyObject * +_decimal_Context_fma_impl(PyObject *context, PyObject *x, PyObject *y, + PyObject *z); + +static PyObject * +_decimal_Context_fma(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + PyObject *z; + + if (!_PyArg_CheckPositional("fma", nargs, 3, 3)) { + goto exit; + } + x = args[0]; + y = args[1]; + z = args[2]; + return_value = _decimal_Context_fma_impl(context, x, y, z); + +exit: + return return_value; +} + PyDoc_STRVAR(_decimal_Context_radix__doc__, "radix($self, /)\n" "--\n" @@ -3221,4 +4143,204 @@ _decimal_Context_radix(PyObject *context, PyObject *Py_UNUSED(ignored)) { return _decimal_Context_radix_impl(context); } -/*[clinic end generated code: output=ffc58f98fffed531 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_decimal_Context_logb__doc__, +"logb($self, x, /)\n" +"--\n" +"\n" +"Return the exponent of the magnitude of the operand\'s MSD."); + +#define _DECIMAL_CONTEXT_LOGB_METHODDEF \ + {"logb", (PyCFunction)_decimal_Context_logb, METH_O, _decimal_Context_logb__doc__}, + +PyDoc_STRVAR(_decimal_Context_logical_invert__doc__, +"logical_invert($self, x, /)\n" +"--\n" +"\n" +"Invert all digits of x."); + +#define _DECIMAL_CONTEXT_LOGICAL_INVERT_METHODDEF \ + {"logical_invert", (PyCFunction)_decimal_Context_logical_invert, METH_O, _decimal_Context_logical_invert__doc__}, + +PyDoc_STRVAR(_decimal_Context_logical_and__doc__, +"logical_and($self, x, y, /)\n" +"--\n" +"\n" +"Digit-wise and of x and y."); + +#define _DECIMAL_CONTEXT_LOGICAL_AND_METHODDEF \ + {"logical_and", _PyCFunction_CAST(_decimal_Context_logical_and), METH_FASTCALL, _decimal_Context_logical_and__doc__}, + +static PyObject * +_decimal_Context_logical_and_impl(PyObject *context, PyObject *x, + PyObject *y); + +static PyObject * +_decimal_Context_logical_and(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("logical_and", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_logical_and_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_logical_or__doc__, +"logical_or($self, x, y, /)\n" +"--\n" +"\n" +"Digit-wise or of x and y."); + +#define _DECIMAL_CONTEXT_LOGICAL_OR_METHODDEF \ + {"logical_or", _PyCFunction_CAST(_decimal_Context_logical_or), METH_FASTCALL, _decimal_Context_logical_or__doc__}, + +static PyObject * +_decimal_Context_logical_or_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_logical_or(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("logical_or", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_logical_or_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_logical_xor__doc__, +"logical_xor($self, x, y, /)\n" +"--\n" +"\n" +"Digit-wise xor of x and y."); + +#define _DECIMAL_CONTEXT_LOGICAL_XOR_METHODDEF \ + {"logical_xor", _PyCFunction_CAST(_decimal_Context_logical_xor), METH_FASTCALL, _decimal_Context_logical_xor__doc__}, + +static PyObject * +_decimal_Context_logical_xor_impl(PyObject *context, PyObject *x, + PyObject *y); + +static PyObject * +_decimal_Context_logical_xor(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("logical_xor", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_logical_xor_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_rotate__doc__, +"rotate($self, x, y, /)\n" +"--\n" +"\n" +"Return a copy of x, rotated by y places."); + +#define _DECIMAL_CONTEXT_ROTATE_METHODDEF \ + {"rotate", _PyCFunction_CAST(_decimal_Context_rotate), METH_FASTCALL, _decimal_Context_rotate__doc__}, + +static PyObject * +_decimal_Context_rotate_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_rotate(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("rotate", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_rotate_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_scaleb__doc__, +"scaleb($self, x, y, /)\n" +"--\n" +"\n" +"Return the first operand after adding the second value to its exp."); + +#define _DECIMAL_CONTEXT_SCALEB_METHODDEF \ + {"scaleb", _PyCFunction_CAST(_decimal_Context_scaleb), METH_FASTCALL, _decimal_Context_scaleb__doc__}, + +static PyObject * +_decimal_Context_scaleb_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_scaleb(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("scaleb", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_scaleb_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_shift__doc__, +"shift($self, x, y, /)\n" +"--\n" +"\n" +"Return a copy of x, shifted by y places."); + +#define _DECIMAL_CONTEXT_SHIFT_METHODDEF \ + {"shift", _PyCFunction_CAST(_decimal_Context_shift), METH_FASTCALL, _decimal_Context_shift__doc__}, + +static PyObject * +_decimal_Context_shift_impl(PyObject *context, PyObject *x, PyObject *y); + +static PyObject * +_decimal_Context_shift(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("shift", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_shift_impl(context, x, y); + +exit: + return return_value; +} +/*[clinic end generated code: output=7165f88e99c22606 input=a9049054013a1b77]*/ diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h index 7b286987d1b8e8..4dfa0d4d618627 100644 --- a/Modules/_decimal/docstrings.h +++ b/Modules/_decimal/docstrings.h @@ -10,53 +10,6 @@ #include "pymacro.h" -PyDoc_STRVAR(doc_is_canonical, -"is_canonical($self, /)\n--\n\n\ -Return True if the argument is canonical and False otherwise. Currently,\n\ -a Decimal instance is always canonical, so this operation always returns\n\ -True.\n\ -\n"); - -PyDoc_STRVAR(doc_is_finite, -"is_finite($self, /)\n--\n\n\ -Return True if the argument is a finite number, and False if the argument\n\ -is infinite or a NaN.\n\ -\n"); - -PyDoc_STRVAR(doc_is_infinite, -"is_infinite($self, /)\n--\n\n\ -Return True if the argument is either positive or negative infinity and\n\ -False otherwise.\n\ -\n"); - -PyDoc_STRVAR(doc_is_nan, -"is_nan($self, /)\n--\n\n\ -Return True if the argument is a (quiet or signaling) NaN and False\n\ -otherwise.\n\ -\n"); - -PyDoc_STRVAR(doc_is_qnan, -"is_qnan($self, /)\n--\n\n\ -Return True if the argument is a quiet NaN, and False otherwise.\n\ -\n"); - -PyDoc_STRVAR(doc_is_signed, -"is_signed($self, /)\n--\n\n\ -Return True if the argument has a negative sign and False otherwise.\n\ -Note that both zeros and NaNs can carry signs.\n\ -\n"); - -PyDoc_STRVAR(doc_is_snan, -"is_snan($self, /)\n--\n\n\ -Return True if the argument is a signaling NaN and False otherwise.\n\ -\n"); - -PyDoc_STRVAR(doc_is_zero, -"is_zero($self, /)\n--\n\n\ -Return True if the argument is a (positive or negative) zero and False\n\ -otherwise.\n\ -\n"); - /******************************************************************************/ /* Context Object and Methods */ /******************************************************************************/ @@ -114,31 +67,11 @@ Create a new Decimal instance from float f. Unlike the Decimal.from_float()\n\ class method, this function observes the context limits.\n\ \n"); -PyDoc_STRVAR(doc_ctx_abs, -"abs($self, x, /)\n--\n\n\ -Return the absolute value of x.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_add, -"add($self, x, y, /)\n--\n\n\ -Return the sum of x and y.\n\ -\n"); - PyDoc_STRVAR(doc_ctx_canonical, "canonical($self, x, /)\n--\n\n\ Return a new instance of x.\n\ \n"); -PyDoc_STRVAR(doc_ctx_compare, -"compare($self, x, y, /)\n--\n\n\ -Compare x and y numerically.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_compare_signal, -"compare_signal($self, x, y, /)\n--\n\n\ -Compare x and y numerically. All NaNs signal.\n\ -\n"); - PyDoc_STRVAR(doc_ctx_compare_total, "compare_total($self, x, y, /)\n--\n\n\ Compare x and y using their abstract representation.\n\ @@ -164,65 +97,11 @@ PyDoc_STRVAR(doc_ctx_copy_sign, Copy the sign from y to x.\n\ \n"); -PyDoc_STRVAR(doc_ctx_divide, -"divide($self, x, y, /)\n--\n\n\ -Return x divided by y.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_divide_int, -"divide_int($self, x, y, /)\n--\n\n\ -Return x divided by y, truncated to an integer.\n\ -\n"); - PyDoc_STRVAR(doc_ctx_divmod, "divmod($self, x, y, /)\n--\n\n\ Return quotient and remainder of the division x / y.\n\ \n"); -PyDoc_STRVAR(doc_ctx_exp, -"exp($self, x, /)\n--\n\n\ -Return e ** x.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_fma, -"fma($self, x, y, z, /)\n--\n\n\ -Return x multiplied by y, plus z.\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\ -their numerical value. 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.\n\ -\n"); - -PyDoc_STRVAR(doc_compare_total_mag, -"compare_total_mag($self, /, other, context=None)\n--\n\n\ -Compare two operands using their abstract representation rather than their\n\ -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.\n\ -\n"); - PyDoc_STRVAR(doc_ctx_is_canonical, "is_canonical($self, x, /)\n--\n\n\ Return True if x is canonical, False otherwise.\n\ @@ -273,87 +152,6 @@ PyDoc_STRVAR(doc_ctx_is_zero, Return True if x is a zero, False otherwise.\n\ \n"); -PyDoc_STRVAR(doc_ctx_ln, -"ln($self, x, /)\n--\n\n\ -Return the natural (base e) logarithm of x.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_log10, -"log10($self, x, /)\n--\n\n\ -Return the base 10 logarithm of x.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_logb, -"logb($self, x, /)\n--\n\n\ -Return the exponent of the magnitude of the operand's MSD.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_logical_and, -"logical_and($self, x, y, /)\n--\n\n\ -Digit-wise and of x and y.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_logical_invert, -"logical_invert($self, x, /)\n--\n\n\ -Invert all digits of x.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_logical_or, -"logical_or($self, x, y, /)\n--\n\n\ -Digit-wise or of x and y.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_logical_xor, -"logical_xor($self, x, y, /)\n--\n\n\ -Digit-wise xor of x and y.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_max, -"max($self, x, y, /)\n--\n\n\ -Compare the values numerically and return the maximum.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_max_mag, -"max_mag($self, x, y, /)\n--\n\n\ -Compare the values numerically with their sign ignored.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_min, -"min($self, x, y, /)\n--\n\n\ -Compare the values numerically and return the minimum.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_min_mag, -"min_mag($self, x, y, /)\n--\n\n\ -Compare the values numerically with their sign ignored.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_minus, -"minus($self, x, /)\n--\n\n\ -Minus corresponds to the unary prefix minus operator in Python, but applies\n\ -the context to the result.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_multiply, -"multiply($self, x, y, /)\n--\n\n\ -Return the product of x and y.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_next_minus, -"next_minus($self, x, /)\n--\n\n\ -Return the largest representable number smaller than x.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_next_plus, -"next_plus($self, x, /)\n--\n\n\ -Return the smallest representable number larger than x.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_next_toward, -"next_toward($self, x, y, /)\n--\n\n\ -Return the number closest to x, in the direction towards y.\n\ -\n"); - PyDoc_STRVAR(doc_ctx_normalize, "normalize($self, x, /)\n--\n\n\ Reduce x to its simplest form. Alias for reduce(x).\n\ @@ -364,79 +162,16 @@ PyDoc_STRVAR(doc_ctx_number_class, Return an indication of the class of x.\n\ \n"); -PyDoc_STRVAR(doc_ctx_plus, -"plus($self, x, /)\n--\n\n\ -Plus corresponds to the unary prefix plus operator in Python, but applies\n\ -the context to the result.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_quantize, -"quantize($self, x, y, /)\n--\n\n\ -Return a value equal to x (rounded), having the exponent of y.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_remainder, -"remainder($self, x, y, /)\n--\n\n\ -Return the remainder from integer division. The sign of the result,\n\ -if non-zero, is the same as that of the original dividend.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_remainder_near, -"remainder_near($self, x, y, /)\n--\n\n\ -Return x - y * n, where n is the integer nearest the exact value of x / y\n\ -(if the result is 0 then its sign will be the sign of x).\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_rotate, -"rotate($self, x, y, /)\n--\n\n\ -Return a copy of x, rotated by y places.\n\ -\n"); - PyDoc_STRVAR(doc_ctx_same_quantum, "same_quantum($self, x, y, /)\n--\n\n\ Return True if the two operands have the same exponent.\n\ \n"); -PyDoc_STRVAR(doc_ctx_scaleb, -"scaleb($self, x, y, /)\n--\n\n\ -Return the first operand after adding the second value to its exp.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_shift, -"shift($self, x, y, /)\n--\n\n\ -Return a copy of x, shifted by y places.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_sqrt, -"sqrt($self, x, /)\n--\n\n\ -Square root of a non-negative number to context precision.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_subtract, -"subtract($self, x, y, /)\n--\n\n\ -Return the difference between x and y.\n\ -\n"); - PyDoc_STRVAR(doc_ctx_to_eng_string, "to_eng_string($self, x, /)\n--\n\n\ Convert a number to a string, using engineering notation.\n\ \n"); -PyDoc_STRVAR(doc_ctx_to_integral, -"to_integral($self, x, /)\n--\n\n\ -Identical to to_integral_value(x).\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_to_integral_exact, -"to_integral_exact($self, x, /)\n--\n\n\ -Round to an integer. Signal if the result is rounded or inexact.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_to_integral_value, -"to_integral_value($self, x, /)\n--\n\n\ -Round to an integer.\n\ -\n"); - PyDoc_STRVAR(doc_ctx_to_sci_string, "to_sci_string($self, x, /)\n--\n\n\ Convert a number to a string using scientific notation.\n\ From 3c66cf57f00ebc8a788619952f1f7ce17f18564c Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 21 Aug 2025 06:00:57 +0300 Subject: [PATCH 2/5] +1 --- Modules/_decimal/_decimal.c | 122 +++++++++++++++++++++++---- Modules/_decimal/clinic/_decimal.c.h | 83 +++++++++++++++++- Modules/_decimal/docstrings.h | 45 ---------- 3 files changed, 188 insertions(+), 62 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 93cd1b872d1272..946d19a3bfebd2 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -6023,13 +6023,11 @@ static PyType_Spec dec_spec = { /* Boolean context method. */ #define DecCtx_BoolFunc(MPDFUNC) \ -static PyObject * \ -ctx_##MPDFUNC(PyObject *context, PyObject *v) \ { \ PyObject *ret; \ PyObject *a; \ \ - CONVERT_OP_RAISE(&a, v, context); \ + CONVERT_OP_RAISE(&a, x, context); \ \ ret = MPDFUNC(MPD(a), CTX(context)) ? incr_true() : incr_false(); \ Py_DECREF(a); \ @@ -6038,13 +6036,11 @@ ctx_##MPDFUNC(PyObject *context, PyObject *v) \ /* Boolean context method. MPDFUNC does NOT use a context. */ #define DecCtx_BoolFunc_NO_CTX(MPDFUNC) \ -static PyObject * \ -ctx_##MPDFUNC(PyObject *context, PyObject *v) \ { \ PyObject *ret; \ PyObject *a; \ \ - CONVERT_OP_RAISE(&a, v, context); \ + CONVERT_OP_RAISE(&a, x, context); \ \ ret = MPDFUNC(MPD(a)) ? incr_true() : incr_false(); \ Py_DECREF(a); \ @@ -6654,14 +6650,108 @@ _decimal_Context_radix_impl(PyObject *context) } /* Boolean functions: single decimal argument */ + +/*[clinic input] +_decimal.Context.is_normal + + self as context: self + x: object + / + +Return True if x is a normal number, False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_is_normal(PyObject *context, PyObject *x) +/*[clinic end generated code: output=fed613aed8b286de input=1e7ff3f560842b8d]*/ DecCtx_BoolFunc(mpd_isnormal) + +/*[clinic input] +_decimal.Context.is_subnormal = _decimal.Context.is_normal + +Return True if x is subnormal, False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_is_subnormal(PyObject *context, PyObject *x) +/*[clinic end generated code: output=834450c602d58759 input=73f1bd9367b913a4]*/ DecCtx_BoolFunc(mpd_issubnormal) + +/*[clinic input] +_decimal.Context.is_finite = _decimal.Context.is_normal + +Return True if x is finite, False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_is_finite(PyObject *context, PyObject *x) +/*[clinic end generated code: output=45606d2f56874fef input=abff92a8a6bb85e6]*/ DecCtx_BoolFunc_NO_CTX(mpd_isfinite) + +/*[clinic input] +_decimal.Context.is_infinite = _decimal.Context.is_normal + +Return True if x is infinite, False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_is_infinite(PyObject *context, PyObject *x) +/*[clinic end generated code: output=35c480cd0a2c3cf9 input=591242ae9a1e60e6]*/ DecCtx_BoolFunc_NO_CTX(mpd_isinfinite) + +/*[clinic input] +_decimal.Context.is_nan = _decimal.Context.is_normal + +Return True if x is a qNaN or sNaN, False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_is_nan(PyObject *context, PyObject *x) +/*[clinic end generated code: output=cb529f55bf3106b3 input=520218376d5eec5e]*/ DecCtx_BoolFunc_NO_CTX(mpd_isnan) + +/*[clinic input] +_decimal.Context.is_qnan = _decimal.Context.is_normal + +Return True if x is a quiet NaN, False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_is_qnan(PyObject *context, PyObject *x) +/*[clinic end generated code: output=3e2e750eb643db1d input=97d06a14ab3360d1]*/ DecCtx_BoolFunc_NO_CTX(mpd_isqnan) -DecCtx_BoolFunc_NO_CTX(mpd_issigned) + +/*[clinic input] +_decimal.Context.is_snan = _decimal.Context.is_normal + +Return True if x is a signaling NaN, False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_is_snan(PyObject *context, PyObject *x) +/*[clinic end generated code: output=a7ead03a2dfa15e4 input=0059fe4e9c3b25a8]*/ DecCtx_BoolFunc_NO_CTX(mpd_issnan) + +/*[clinic input] +_decimal.Context.is_signed = _decimal.Context.is_normal + +Return True if x is negative, False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_is_signed(PyObject *context, PyObject *x) +/*[clinic end generated code: output=c85cc15479d5ed47 input=b950cd697721ab8b]*/ +DecCtx_BoolFunc_NO_CTX(mpd_issigned) + +/*[clinic input] +_decimal.Context.is_zero = _decimal.Context.is_normal + +Return True if x is a zero, False otherwise. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_is_zero(PyObject *context, PyObject *x) +/*[clinic end generated code: output=24150f3c2422ebf8 input=bf08197d142a8027]*/ DecCtx_BoolFunc_NO_CTX(mpd_iszero) static PyObject * @@ -7015,15 +7105,15 @@ static PyMethodDef context_methods [] = /* Boolean functions */ { "is_canonical", ctx_iscanonical, METH_O, doc_ctx_is_canonical }, - { "is_finite", ctx_mpd_isfinite, METH_O, doc_ctx_is_finite }, - { "is_infinite", ctx_mpd_isinfinite, METH_O, doc_ctx_is_infinite }, - { "is_nan", ctx_mpd_isnan, METH_O, doc_ctx_is_nan }, - { "is_normal", ctx_mpd_isnormal, METH_O, doc_ctx_is_normal }, - { "is_qnan", ctx_mpd_isqnan, METH_O, doc_ctx_is_qnan }, - { "is_signed", ctx_mpd_issigned, METH_O, doc_ctx_is_signed }, - { "is_snan", ctx_mpd_issnan, METH_O, doc_ctx_is_snan }, - { "is_subnormal", ctx_mpd_issubnormal, METH_O, doc_ctx_is_subnormal }, - { "is_zero", ctx_mpd_iszero, METH_O, doc_ctx_is_zero }, + _DECIMAL_CONTEXT_IS_FINITE_METHODDEF + _DECIMAL_CONTEXT_IS_INFINITE_METHODDEF + _DECIMAL_CONTEXT_IS_NAN_METHODDEF + _DECIMAL_CONTEXT_IS_NORMAL_METHODDEF + _DECIMAL_CONTEXT_IS_QNAN_METHODDEF + _DECIMAL_CONTEXT_IS_SIGNED_METHODDEF + _DECIMAL_CONTEXT_IS_SNAN_METHODDEF + _DECIMAL_CONTEXT_IS_SUBNORMAL_METHODDEF + _DECIMAL_CONTEXT_IS_ZERO_METHODDEF /* Functions with a single decimal argument */ { "_apply", PyDecContext_Apply, METH_O, NULL }, /* alias for apply */ diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index 5473b246e7ca70..f0b3d691781951 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -4144,6 +4144,87 @@ _decimal_Context_radix(PyObject *context, PyObject *Py_UNUSED(ignored)) return _decimal_Context_radix_impl(context); } +PyDoc_STRVAR(_decimal_Context_is_normal__doc__, +"is_normal($self, x, /)\n" +"--\n" +"\n" +"Return True if x is a normal number, False otherwise."); + +#define _DECIMAL_CONTEXT_IS_NORMAL_METHODDEF \ + {"is_normal", (PyCFunction)_decimal_Context_is_normal, METH_O, _decimal_Context_is_normal__doc__}, + +PyDoc_STRVAR(_decimal_Context_is_subnormal__doc__, +"is_subnormal($self, x, /)\n" +"--\n" +"\n" +"Return True if x is subnormal, False otherwise."); + +#define _DECIMAL_CONTEXT_IS_SUBNORMAL_METHODDEF \ + {"is_subnormal", (PyCFunction)_decimal_Context_is_subnormal, METH_O, _decimal_Context_is_subnormal__doc__}, + +PyDoc_STRVAR(_decimal_Context_is_finite__doc__, +"is_finite($self, x, /)\n" +"--\n" +"\n" +"Return True if x is finite, False otherwise."); + +#define _DECIMAL_CONTEXT_IS_FINITE_METHODDEF \ + {"is_finite", (PyCFunction)_decimal_Context_is_finite, METH_O, _decimal_Context_is_finite__doc__}, + +PyDoc_STRVAR(_decimal_Context_is_infinite__doc__, +"is_infinite($self, x, /)\n" +"--\n" +"\n" +"Return True if x is infinite, False otherwise."); + +#define _DECIMAL_CONTEXT_IS_INFINITE_METHODDEF \ + {"is_infinite", (PyCFunction)_decimal_Context_is_infinite, METH_O, _decimal_Context_is_infinite__doc__}, + +PyDoc_STRVAR(_decimal_Context_is_nan__doc__, +"is_nan($self, x, /)\n" +"--\n" +"\n" +"Return True if x is a qNaN or sNaN, False otherwise."); + +#define _DECIMAL_CONTEXT_IS_NAN_METHODDEF \ + {"is_nan", (PyCFunction)_decimal_Context_is_nan, METH_O, _decimal_Context_is_nan__doc__}, + +PyDoc_STRVAR(_decimal_Context_is_qnan__doc__, +"is_qnan($self, x, /)\n" +"--\n" +"\n" +"Return True if x is a quiet NaN, False otherwise."); + +#define _DECIMAL_CONTEXT_IS_QNAN_METHODDEF \ + {"is_qnan", (PyCFunction)_decimal_Context_is_qnan, METH_O, _decimal_Context_is_qnan__doc__}, + +PyDoc_STRVAR(_decimal_Context_is_snan__doc__, +"is_snan($self, x, /)\n" +"--\n" +"\n" +"Return True if x is a signaling NaN, False otherwise."); + +#define _DECIMAL_CONTEXT_IS_SNAN_METHODDEF \ + {"is_snan", (PyCFunction)_decimal_Context_is_snan, METH_O, _decimal_Context_is_snan__doc__}, + +PyDoc_STRVAR(_decimal_Context_is_signed__doc__, +"is_signed($self, x, /)\n" +"--\n" +"\n" +"Return True if x is negative, False otherwise."); + +#define _DECIMAL_CONTEXT_IS_SIGNED_METHODDEF \ + {"is_signed", (PyCFunction)_decimal_Context_is_signed, METH_O, _decimal_Context_is_signed__doc__}, + +PyDoc_STRVAR(_decimal_Context_is_zero__doc__, +"is_zero($self, x, /)\n" +"--\n" +"\n" +"Return True if x is a zero, False otherwise."); + +#define _DECIMAL_CONTEXT_IS_ZERO_METHODDEF \ + {"is_zero", (PyCFunction)_decimal_Context_is_zero, METH_O, _decimal_Context_is_zero__doc__}, + PyDoc_STRVAR(_decimal_Context_logb__doc__, "logb($self, x, /)\n" "--\n" @@ -4343,4 +4424,4 @@ _decimal_Context_shift(PyObject *context, PyObject *const *args, Py_ssize_t narg exit: return return_value; } -/*[clinic end generated code: output=7165f88e99c22606 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a919211d848d4da8 input=a9049054013a1b77]*/ diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h index 4dfa0d4d618627..1308597f478ee2 100644 --- a/Modules/_decimal/docstrings.h +++ b/Modules/_decimal/docstrings.h @@ -107,51 +107,6 @@ PyDoc_STRVAR(doc_ctx_is_canonical, Return True if x is canonical, False otherwise.\n\ \n"); -PyDoc_STRVAR(doc_ctx_is_finite, -"is_finite($self, x, /)\n--\n\n\ -Return True if x is finite, False otherwise.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_is_infinite, -"is_infinite($self, x, /)\n--\n\n\ -Return True if x is infinite, False otherwise.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_is_nan, -"is_nan($self, x, /)\n--\n\n\ -Return True if x is a qNaN or sNaN, False otherwise.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_is_normal, -"is_normal($self, x, /)\n--\n\n\ -Return True if x is a normal number, False otherwise.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_is_qnan, -"is_qnan($self, x, /)\n--\n\n\ -Return True if x is a quiet NaN, False otherwise.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_is_signed, -"is_signed($self, x, /)\n--\n\n\ -Return True if x is negative, False otherwise.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_is_snan, -"is_snan($self, x, /)\n--\n\n\ -Return True if x is a signaling NaN, False otherwise.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_is_subnormal, -"is_subnormal($self, x, /)\n--\n\n\ -Return True if x is subnormal, False otherwise.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_is_zero, -"is_zero($self, x, /)\n--\n\n\ -Return True if x is a zero, False otherwise.\n\ -\n"); - PyDoc_STRVAR(doc_ctx_normalize, "normalize($self, x, /)\n--\n\n\ Reduce x to its simplest form. Alias for reduce(x).\n\ From d3f8428d385d93d16d440714f8eb02c849821608 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 21 Aug 2025 06:13:34 +0300 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Modules/_decimal/_decimal.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 946d19a3bfebd2..5bb7bfddce471a 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -4346,7 +4346,9 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ return result; \ } -/* Boolean function without a context arg. */ +/* Boolean function without a context arg. + Argument Clinic provides PyObject *self +*/ #define Dec_BoolFunc(MPDFUNC) \ { \ return MPDFUNC(MPD(self)) ? incr_true() : incr_false(); \ @@ -4419,7 +4421,10 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ /* Binary function with an optional context arg. Actual MPDFUNC does NOT take a context. The context is used to record InvalidOperation - if the second operand cannot be converted exactly. */ + if the second operand cannot be converted exactly. + + Argument Clinic provides PyObject *self, PyObject *other, PyObject *context +*/ #define Dec_BinaryFuncVA_NO_CTX(MPDFUNC) \ { \ PyObject *a, *b; \ @@ -6047,7 +6052,9 @@ static PyType_Spec dec_spec = { return ret; \ } -/* Unary context method. */ +/* Unary context method. + Argument Clinic provides PyObject *context, PyObject *x +*/ #define DecCtx_UnaryFunc(MPDFUNC) \ { \ PyObject *result, *a; \ @@ -6071,7 +6078,9 @@ static PyType_Spec dec_spec = { return result; \ } -/* Binary context method. */ +/* Binary context method. + Argument Clinic provides PyObject *context, PyObject *v, PyObject *w +*/ #define DecCtx_BinaryFunc(MPDFUNC) \ { \ PyObject *a, *b; \ @@ -6130,7 +6139,10 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ return result; \ } -/* Ternary context method. */ +/* Ternary context method. + Argument Clinic provides PyObject *context, PyObject *v, PyObject *w, + PyObject *x +*/ #define DecCtx_TernaryFunc(MPDFUNC) \ { \ PyObject *a, *b, *c; \ From 94537e1cf350753415206b8f37cdd665394faa96 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 21 Aug 2025 06:20:49 +0300 Subject: [PATCH 4/5] +2 --- Modules/_decimal/_decimal.c | 40 ++++++++++++----- Modules/_decimal/clinic/_decimal.c.h | 64 +++++++++++++++++++++++++++- Modules/_decimal/docstrings.h | 10 ----- 3 files changed, 93 insertions(+), 21 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 5bb7bfddce471a..dd3fe72663580f 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -6112,18 +6112,11 @@ static PyType_Spec dec_spec = { * The actual MPDFUNC does NOT take a context arg. */ #define DecCtx_BinaryFunc_NO_CTX(MPDFUNC) \ -static PyObject * \ -ctx_##MPDFUNC(PyObject *context, PyObject *args) \ { \ - PyObject *v, *w; \ PyObject *a, *b; \ PyObject *result; \ \ - if (!PyArg_ParseTuple(args, "OO", &v, &w)) { \ - return NULL; \ - } \ - \ - CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ + CONVERT_BINOP_RAISE(&a, &b, x, y, context); \ decimal_state *state = \ get_module_state_from_ctx(context); \ if ((result = dec_alloc(state)) == NULL) { \ @@ -6945,7 +6938,34 @@ ctx_mpd_to_eng(PyObject *context, PyObject *v) } /* Functions with two decimal arguments */ + +/*[clinic input] +_decimal.Context.compare_total + + self as context: self + x: object + y: object + / + +Compare x and y using their abstract representation. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_compare_total_impl(PyObject *context, PyObject *x, + PyObject *y) +/*[clinic end generated code: output=a9299ef125fb2245 input=020b30c9bc2ea2c6]*/ DecCtx_BinaryFunc_NO_CTX(mpd_compare_total) + +/*[clinic input] +_decimal.Context.compare_total_mag = _decimal.Context.compare_total + +Compare x and y using their abstract representation, ignoring sign. +[clinic start generated code]*/ + +static PyObject * +_decimal_Context_compare_total_mag_impl(PyObject *context, PyObject *x, + PyObject *y) +/*[clinic end generated code: output=7c376de9f94feeaf input=2b982e69f932dcb2]*/ DecCtx_BinaryFunc_NO_CTX(mpd_compare_total_mag) static PyObject * @@ -7143,8 +7163,8 @@ static PyMethodDef context_methods [] = { "to_eng_string", ctx_mpd_to_eng, METH_O, doc_ctx_to_eng_string }, /* Functions with two decimal arguments */ - { "compare_total", ctx_mpd_compare_total, METH_VARARGS, doc_ctx_compare_total }, - { "compare_total_mag", ctx_mpd_compare_total_mag, METH_VARARGS, doc_ctx_compare_total_mag }, + _DECIMAL_CONTEXT_COMPARE_TOTAL_METHODDEF + _DECIMAL_CONTEXT_COMPARE_TOTAL_MAG_METHODDEF { "copy_sign", ctx_mpd_qcopy_sign, METH_VARARGS, doc_ctx_copy_sign }, _DECIMAL_CONTEXT_LOGICAL_AND_METHODDEF _DECIMAL_CONTEXT_LOGICAL_OR_METHODDEF diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index f0b3d691781951..06dd1b1b762060 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -4243,6 +4243,68 @@ PyDoc_STRVAR(_decimal_Context_logical_invert__doc__, #define _DECIMAL_CONTEXT_LOGICAL_INVERT_METHODDEF \ {"logical_invert", (PyCFunction)_decimal_Context_logical_invert, METH_O, _decimal_Context_logical_invert__doc__}, +PyDoc_STRVAR(_decimal_Context_compare_total__doc__, +"compare_total($self, x, y, /)\n" +"--\n" +"\n" +"Compare x and y using their abstract representation."); + +#define _DECIMAL_CONTEXT_COMPARE_TOTAL_METHODDEF \ + {"compare_total", _PyCFunction_CAST(_decimal_Context_compare_total), METH_FASTCALL, _decimal_Context_compare_total__doc__}, + +static PyObject * +_decimal_Context_compare_total_impl(PyObject *context, PyObject *x, + PyObject *y); + +static PyObject * +_decimal_Context_compare_total(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("compare_total", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_compare_total_impl(context, x, y); + +exit: + return return_value; +} + +PyDoc_STRVAR(_decimal_Context_compare_total_mag__doc__, +"compare_total_mag($self, x, y, /)\n" +"--\n" +"\n" +"Compare x and y using their abstract representation, ignoring sign."); + +#define _DECIMAL_CONTEXT_COMPARE_TOTAL_MAG_METHODDEF \ + {"compare_total_mag", _PyCFunction_CAST(_decimal_Context_compare_total_mag), METH_FASTCALL, _decimal_Context_compare_total_mag__doc__}, + +static PyObject * +_decimal_Context_compare_total_mag_impl(PyObject *context, PyObject *x, + PyObject *y); + +static PyObject * +_decimal_Context_compare_total_mag(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *x; + PyObject *y; + + if (!_PyArg_CheckPositional("compare_total_mag", nargs, 2, 2)) { + goto exit; + } + x = args[0]; + y = args[1]; + return_value = _decimal_Context_compare_total_mag_impl(context, x, y); + +exit: + return return_value; +} + PyDoc_STRVAR(_decimal_Context_logical_and__doc__, "logical_and($self, x, y, /)\n" "--\n" @@ -4424,4 +4486,4 @@ _decimal_Context_shift(PyObject *context, PyObject *const *args, Py_ssize_t narg exit: return return_value; } -/*[clinic end generated code: output=a919211d848d4da8 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=db00589bcc7a168d input=a9049054013a1b77]*/ diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h index 1308597f478ee2..d9be7d9edf6c9e 100644 --- a/Modules/_decimal/docstrings.h +++ b/Modules/_decimal/docstrings.h @@ -72,16 +72,6 @@ PyDoc_STRVAR(doc_ctx_canonical, Return a new instance of x.\n\ \n"); -PyDoc_STRVAR(doc_ctx_compare_total, -"compare_total($self, x, y, /)\n--\n\n\ -Compare x and y using their abstract representation.\n\ -\n"); - -PyDoc_STRVAR(doc_ctx_compare_total_mag, -"compare_total_mag($self, x, y, /)\n--\n\n\ -Compare x and y using their abstract representation, ignoring sign.\n\ -\n"); - PyDoc_STRVAR(doc_ctx_copy_abs, "copy_abs($self, x, /)\n--\n\n\ Return a copy of x with the sign set to 0.\n\ From 416bce2b962f29042733e802bfaafbcd9a43b287 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 21 Aug 2025 09:47:57 +0300 Subject: [PATCH 5/5] address review: add comments & fix parameter names --- Modules/_decimal/_decimal.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index dd3fe72663580f..7d4801f4c752d9 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -6026,7 +6026,9 @@ static PyType_Spec dec_spec = { /* Macros for converting mpdecimal functions to Context methods */ /************************************************************************/ -/* Boolean context method. */ +/* Boolean context method. + Argument Clinic provides PyObject *context, PyObject *x +*/ #define DecCtx_BoolFunc(MPDFUNC) \ { \ PyObject *ret; \ @@ -6039,7 +6041,9 @@ static PyType_Spec dec_spec = { return ret; \ } -/* Boolean context method. MPDFUNC does NOT use a context. */ +/* Boolean context method. MPDFUNC does NOT use a context. + Argument Clinic provides PyObject *context, PyObject *x +*/ #define DecCtx_BoolFunc_NO_CTX(MPDFUNC) \ { \ PyObject *ret; \ @@ -6079,7 +6083,7 @@ static PyType_Spec dec_spec = { } /* Binary context method. - Argument Clinic provides PyObject *context, PyObject *v, PyObject *w + Argument Clinic provides PyObject *context, PyObject *x, PyObject *y */ #define DecCtx_BinaryFunc(MPDFUNC) \ { \ @@ -6110,6 +6114,7 @@ static PyType_Spec dec_spec = { /* * Binary context method. The context is only used for conversion. * The actual MPDFUNC does NOT take a context arg. + * Argument Clinic provides PyObject *context, PyObject *x, PyObject *y */ #define DecCtx_BinaryFunc_NO_CTX(MPDFUNC) \ { \ @@ -6133,8 +6138,8 @@ static PyType_Spec dec_spec = { } /* Ternary context method. - Argument Clinic provides PyObject *context, PyObject *v, PyObject *w, - PyObject *x + Argument Clinic provides PyObject *context, PyObject *x, PyObject *y, + PyObject *z */ #define DecCtx_TernaryFunc(MPDFUNC) \ { \