@@ -2494,6 +2494,172 @@ math_isclose_impl(PyObject *module, double a, double b, double rel_tol,
24942494}
24952495
24962496
2497+ /*[clinic input]
2498+ math.prod
2499+
2500+ iterable: object
2501+ /
2502+ *
2503+ start: object(c_default="NULL") = 1
2504+
2505+ Calculate the product of all the elements in the input iterable.
2506+
2507+ The default start value for the product is 1.
2508+
2509+ When the iterable is empty, return the start value. This function is
2510+ intended specifically for use with numeric values and may reject
2511+ non-numeric types.
2512+ [clinic start generated code]*/
2513+
2514+ static PyObject *
2515+ math_prod_impl (PyObject * module , PyObject * iterable , PyObject * start )
2516+ /*[clinic end generated code: output=36153bedac74a198 input=4c5ab0682782ed54]*/
2517+ {
2518+ PyObject * result = start ;
2519+ PyObject * temp , * item , * iter ;
2520+
2521+ iter = PyObject_GetIter (iterable );
2522+ if (iter == NULL ) {
2523+ return NULL ;
2524+ }
2525+
2526+ if (result == NULL ) {
2527+ result = PyLong_FromLong (1 );
2528+ if (result == NULL ) {
2529+ Py_DECREF (iter );
2530+ return NULL ;
2531+ }
2532+ } else {
2533+ Py_INCREF (result );
2534+ }
2535+ #ifndef SLOW_PROD
2536+ /* Fast paths for integers keeping temporary products in C.
2537+ * Assumes all inputs are the same type.
2538+ * If the assumption fails, default to use PyObjects instead.
2539+ */
2540+ if (PyLong_CheckExact (result )) {
2541+ int overflow ;
2542+ long i_result = PyLong_AsLongAndOverflow (result , & overflow );
2543+ /* If this already overflowed, don't even enter the loop. */
2544+ if (overflow == 0 ) {
2545+ Py_DECREF (result );
2546+ result = NULL ;
2547+ }
2548+ /* Loop over all the items in the iterable until we finish, we overflow
2549+ * or we found a non integer element */
2550+ while (result == NULL ) {
2551+ item = PyIter_Next (iter );
2552+ if (item == NULL ) {
2553+ Py_DECREF (iter );
2554+ if (PyErr_Occurred ()) {
2555+ return NULL ;
2556+ }
2557+ return PyLong_FromLong (i_result );
2558+ }
2559+ if (PyLong_CheckExact (item )) {
2560+ long b = PyLong_AsLongAndOverflow (item , & overflow );
2561+ long x = i_result * b ;
2562+ /* Continue if there is no overflow */
2563+ if (overflow == 0
2564+ && x < INT_MAX && x > INT_MIN
2565+ && !(b != 0 && x / i_result != b )) {
2566+ i_result = x ;
2567+ Py_DECREF (item );
2568+ continue ;
2569+ }
2570+ }
2571+ /* Either overflowed or is not an int.
2572+ * Restore real objects and process normally */
2573+ result = PyLong_FromLong (i_result );
2574+ if (result == NULL ) {
2575+ Py_DECREF (item );
2576+ Py_DECREF (iter );
2577+ return NULL ;
2578+ }
2579+ temp = PyNumber_Multiply (result , item );
2580+ Py_DECREF (result );
2581+ Py_DECREF (item );
2582+ result = temp ;
2583+ if (result == NULL ) {
2584+ Py_DECREF (iter );
2585+ return NULL ;
2586+ }
2587+ }
2588+ }
2589+
2590+ /* Fast paths for floats keeping temporary products in C.
2591+ * Assumes all inputs are the same type.
2592+ * If the assumption fails, default to use PyObjects instead.
2593+ */
2594+ if (PyFloat_CheckExact (result )) {
2595+ double f_result = PyFloat_AS_DOUBLE (result );
2596+ Py_DECREF (result );
2597+ result = NULL ;
2598+ while (result == NULL ) {
2599+ item = PyIter_Next (iter );
2600+ if (item == NULL ) {
2601+ Py_DECREF (iter );
2602+ if (PyErr_Occurred ()) {
2603+ return NULL ;
2604+ }
2605+ return PyFloat_FromDouble (f_result );
2606+ }
2607+ if (PyFloat_CheckExact (item )) {
2608+ f_result *= PyFloat_AS_DOUBLE (item );
2609+ Py_DECREF (item );
2610+ continue ;
2611+ }
2612+ if (PyLong_CheckExact (item )) {
2613+ long value ;
2614+ int overflow ;
2615+ value = PyLong_AsLongAndOverflow (item , & overflow );
2616+ if (!overflow ) {
2617+ f_result *= (double )value ;
2618+ Py_DECREF (item );
2619+ continue ;
2620+ }
2621+ }
2622+ result = PyFloat_FromDouble (f_result );
2623+ if (result == NULL ) {
2624+ Py_DECREF (item );
2625+ Py_DECREF (iter );
2626+ return NULL ;
2627+ }
2628+ temp = PyNumber_Multiply (result , item );
2629+ Py_DECREF (result );
2630+ Py_DECREF (item );
2631+ result = temp ;
2632+ if (result == NULL ) {
2633+ Py_DECREF (iter );
2634+ return NULL ;
2635+ }
2636+ }
2637+ }
2638+ #endif
2639+ /* Consume rest of the iterable (if any) that could not be handled
2640+ * by specialized functions above.*/
2641+ for (;;) {
2642+ item = PyIter_Next (iter );
2643+ if (item == NULL ) {
2644+ /* error, or end-of-sequence */
2645+ if (PyErr_Occurred ()) {
2646+ Py_DECREF (result );
2647+ result = NULL ;
2648+ }
2649+ break ;
2650+ }
2651+ temp = PyNumber_Multiply (result , item );
2652+ Py_DECREF (result );
2653+ Py_DECREF (item );
2654+ result = temp ;
2655+ if (result == NULL )
2656+ break ;
2657+ }
2658+ Py_DECREF (iter );
2659+ return result ;
2660+ }
2661+
2662+
24972663static PyMethodDef math_methods [] = {
24982664 {"acos" , math_acos , METH_O , math_acos_doc },
24992665 {"acosh" , math_acosh , METH_O , math_acosh_doc },
@@ -2541,6 +2707,7 @@ static PyMethodDef math_methods[] = {
25412707 {"tan" , math_tan , METH_O , math_tan_doc },
25422708 {"tanh" , math_tanh , METH_O , math_tanh_doc },
25432709 MATH_TRUNC_METHODDEF
2710+ MATH_PROD_METHODDEF
25442711 {NULL, NULL } /* sentinel */
25452712};
25462713
0 commit comments