From 963eb0f4738456455b9bef7eb531b46805415208 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 4 Jun 2019 01:23:06 -0700 Subject: bpo-35431: Drop the k <= n requirement (GH-13798) --- Doc/library/math.rst | 20 ++++++++++++-------- Lib/test/test_math.py | 12 ++++++------ Modules/clinic/mathmodule.c.h | 22 +++++++++++++--------- Modules/mathmodule.c | 33 ++++++++++++++++++--------------- 4 files changed, 49 insertions(+), 38 deletions(-) diff --git a/Doc/library/math.rst b/Doc/library/math.rst index c5a77f1..4a15789 100644 --- a/Doc/library/math.rst +++ b/Doc/library/math.rst @@ -41,12 +41,15 @@ Number-theoretic and representation functions Return the number of ways to choose *k* items from *n* items without repetition and without order. - Also called the binomial coefficient. It is mathematically equal to the expression - ``n! / (k! (n - k)!)``. It is equivalent to the coefficient of the *k*-th term in the - polynomial expansion of the expression ``(1 + x) ** n``. + Evaluates to ``n! / (k! * (n - k)!)`` when ``k <= n`` and evaluates + to zero when ``k > n``. - Raises :exc:`TypeError` if the arguments not integers. - Raises :exc:`ValueError` if the arguments are negative or if *k* > *n*. + Also called the binomial coefficient because it is equivalent + to the coefficient of k-th term in polynomial expansion of the + expression ``(1 + x) ** n``. + + Raises :exc:`TypeError` if either of the arguments not integers. + Raises :exc:`ValueError` if either of the arguments are negative. .. versionadded:: 3.8 @@ -212,10 +215,11 @@ Number-theoretic and representation functions Return the number of ways to choose *k* items from *n* items without repetition and with order. - It is mathematically equal to the expression ``n! / (n - k)!``. + Evaluates to ``n! / (n - k)!`` when ``k <= n`` and evaluates + to zero when ``k > n``. - Raises :exc:`TypeError` if the arguments not integers. - Raises :exc:`ValueError` if the arguments are negative or if *k* > *n*. + Raises :exc:`TypeError` if either of the arguments not integers. + Raises :exc:`ValueError` if either of the arguments are negative. .. versionadded:: 3.8 diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index 96e0cf2..86e3923 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1904,9 +1904,9 @@ class IsCloseTests(unittest.TestCase): self.assertRaises(ValueError, perm, 1, -1) self.assertRaises(ValueError, perm, 1, -2**1000) - # Raises value error if k is greater than n - self.assertRaises(ValueError, perm, 1, 2) - self.assertRaises(ValueError, perm, 1, 2**1000) + # Returns zero if k is greater than n + self.assertEqual(perm(1, 2), 0) + self.assertEqual(perm(1, 2**1000), 0) n = 2**1000 self.assertEqual(perm(n, 0), 1) @@ -1970,9 +1970,9 @@ class IsCloseTests(unittest.TestCase): self.assertRaises(ValueError, comb, 1, -1) self.assertRaises(ValueError, comb, 1, -2**1000) - # Raises value error if k is greater than n - self.assertRaises(ValueError, comb, 1, 2) - self.assertRaises(ValueError, comb, 1, 2**1000) + # Returns zero if k is greater than n + self.assertEqual(comb(1, 2), 0) + self.assertEqual(comb(1, 2**1000), 0) n = 2**1000 self.assertEqual(comb(n, 0), 1) diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h index 0efe5cc..cdf4305 100644 --- a/Modules/clinic/mathmodule.c.h +++ b/Modules/clinic/mathmodule.c.h @@ -644,10 +644,11 @@ PyDoc_STRVAR(math_perm__doc__, "\n" "Number of ways to choose k items from n items without repetition and with order.\n" "\n" -"It is mathematically equal to the expression n! / (n - k)!.\n" +"Evaluates to n! / (n - k)! when k <= n and evaluates\n" +"to zero when k > n.\n" "\n" -"Raises TypeError if the arguments are not integers.\n" -"Raises ValueError if the arguments are negative or if k > n."); +"Raises TypeError if either of the arguments are not integers.\n" +"Raises ValueError if either of the arguments are negative."); #define MATH_PERM_METHODDEF \ {"perm", (PyCFunction)(void(*)(void))math_perm, METH_FASTCALL, math_perm__doc__}, @@ -679,12 +680,15 @@ PyDoc_STRVAR(math_comb__doc__, "\n" "Number of ways to choose k items from n items without repetition and without order.\n" "\n" -"Also called the binomial coefficient. It is mathematically equal to the expression\n" -"n! / (k! * (n - k)!). It is equivalent to the coefficient of k-th term in\n" -"polynomial expansion of the expression (1 + x)**n.\n" +"Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates\n" +"to zero when k > n.\n" "\n" -"Raises TypeError if the arguments are not integers.\n" -"Raises ValueError if the arguments are negative or if k > n."); +"Also called the binomial coefficient because it is equivalent\n" +"to the coefficient of k-th term in polynomial expansion of the\n" +"expression (1 + x)**n.\n" +"\n" +"Raises TypeError if either of the arguments are not integers.\n" +"Raises ValueError if either of the arguments are negative."); #define MATH_COMB_METHODDEF \ {"comb", (PyCFunction)(void(*)(void))math_comb, METH_FASTCALL, math_comb__doc__}, @@ -709,4 +713,4 @@ math_comb(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=a82b0e705b6d0ec0 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5004266613284dcc input=a9049054013a1b77]*/ diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 6e10993..9a9a815 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -3007,15 +3007,16 @@ math.perm Number of ways to choose k items from n items without repetition and with order. -It is mathematically equal to the expression n! / (n - k)!. +Evaluates to n! / (n - k)! when k <= n and evaluates +to zero when k > n. -Raises TypeError if the arguments are not integers. -Raises ValueError if the arguments are negative or if k > n. +Raises TypeError if either of the arguments are not integers. +Raises ValueError if either of the arguments are negative. [clinic start generated code]*/ static PyObject * math_perm_impl(PyObject *module, PyObject *n, PyObject *k) -/*[clinic end generated code: output=e021a25469653e23 input=f71ee4f6ff26be24]*/ +/*[clinic end generated code: output=e021a25469653e23 input=b2e7729d9a1949cf]*/ { PyObject *result = NULL, *factor = NULL; int overflow, cmp; @@ -3052,8 +3053,8 @@ math_perm_impl(PyObject *module, PyObject *n, PyObject *k) cmp = PyObject_RichCompareBool(n, k, Py_LT); if (cmp != 0) { if (cmp > 0) { - PyErr_SetString(PyExc_ValueError, - "k must be an integer less than or equal to n"); + result = PyLong_FromLong(0); + goto done; } goto error; } @@ -3121,18 +3122,21 @@ math.comb Number of ways to choose k items from n items without repetition and without order. -Also called the binomial coefficient. It is mathematically equal to the expression -n! / (k! * (n - k)!). It is equivalent to the coefficient of k-th term in -polynomial expansion of the expression (1 + x)**n. +Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates +to zero when k > n. + +Also called the binomial coefficient because it is equivalent +to the coefficient of k-th term in polynomial expansion of the +expression (1 + x)**n. -Raises TypeError if the arguments are not integers. -Raises ValueError if the arguments are negative or if k > n. +Raises TypeError if either of the arguments are not integers. +Raises ValueError if either of the arguments are negative. [clinic start generated code]*/ static PyObject * math_comb_impl(PyObject *module, PyObject *n, PyObject *k) -/*[clinic end generated code: output=bd2cec8d854f3493 input=2f336ac9ec8242f9]*/ +/*[clinic end generated code: output=bd2cec8d854f3493 input=9a05315af2518709]*/ { PyObject *result = NULL, *factor = NULL, *temp; int overflow, cmp; @@ -3173,9 +3177,8 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k) } if (Py_SIZE(temp) < 0) { Py_DECREF(temp); - PyErr_SetString(PyExc_ValueError, - "k must be an integer less than or equal to n"); - goto error; + result = PyLong_FromLong(0); + goto done; } cmp = PyObject_RichCompareBool(temp, k, Py_LT); if (cmp > 0) { -- cgit v0.12