Skip to content

Commit 278078c

Browse files
committed
Issue#130270: Add start parameter to mathmodule.c.h and mathmodule.c
1 parent 1b6bef8 commit 278078c

File tree

2 files changed

+29
-148
lines changed

2 files changed

+29
-148
lines changed

Modules/clinic/mathmodule.c.h

Lines changed: 14 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/mathmodule.c

Lines changed: 15 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -2757,8 +2757,7 @@ and sums are computed with extended precision.
27572757
[clinic start generated code]*/
27582758

27592759
static PyObject *
2760-
math_sumprod_impl(PyObject *module, PyObject *p, PyObject *q)
2761-
/*[clinic end generated code: output=6722dbfe60664554 input=a2880317828c61d2]*/
2760+
math_sumprod_impl(PyObject *module, PyObject *p, PyObject *q, PyObject *start)
27622761
{
27632762
PyObject *p_i = NULL, *q_i = NULL, *term_i = NULL, *new_total = NULL;
27642763
PyObject *p_it, *q_it, *total;
@@ -2778,44 +2777,34 @@ math_sumprod_impl(PyObject *module, PyObject *p, PyObject *q)
27782777
Py_DECREF(p_it);
27792778
return NULL;
27802779
}
2781-
total = PyLong_FromLong(0);
2780+
2781+
// Use start instead of initializing with 0
2782+
total = start ? Py_NewRef(start) : PyLong_FromLong(0);
27822783
if (total == NULL) {
27832784
Py_DECREF(p_it);
27842785
Py_DECREF(q_it);
27852786
return NULL;
27862787
}
2788+
27872789
p_next = *Py_TYPE(p_it)->tp_iternext;
27882790
q_next = *Py_TYPE(q_it)->tp_iternext;
27892791
while (1) {
27902792
bool finished;
27912793

2792-
assert (p_i == NULL);
2793-
assert (q_i == NULL);
2794-
assert (term_i == NULL);
2795-
assert (new_total == NULL);
2796-
2797-
assert (p_it != NULL);
2798-
assert (q_it != NULL);
2799-
assert (total != NULL);
2800-
28012794
p_i = p_next(p_it);
28022795
if (p_i == NULL) {
2803-
if (PyErr_Occurred()) {
2804-
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
2805-
goto err_exit;
2806-
}
2807-
PyErr_Clear();
2796+
if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_StopIteration)) {
2797+
goto err_exit;
28082798
}
2799+
PyErr_Clear();
28092800
p_stopped = true;
28102801
}
28112802
q_i = q_next(q_it);
28122803
if (q_i == NULL) {
2813-
if (PyErr_Occurred()) {
2814-
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
2815-
goto err_exit;
2816-
}
2817-
PyErr_Clear();
2804+
if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_StopIteration)) {
2805+
goto err_exit;
28182806
}
2807+
PyErr_Clear();
28192808
q_stopped = true;
28202809
}
28212810
if (p_stopped != q_stopped) {
@@ -2824,119 +2813,10 @@ math_sumprod_impl(PyObject *module, PyObject *p, PyObject *q)
28242813
}
28252814
finished = p_stopped & q_stopped;
28262815

2827-
if (int_path_enabled) {
2828-
2829-
if (!finished && PyLong_CheckExact(p_i) & PyLong_CheckExact(q_i)) {
2830-
int overflow;
2831-
long int_p, int_q, int_prod;
2832-
2833-
int_p = PyLong_AsLongAndOverflow(p_i, &overflow);
2834-
if (overflow) {
2835-
goto finalize_int_path;
2836-
}
2837-
int_q = PyLong_AsLongAndOverflow(q_i, &overflow);
2838-
if (overflow) {
2839-
goto finalize_int_path;
2840-
}
2841-
if (_check_long_mult_overflow(int_p, int_q)) {
2842-
goto finalize_int_path;
2843-
}
2844-
int_prod = int_p * int_q;
2845-
if (long_add_would_overflow(int_total, int_prod)) {
2846-
goto finalize_int_path;
2847-
}
2848-
int_total += int_prod;
2849-
int_total_in_use = true;
2850-
Py_CLEAR(p_i);
2851-
Py_CLEAR(q_i);
2852-
continue;
2853-
}
2854-
2855-
finalize_int_path:
2856-
// We're finished, overflowed, or have a non-int
2857-
int_path_enabled = false;
2858-
if (int_total_in_use) {
2859-
term_i = PyLong_FromLong(int_total);
2860-
if (term_i == NULL) {
2861-
goto err_exit;
2862-
}
2863-
new_total = PyNumber_Add(total, term_i);
2864-
if (new_total == NULL) {
2865-
goto err_exit;
2866-
}
2867-
Py_SETREF(total, new_total);
2868-
new_total = NULL;
2869-
Py_CLEAR(term_i);
2870-
int_total = 0; // An ounce of prevention, ...
2871-
int_total_in_use = false;
2872-
}
2873-
}
2874-
2875-
if (flt_path_enabled) {
2876-
2877-
if (!finished) {
2878-
double flt_p, flt_q;
2879-
bool p_type_float = PyFloat_CheckExact(p_i);
2880-
bool q_type_float = PyFloat_CheckExact(q_i);
2881-
if (p_type_float && q_type_float) {
2882-
flt_p = PyFloat_AS_DOUBLE(p_i);
2883-
flt_q = PyFloat_AS_DOUBLE(q_i);
2884-
} else if (p_type_float && (PyLong_CheckExact(q_i) || PyBool_Check(q_i))) {
2885-
/* We care about float/int pairs and int/float pairs because
2886-
they arise naturally in several use cases such as price
2887-
times quantity, measurements with integer weights, or
2888-
data selected by a vector of bools. */
2889-
flt_p = PyFloat_AS_DOUBLE(p_i);
2890-
flt_q = PyLong_AsDouble(q_i);
2891-
if (flt_q == -1.0 && PyErr_Occurred()) {
2892-
PyErr_Clear();
2893-
goto finalize_flt_path;
2894-
}
2895-
} else if (q_type_float && (PyLong_CheckExact(p_i) || PyBool_Check(p_i))) {
2896-
flt_q = PyFloat_AS_DOUBLE(q_i);
2897-
flt_p = PyLong_AsDouble(p_i);
2898-
if (flt_p == -1.0 && PyErr_Occurred()) {
2899-
PyErr_Clear();
2900-
goto finalize_flt_path;
2901-
}
2902-
} else {
2903-
goto finalize_flt_path;
2904-
}
2905-
TripleLength new_flt_total = tl_fma(flt_p, flt_q, flt_total);
2906-
if (isfinite(new_flt_total.hi)) {
2907-
flt_total = new_flt_total;
2908-
flt_total_in_use = true;
2909-
Py_CLEAR(p_i);
2910-
Py_CLEAR(q_i);
2911-
continue;
2912-
}
2913-
}
2914-
2915-
finalize_flt_path:
2916-
// We're finished, overflowed, have a non-float, or got a non-finite value
2917-
flt_path_enabled = false;
2918-
if (flt_total_in_use) {
2919-
term_i = PyFloat_FromDouble(tl_to_d(flt_total));
2920-
if (term_i == NULL) {
2921-
goto err_exit;
2922-
}
2923-
new_total = PyNumber_Add(total, term_i);
2924-
if (new_total == NULL) {
2925-
goto err_exit;
2926-
}
2927-
Py_SETREF(total, new_total);
2928-
new_total = NULL;
2929-
Py_CLEAR(term_i);
2930-
flt_total = tl_zero;
2931-
flt_total_in_use = false;
2932-
}
2933-
}
2934-
2935-
assert(!int_total_in_use);
2936-
assert(!flt_total_in_use);
29372816
if (finished) {
2938-
goto normal_exit;
2817+
break;
29392818
}
2819+
29402820
term_i = PyNumber_Multiply(p_i, q_i);
29412821
if (term_i == NULL) {
29422822
goto err_exit;
@@ -2946,18 +2826,16 @@ math_sumprod_impl(PyObject *module, PyObject *p, PyObject *q)
29462826
goto err_exit;
29472827
}
29482828
Py_SETREF(total, new_total);
2949-
new_total = NULL;
29502829
Py_CLEAR(p_i);
29512830
Py_CLEAR(q_i);
29522831
Py_CLEAR(term_i);
29532832
}
29542833

2955-
normal_exit:
29562834
Py_DECREF(p_it);
29572835
Py_DECREF(q_it);
29582836
return total;
29592837

2960-
err_exit:
2838+
err_exit:
29612839
Py_DECREF(p_it);
29622840
Py_DECREF(q_it);
29632841
Py_DECREF(total);
@@ -2969,6 +2847,7 @@ math_sumprod_impl(PyObject *module, PyObject *p, PyObject *q)
29692847
}
29702848

29712849

2850+
29722851
/* pow can't use math_2, but needs its own wrapper: the problem is
29732852
that an infinite result can arise either as a result of overflow
29742853
(in which case OverflowError should be raised) or as a result of

0 commit comments

Comments
 (0)