summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Modules/mathmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tools/python3/Modules/mathmodule.c')
-rw-r--r--contrib/tools/python3/Modules/mathmodule.c144
1 files changed, 103 insertions, 41 deletions
diff --git a/contrib/tools/python3/Modules/mathmodule.c b/contrib/tools/python3/Modules/mathmodule.c
index d856ff6c354..aee1b17be9c 100644
--- a/contrib/tools/python3/Modules/mathmodule.c
+++ b/contrib/tools/python3/Modules/mathmodule.c
@@ -57,6 +57,7 @@ raised for division by zero and mod by zero.
#endif
#include "Python.h"
+#include "pycore_abstract.h" // _PyNumber_Index()
#include "pycore_bitutils.h" // _Py_bit_length()
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_long.h" // _PyLong_GetZero()
@@ -758,13 +759,17 @@ m_log10(double x)
static PyObject *
math_gcd(PyObject *module, PyObject * const *args, Py_ssize_t nargs)
{
- PyObject *res, *x;
- Py_ssize_t i;
+ // Fast-path for the common case: gcd(int, int)
+ if (nargs == 2 && PyLong_CheckExact(args[0]) && PyLong_CheckExact(args[1]))
+ {
+ return _PyLong_GCD(args[0], args[1]);
+ }
if (nargs == 0) {
return PyLong_FromLong(0);
}
- res = PyNumber_Index(args[0]);
+
+ PyObject *res = PyNumber_Index(args[0]);
if (res == NULL) {
return NULL;
}
@@ -774,8 +779,8 @@ math_gcd(PyObject *module, PyObject * const *args, Py_ssize_t nargs)
}
PyObject *one = _PyLong_GetOne(); // borrowed ref
- for (i = 1; i < nargs; i++) {
- x = _PyNumber_Index(args[i]);
+ for (Py_ssize_t i = 1; i < nargs; i++) {
+ PyObject *x = _PyNumber_Index(args[i]);
if (x == NULL) {
Py_DECREF(res);
return NULL;
@@ -1124,8 +1129,12 @@ static PyObject *
math_ceil(PyObject *module, PyObject *number)
/*[clinic end generated code: output=6c3b8a78bc201c67 input=2725352806399cab]*/
{
+ double x;
- if (!PyFloat_CheckExact(number)) {
+ if (PyFloat_CheckExact(number)) {
+ x = PyFloat_AS_DOUBLE(number);
+ }
+ else {
math_module_state *state = get_math_module_state(module);
PyObject *method = _PyObject_LookupSpecial(number, state->str___ceil__);
if (method != NULL) {
@@ -1135,11 +1144,10 @@ math_ceil(PyObject *module, PyObject *number)
}
if (PyErr_Occurred())
return NULL;
+ x = PyFloat_AsDouble(number);
+ if (x == -1.0 && PyErr_Occurred())
+ return NULL;
}
- double x = PyFloat_AsDouble(number);
- if (x == -1.0 && PyErr_Occurred())
- return NULL;
-
return PyLong_FromDouble(ceil(x));
}
@@ -1195,8 +1203,7 @@ math_floor(PyObject *module, PyObject *number)
if (PyFloat_CheckExact(number)) {
x = PyFloat_AS_DOUBLE(number);
}
- else
- {
+ else {
math_module_state *state = get_math_module_state(module);
PyObject *method = _PyObject_LookupSpecial(number, state->str___floor__);
if (method != NULL) {
@@ -2002,13 +2009,11 @@ math.factorial
/
Find n!.
-
-Raise a ValueError if x is negative or non-integral.
[clinic start generated code]*/
static PyObject *
math_factorial(PyObject *module, PyObject *arg)
-/*[clinic end generated code: output=6686f26fae00e9ca input=713fb771677e8c31]*/
+/*[clinic end generated code: output=6686f26fae00e9ca input=366cc321df3d4773]*/
{
long x, two_valuation;
int overflow;
@@ -2067,11 +2072,6 @@ math_trunc(PyObject *module, PyObject *x)
return PyFloat_Type.tp_as_number->nb_int(x);
}
- if (!_PyType_IsReady(Py_TYPE(x))) {
- if (PyType_Ready(Py_TYPE(x)) < 0)
- return NULL;
- }
-
math_module_state *state = get_math_module_state(module);
trunc = _PyObject_LookupSpecial(x, state->str___trunc__);
if (trunc == NULL) {
@@ -2166,6 +2166,27 @@ math_ldexp_impl(PyObject *module, double x, PyObject *i)
} else {
errno = 0;
r = ldexp(x, (int)exp);
+#ifdef _MSC_VER
+ if (DBL_MIN > r && r > -DBL_MIN) {
+ /* Denormal (or zero) results can be incorrectly rounded here (rather,
+ truncated). Fixed in newer versions of the C runtime, included
+ with Windows 11. */
+ int original_exp;
+ frexp(x, &original_exp);
+ if (original_exp > DBL_MIN_EXP) {
+ /* Shift down to the smallest normal binade. No bits lost. */
+ int shift = DBL_MIN_EXP - original_exp;
+ x = ldexp(x, shift);
+ exp -= shift;
+ }
+ /* Multiplying by 2**exp finishes the job, and the HW will round as
+ appropriate. Note: if exp < -DBL_MANT_DIG, all of x is shifted
+ to be < 0.5ULP of smallest denorm, so should be thrown away. If
+ exp is so very negative that ldexp underflows to 0, that's fine;
+ no need to check in advance. */
+ r = x*ldexp(1.0, (int)exp);
+ }
+#endif
if (Py_IS_INFINITY(r))
errno = ERANGE;
}
@@ -2194,12 +2215,10 @@ math_modf_impl(PyObject *module, double x)
double y;
/* some platforms don't do the right thing for NaNs and
infinities, so we take care of special cases directly. */
- if (!Py_IS_FINITE(x)) {
- if (Py_IS_INFINITY(x))
- return Py_BuildValue("(dd)", copysign(0., x), x);
- else if (Py_IS_NAN(x))
- return Py_BuildValue("(dd)", x, x);
- }
+ if (Py_IS_INFINITY(x))
+ return Py_BuildValue("(dd)", copysign(0., x), x);
+ else if (Py_IS_NAN(x))
+ return Py_BuildValue("(dd)", x, x);
errno = 0;
x = modf(x, &y);
@@ -2322,6 +2341,48 @@ math_log10(PyObject *module, PyObject *x)
/*[clinic input]
+math.fma
+
+ x: double
+ y: double
+ z: double
+ /
+
+Fused multiply-add operation.
+
+Compute (x * y) + z with a single round.
+[clinic start generated code]*/
+
+static PyObject *
+math_fma_impl(PyObject *module, double x, double y, double z)
+/*[clinic end generated code: output=4fc8626dbc278d17 input=e3ad1f4a4c89626e]*/
+{
+ double r = fma(x, y, z);
+
+ /* Fast path: if we got a finite result, we're done. */
+ if (Py_IS_FINITE(r)) {
+ return PyFloat_FromDouble(r);
+ }
+
+ /* Non-finite result. Raise an exception if appropriate, else return r. */
+ if (Py_IS_NAN(r)) {
+ if (!Py_IS_NAN(x) && !Py_IS_NAN(y) && !Py_IS_NAN(z)) {
+ /* NaN result from non-NaN inputs. */
+ PyErr_SetString(PyExc_ValueError, "invalid operation in fma");
+ return NULL;
+ }
+ }
+ else if (Py_IS_FINITE(x) && Py_IS_FINITE(y) && Py_IS_FINITE(z)) {
+ /* Infinite result from finite inputs. */
+ PyErr_SetString(PyExc_OverflowError, "overflow in fma");
+ return NULL;
+ }
+
+ return PyFloat_FromDouble(r);
+}
+
+
+/*[clinic input]
math.fmod
x: double
@@ -2574,7 +2635,7 @@ math_dist_impl(PyObject *module, PyObject *p, PyObject *q)
goto error_exit;
}
if (n > NUM_STACK_ELEMS) {
- diffs = (double *) PyObject_Malloc(n * sizeof(double));
+ diffs = (double *) PyMem_Malloc(n * sizeof(double));
if (diffs == NULL) {
PyErr_NoMemory();
goto error_exit;
@@ -2594,7 +2655,7 @@ math_dist_impl(PyObject *module, PyObject *p, PyObject *q)
}
result = vector_norm(n, diffs, max, found_nan);
if (diffs != diffs_on_stack) {
- PyObject_Free(diffs);
+ PyMem_Free(diffs);
}
if (p_allocated) {
Py_DECREF(p);
@@ -2606,7 +2667,7 @@ math_dist_impl(PyObject *module, PyObject *p, PyObject *q)
error_exit:
if (diffs != diffs_on_stack) {
- PyObject_Free(diffs);
+ PyMem_Free(diffs);
}
if (p_allocated) {
Py_DECREF(p);
@@ -2630,7 +2691,7 @@ math_hypot(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
double *coordinates = coord_on_stack;
if (nargs > NUM_STACK_ELEMS) {
- coordinates = (double *) PyObject_Malloc(nargs * sizeof(double));
+ coordinates = (double *) PyMem_Malloc(nargs * sizeof(double));
if (coordinates == NULL) {
return PyErr_NoMemory();
}
@@ -2647,13 +2708,13 @@ math_hypot(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
}
result = vector_norm(nargs, coordinates, max, found_nan);
if (coordinates != coord_on_stack) {
- PyObject_Free(coordinates);
+ PyMem_Free(coordinates);
}
return PyFloat_FromDouble(result);
error_exit:
if (coordinates != coord_on_stack) {
- PyObject_Free(coordinates);
+ PyMem_Free(coordinates);
}
return NULL;
}
@@ -2958,7 +3019,8 @@ math_pow_impl(PyObject *module, double x, double y)
else /* y < 0. */
r = odd_y ? copysign(0., x) : 0.;
}
- else if (Py_IS_INFINITY(y)) {
+ else {
+ assert(Py_IS_INFINITY(y));
if (fabs(x) == 1.0)
r = 1.;
else if (y > 0. && fabs(x) > 1.0)
@@ -3488,9 +3550,7 @@ static const uint8_t factorial_trailing_zeros[] = {
static PyObject *
perm_comb_small(unsigned long long n, unsigned long long k, int iscomb)
{
- if (k == 0) {
- return PyLong_FromLong(1);
- }
+ assert(k != 0);
/* For small enough n and k the result fits in the 64-bit range and can
* be calculated without allocating intermediate PyLong objects. */
@@ -4046,20 +4106,20 @@ math_exec(PyObject *module)
if (state->str___trunc__ == NULL) {
return -1;
}
- if (_PyModule_Add(module, "pi", PyFloat_FromDouble(Py_MATH_PI)) < 0) {
+ if (PyModule_Add(module, "pi", PyFloat_FromDouble(Py_MATH_PI)) < 0) {
return -1;
}
- if (_PyModule_Add(module, "e", PyFloat_FromDouble(Py_MATH_E)) < 0) {
+ if (PyModule_Add(module, "e", PyFloat_FromDouble(Py_MATH_E)) < 0) {
return -1;
}
// 2pi
- if (_PyModule_Add(module, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) {
+ if (PyModule_Add(module, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) {
return -1;
}
- if (_PyModule_Add(module, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) {
+ if (PyModule_Add(module, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) {
return -1;
}
- if (_PyModule_Add(module, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) {
+ if (PyModule_Add(module, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) {
return -1;
}
return 0;
@@ -4104,6 +4164,7 @@ static PyMethodDef math_methods[] = {
{"fabs", math_fabs, METH_O, math_fabs_doc},
MATH_FACTORIAL_METHODDEF
MATH_FLOOR_METHODDEF
+ MATH_FMA_METHODDEF
MATH_FMOD_METHODDEF
MATH_FREXP_METHODDEF
MATH_FSUM_METHODDEF
@@ -4144,6 +4205,7 @@ static PyMethodDef math_methods[] = {
static PyModuleDef_Slot math_slots[] = {
{Py_mod_exec, math_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
+ {Py_mod_gil, Py_MOD_GIL_NOT_USED},
{0, NULL}
};