bpo-37178: Allow a one argument form of math.perm() (GH-13905)
This commit is contained in:
parent
8cc605acdd
commit
e119b3d136
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
For math.perm(n, k), let k default to n, giving the same result as
|
||||||
|
factorial.
|
|
@ -0,0 +1,2 @@
|
||||||
|
Give math.perm() a one argument form that means the same as
|
||||||
|
math.factorial().
|
|
@ -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]*/
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue