bpo-37178: Allow a one argument form of math.perm() (GH-13905)

This commit is contained in:
Raymond Hettinger 2019-06-08 08:58:11 -07:00 committed by GitHub
parent 8cc605acdd
commit e119b3d136
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 34 additions and 9 deletions

View File

@ -210,7 +210,7 @@ Number-theoretic and representation functions
of *x* and are floats. of *x* and are floats.
.. function:: perm(n, k) .. function:: perm(n, k=None)
Return the number of ways to choose *k* items from *n* items Return the number of ways to choose *k* items from *n* items
without repetition and with order. without repetition and with order.
@ -218,6 +218,9 @@ Number-theoretic and representation functions
Evaluates to ``n! / (n - k)!`` when ``k <= n`` and evaluates Evaluates to ``n! / (n - k)!`` when ``k <= n`` and evaluates
to zero when ``k > n``. to zero when ``k > n``.
If *k* is not specified or is None, then *k* defaults to *n*
and the function returns ``n!``.
Raises :exc:`TypeError` if either of the arguments are not integers. Raises :exc:`TypeError` if either of the arguments are not integers.
Raises :exc:`ValueError` if either of the arguments are negative. Raises :exc:`ValueError` if either of the arguments are negative.

View File

@ -1885,8 +1885,13 @@ class IsCloseTests(unittest.TestCase):
self.assertEqual(perm(n, 1), n) self.assertEqual(perm(n, 1), n)
self.assertEqual(perm(n, n), factorial(n)) self.assertEqual(perm(n, n), factorial(n))
# Test one argument form
for n in range(20):
self.assertEqual(perm(n), factorial(n))
self.assertEqual(perm(n, None), factorial(n))
# Raises TypeError if any argument is non-integer or argument count is # Raises TypeError if any argument is non-integer or argument count is
# not 2 # not 1 or 2
self.assertRaises(TypeError, perm, 10, 1.0) self.assertRaises(TypeError, perm, 10, 1.0)
self.assertRaises(TypeError, perm, 10, decimal.Decimal(1.0)) self.assertRaises(TypeError, perm, 10, decimal.Decimal(1.0))
self.assertRaises(TypeError, perm, 10, "1") self.assertRaises(TypeError, perm, 10, "1")
@ -1894,7 +1899,7 @@ class IsCloseTests(unittest.TestCase):
self.assertRaises(TypeError, perm, decimal.Decimal(10.0), 1) self.assertRaises(TypeError, perm, decimal.Decimal(10.0), 1)
self.assertRaises(TypeError, perm, "10", 1) self.assertRaises(TypeError, perm, "10", 1)
self.assertRaises(TypeError, perm, 10) self.assertRaises(TypeError, perm)
self.assertRaises(TypeError, perm, 10, 1, 3) self.assertRaises(TypeError, perm, 10, 1, 3)
self.assertRaises(TypeError, perm) self.assertRaises(TypeError, perm)

View File

@ -0,0 +1,2 @@
For math.perm(n, k), let k default to n, giving the same result as
factorial.

View File

@ -0,0 +1,2 @@
Give math.perm() a one argument form that means the same as
math.factorial().

View File

@ -639,7 +639,7 @@ exit:
} }
PyDoc_STRVAR(math_perm__doc__, PyDoc_STRVAR(math_perm__doc__,
"perm($module, n, k, /)\n" "perm($module, n, k=None, /)\n"
"--\n" "--\n"
"\n" "\n"
"Number of ways to choose k items from n items without repetition and with order.\n" "Number of ways to choose k items from n items without repetition and with order.\n"
@ -647,6 +647,9 @@ PyDoc_STRVAR(math_perm__doc__,
"Evaluates to n! / (n - k)! when k <= n and evaluates\n" "Evaluates to n! / (n - k)! when k <= n and evaluates\n"
"to zero when k > n.\n" "to zero when k > n.\n"
"\n" "\n"
"If k is not specified or is None, then k defaults to n\n"
"and the function returns n!.\n"
"\n"
"Raises TypeError if either of the arguments are not integers.\n" "Raises TypeError if either of the arguments are not integers.\n"
"Raises ValueError if either of the arguments are negative."); "Raises ValueError if either of the arguments are negative.");
@ -661,13 +664,17 @@ math_perm(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
PyObject *n; PyObject *n;
PyObject *k; PyObject *k = Py_None;
if (!_PyArg_CheckPositional("perm", nargs, 2, 2)) { if (!_PyArg_CheckPositional("perm", nargs, 1, 2)) {
goto exit; goto exit;
} }
n = args[0]; n = args[0];
if (nargs < 2) {
goto skip_optional;
}
k = args[1]; k = args[1];
skip_optional:
return_value = math_perm_impl(module, n, k); return_value = math_perm_impl(module, n, k);
exit: exit:
@ -713,4 +720,4 @@ math_comb(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=5004266613284dcc input=a9049054013a1b77]*/ /*[clinic end generated code: output=0eb1e76a769cdd30 input=a9049054013a1b77]*/

View File

@ -3002,7 +3002,7 @@ math_prod_impl(PyObject *module, PyObject *iterable, PyObject *start)
math.perm math.perm
n: object n: object
k: object k: object = None
/ /
Number of ways to choose k items from n items without repetition and with order. Number of ways to choose k items from n items without repetition and with order.
@ -3010,18 +3010,24 @@ Number of ways to choose k items from n items without repetition and with order.
Evaluates to n! / (n - k)! when k <= n and evaluates Evaluates to n! / (n - k)! when k <= n and evaluates
to zero when k > n. to zero when k > n.
If k is not specified or is None, then k defaults to n
and the function returns n!.
Raises TypeError if either of the arguments are not integers. Raises TypeError if either of the arguments are not integers.
Raises ValueError if either of the arguments are negative. Raises ValueError if either of the arguments are negative.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
math_perm_impl(PyObject *module, PyObject *n, PyObject *k) math_perm_impl(PyObject *module, PyObject *n, PyObject *k)
/*[clinic end generated code: output=e021a25469653e23 input=b2e7729d9a1949cf]*/ /*[clinic end generated code: output=e021a25469653e23 input=5311c5a00f359b53]*/
{ {
PyObject *result = NULL, *factor = NULL; PyObject *result = NULL, *factor = NULL;
int overflow, cmp; int overflow, cmp;
long long i, factors; long long i, factors;
if (k == Py_None) {
return math_factorial(module, n);
}
n = PyNumber_Index(n); n = PyNumber_Index(n);
if (n == NULL) { if (n == NULL) {
return NULL; return NULL;