mirror of https://github.com/python/cpython
Issue #2138: Add math.factorial().
This commit is contained in:
parent
dd96db63f6
commit
ecbdd2e9b0
|
@ -42,6 +42,10 @@ Number-theoretic and representation functions:
|
||||||
|
|
||||||
Return the absolute value of *x*.
|
Return the absolute value of *x*.
|
||||||
|
|
||||||
|
.. function:: factorial(x)
|
||||||
|
|
||||||
|
Return *x* factorial. Raises :exc:`ValueError` if *x* is not intergral or
|
||||||
|
is negative.
|
||||||
|
|
||||||
.. function:: floor(x)
|
.. function:: floor(x)
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import unittest
|
||||||
import math
|
import math
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import random
|
||||||
|
|
||||||
eps = 1E-05
|
eps = 1E-05
|
||||||
NAN = float('nan')
|
NAN = float('nan')
|
||||||
|
@ -277,6 +278,20 @@ class MathTests(unittest.TestCase):
|
||||||
self.ftest('fabs(0)', math.fabs(0), 0)
|
self.ftest('fabs(0)', math.fabs(0), 0)
|
||||||
self.ftest('fabs(1)', math.fabs(1), 1)
|
self.ftest('fabs(1)', math.fabs(1), 1)
|
||||||
|
|
||||||
|
def testFactorial(self):
|
||||||
|
def fact(n):
|
||||||
|
result = 1
|
||||||
|
for i in range(1, int(n)+1):
|
||||||
|
result *= i
|
||||||
|
return result
|
||||||
|
values = range(10) + [50, 100, 500]
|
||||||
|
random.shuffle(values)
|
||||||
|
for x in range(10):
|
||||||
|
for cast in (int, long, float):
|
||||||
|
self.assertEqual(math.factorial(cast(x)), fact(x), (x, fact(x), math.factorial(x)))
|
||||||
|
self.assertRaises(ValueError, math.factorial, -1)
|
||||||
|
self.assertRaises(ValueError, math.factorial, math.pi)
|
||||||
|
|
||||||
def testFloor(self):
|
def testFloor(self):
|
||||||
self.assertRaises(TypeError, math.floor)
|
self.assertRaises(TypeError, math.floor)
|
||||||
# These types will be int in py3k.
|
# These types will be int in py3k.
|
||||||
|
|
|
@ -40,6 +40,8 @@ Core and Builtins
|
||||||
Extension Modules
|
Extension Modules
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #2138: Add factorial() the math module.
|
||||||
|
|
||||||
- The heapq module does comparisons using LT instead of LE. This
|
- The heapq module does comparisons using LT instead of LE. This
|
||||||
makes its implementation match that used by list.sort().
|
makes its implementation match that used by list.sort().
|
||||||
|
|
||||||
|
|
|
@ -512,6 +512,55 @@ PyDoc_STRVAR(math_sum_doc,
|
||||||
Return an accurate floating point sum of values in the iterable.\n\
|
Return an accurate floating point sum of values in the iterable.\n\
|
||||||
Assumes IEEE-754 floating point arithmetic.");
|
Assumes IEEE-754 floating point arithmetic.");
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
math_factorial(PyObject *self, PyObject *arg)
|
||||||
|
{
|
||||||
|
long i, x;
|
||||||
|
PyObject *result, *iobj, *newresult;
|
||||||
|
|
||||||
|
if (PyFloat_Check(arg)) {
|
||||||
|
double dx = PyFloat_AS_DOUBLE((PyFloatObject *)arg);
|
||||||
|
if (dx != floor(dx)) {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"factorial() only accepts integral values");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x = PyInt_AsLong(arg);
|
||||||
|
if (x == -1 && PyErr_Occurred())
|
||||||
|
return NULL;
|
||||||
|
if (x < 0) {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"factorial() not defined for negative values");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = (PyObject *)PyInt_FromLong(1);
|
||||||
|
if (result == NULL)
|
||||||
|
return NULL;
|
||||||
|
for (i=1 ; i<=x ; i++) {
|
||||||
|
iobj = (PyObject *)PyInt_FromLong(i);
|
||||||
|
if (iobj == NULL)
|
||||||
|
goto error;
|
||||||
|
newresult = PyNumber_Multiply(result, iobj);
|
||||||
|
Py_DECREF(iobj);
|
||||||
|
if (newresult == NULL)
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(result);
|
||||||
|
result = newresult;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_DECREF(result);
|
||||||
|
Py_XDECREF(iobj);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(math_factorial_doc, "Return n!");
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
math_trunc(PyObject *self, PyObject *number)
|
math_trunc(PyObject *self, PyObject *number)
|
||||||
{
|
{
|
||||||
|
@ -949,6 +998,7 @@ static PyMethodDef math_methods[] = {
|
||||||
{"degrees", math_degrees, METH_O, math_degrees_doc},
|
{"degrees", math_degrees, METH_O, math_degrees_doc},
|
||||||
{"exp", math_exp, METH_O, math_exp_doc},
|
{"exp", math_exp, METH_O, math_exp_doc},
|
||||||
{"fabs", math_fabs, METH_O, math_fabs_doc},
|
{"fabs", math_fabs, METH_O, math_fabs_doc},
|
||||||
|
{"factorial", math_factorial, METH_O, math_factorial_doc},
|
||||||
{"floor", math_floor, METH_O, math_floor_doc},
|
{"floor", math_floor, METH_O, math_floor_doc},
|
||||||
{"fmod", math_fmod, METH_VARARGS, math_fmod_doc},
|
{"fmod", math_fmod, METH_VARARGS, math_fmod_doc},
|
||||||
{"frexp", math_frexp, METH_O, math_frexp_doc},
|
{"frexp", math_frexp, METH_O, math_frexp_doc},
|
||||||
|
|
Loading…
Reference in New Issue