(original) (raw)
static PyObject * math_factorial(PyObject *self, PyObject *arg) { long x; 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; } return _lh_factorial(2, x); } PyDoc_STRVAR(math_factorial_doc, "factorial(x) -> Integral\n" "\n" "Find x!. Raise a ValueError if x is negative or non-integral."); static PyObject * math_permutations(PyObject *self, PyObject *args) { long i, n, r; PyObject *result, *iobj, *newresult; /* XXX should r be an optional argument? */ if (!PyArg_ParseTuple(args, "ll:npermutations", &n, &r)) return NULL; if (r < 0 || n < 0) { PyErr_SetString(PyExc_ValueError, "npermutations(n,r) not defined for negative values."); return NULL; } if (r > n) return PyInt_FromLong(0); result = (PyObject *)PyInt_FromLong(1); if (result == NULL) return NULL; for (i=n ; i>n-r ; 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); return NULL; } PyDoc_STRVAR(math_permutations_doc, "npermutations(n, r) -> n! / (n-r)! when 0 <= r <= n or zero when r > n >= 0."); static PyObject * math_combinations(PyObject *self, PyObject *args) { long n, r; PyObject *result, *denom, *newresult; if (!PyArg_ParseTuple(args, "ll:ncombinations", &n, &r)) return NULL; if (r < 0 || n < 0) { PyErr_SetString(PyExc_ValueError, "ncombinations(n,r) not defined for negative values."); return NULL; } if (r > n) return PyInt_FromLong(0); /* XXX swap r with n-r for speed */ result = math_permutations(self, args); if (result == NULL) return NULL; denom = math_factorial(self, PyTuple_GET_ITEM(args, 1)); if (denom == NULL) { Py_DECREF(result); return NULL; } newresult = PyNumber_Divide(result, denom); Py_DECREF(result); Py_DECREF(denom); return newresult; } PyDoc_STRVAR(math_combinations_doc, "ncombinations(n, r) -> n! / r! / (n-r)! when 0 <= r <= n or zero when r > n >= 0."); static PyObject * math_cwr(PyObject *self, PyObject *args) { long n, r; PyObject *nrm1, *newresult; if (!PyArg_ParseTuple(args, "ll:ncombinations_with_replacement", &n, &r)) return NULL; if (r < 0 || n < 0) { PyErr_SetString(PyExc_ValueError, "ncombinations(n,r) not defined for negative values."); return NULL; } if (n == 0) return PyInt_FromLong(r>0 ? 0 : 1); nrm1 = PyInt_FromLong(n+r-1); if (nrm1 == NULL) return NULL; args = PyTuple_Pack(2, nrm1, PyTuple_GET_ITEM(args, 1)); Py_DECREF(nrm1); if (args == NULL) return NULL; newresult = math_combinations(self, args); Py_DECREF(args); return newresult; } PyDoc_STRVAR(math_cwr_doc, "ncombinations_with_replacement(n, r) -> (n+r-1)! / r! / (n-1)! when n>0; otherwise, 0 if r>0 else 1");