Issue #20186: Converted the math module to Argument Clinic.

Patch by Tal Einat.
This commit is contained in:
Serhiy Storchaka 2017-01-19 18:13:09 +02:00
parent b813a0e948
commit c9ea933586
2 changed files with 927 additions and 251 deletions

View File

@ -0,0 +1,539 @@
/*[clinic input]
preserve
[clinic start generated code]*/
PyDoc_STRVAR(math_gcd__doc__,
"gcd($module, x, y, /)\n"
"--\n"
"\n"
"greatest common divisor of x and y");
#define MATH_GCD_METHODDEF \
{"gcd", (PyCFunction)math_gcd, METH_FASTCALL, math_gcd__doc__},
static PyObject *
math_gcd_impl(PyObject *module, PyObject *a, PyObject *b);
static PyObject *
math_gcd(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
PyObject *a;
PyObject *b;
if (!_PyArg_UnpackStack(args, nargs, "gcd",
2, 2,
&a, &b)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("gcd", kwnames)) {
goto exit;
}
return_value = math_gcd_impl(module, a, b);
exit:
return return_value;
}
PyDoc_STRVAR(math_ceil__doc__,
"ceil($module, x, /)\n"
"--\n"
"\n"
"Return the ceiling of x as an Integral.\n"
"\n"
"This is the smallest integer >= x.");
#define MATH_CEIL_METHODDEF \
{"ceil", (PyCFunction)math_ceil, METH_O, math_ceil__doc__},
PyDoc_STRVAR(math_floor__doc__,
"floor($module, x, /)\n"
"--\n"
"\n"
"Return the floor of x as an Integral.\n"
"\n"
"This is the largest integer <= x.");
#define MATH_FLOOR_METHODDEF \
{"floor", (PyCFunction)math_floor, METH_O, math_floor__doc__},
PyDoc_STRVAR(math_fsum__doc__,
"fsum($module, seq, /)\n"
"--\n"
"\n"
"Return an accurate floating point sum of values in the iterable seq.\n"
"\n"
"Assumes IEEE-754 floating point arithmetic.");
#define MATH_FSUM_METHODDEF \
{"fsum", (PyCFunction)math_fsum, METH_O, math_fsum__doc__},
PyDoc_STRVAR(math_factorial__doc__,
"factorial($module, x, /)\n"
"--\n"
"\n"
"Find x!.\n"
"\n"
"Raise a ValueError if x is negative or non-integral.");
#define MATH_FACTORIAL_METHODDEF \
{"factorial", (PyCFunction)math_factorial, METH_O, math_factorial__doc__},
PyDoc_STRVAR(math_trunc__doc__,
"trunc($module, x, /)\n"
"--\n"
"\n"
"Truncates the Real x to the nearest Integral toward 0.\n"
"\n"
"Uses the __trunc__ magic method.");
#define MATH_TRUNC_METHODDEF \
{"trunc", (PyCFunction)math_trunc, METH_O, math_trunc__doc__},
PyDoc_STRVAR(math_frexp__doc__,
"frexp($module, x, /)\n"
"--\n"
"\n"
"Return the mantissa and exponent of x, as pair (m, e).\n"
"\n"
"m is a float and e is an int, such that x = m * 2.**e.\n"
"If x is 0, m and e are both 0. Else 0.5 <= abs(m) < 1.0.");
#define MATH_FREXP_METHODDEF \
{"frexp", (PyCFunction)math_frexp, METH_O, math_frexp__doc__},
static PyObject *
math_frexp_impl(PyObject *module, double x);
static PyObject *
math_frexp(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
double x;
if (!PyArg_Parse(arg, "d:frexp", &x)) {
goto exit;
}
return_value = math_frexp_impl(module, x);
exit:
return return_value;
}
PyDoc_STRVAR(math_ldexp__doc__,
"ldexp($module, x, i, /)\n"
"--\n"
"\n"
"Return x * (2**i).\n"
"\n"
"This is essentially the inverse of frexp().");
#define MATH_LDEXP_METHODDEF \
{"ldexp", (PyCFunction)math_ldexp, METH_FASTCALL, math_ldexp__doc__},
static PyObject *
math_ldexp_impl(PyObject *module, double x, PyObject *i);
static PyObject *
math_ldexp(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
double x;
PyObject *i;
if (!_PyArg_ParseStack(args, nargs, "dO:ldexp",
&x, &i)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("ldexp", kwnames)) {
goto exit;
}
return_value = math_ldexp_impl(module, x, i);
exit:
return return_value;
}
PyDoc_STRVAR(math_modf__doc__,
"modf($module, x, /)\n"
"--\n"
"\n"
"Return the fractional and integer parts of x.\n"
"\n"
"Both results carry the sign of x and are floats.");
#define MATH_MODF_METHODDEF \
{"modf", (PyCFunction)math_modf, METH_O, math_modf__doc__},
static PyObject *
math_modf_impl(PyObject *module, double x);
static PyObject *
math_modf(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
double x;
if (!PyArg_Parse(arg, "d:modf", &x)) {
goto exit;
}
return_value = math_modf_impl(module, x);
exit:
return return_value;
}
PyDoc_STRVAR(math_log__doc__,
"log(x, [base=math.e])\n"
"Return the logarithm of x to the given base.\n"
"\n"
"If the base not specified, returns the natural logarithm (base e) of x.");
#define MATH_LOG_METHODDEF \
{"log", (PyCFunction)math_log, METH_VARARGS, math_log__doc__},
static PyObject *
math_log_impl(PyObject *module, PyObject *x, int group_right_1,
PyObject *base);
static PyObject *
math_log(PyObject *module, PyObject *args)
{
PyObject *return_value = NULL;
PyObject *x;
int group_right_1 = 0;
PyObject *base = NULL;
switch (PyTuple_GET_SIZE(args)) {
case 1:
if (!PyArg_ParseTuple(args, "O:log", &x)) {
goto exit;
}
break;
case 2:
if (!PyArg_ParseTuple(args, "OO:log", &x, &base)) {
goto exit;
}
group_right_1 = 1;
break;
default:
PyErr_SetString(PyExc_TypeError, "math.log requires 1 to 2 arguments");
goto exit;
}
return_value = math_log_impl(module, x, group_right_1, base);
exit:
return return_value;
}
PyDoc_STRVAR(math_log2__doc__,
"log2($module, x, /)\n"
"--\n"
"\n"
"Return the base 2 logarithm of x.");
#define MATH_LOG2_METHODDEF \
{"log2", (PyCFunction)math_log2, METH_O, math_log2__doc__},
PyDoc_STRVAR(math_log10__doc__,
"log10($module, x, /)\n"
"--\n"
"\n"
"Return the base 10 logarithm of x.");
#define MATH_LOG10_METHODDEF \
{"log10", (PyCFunction)math_log10, METH_O, math_log10__doc__},
PyDoc_STRVAR(math_fmod__doc__,
"fmod($module, x, y, /)\n"
"--\n"
"\n"
"Return fmod(x, y), according to platform C.\n"
"\n"
"x % y may differ.");
#define MATH_FMOD_METHODDEF \
{"fmod", (PyCFunction)math_fmod, METH_FASTCALL, math_fmod__doc__},
static PyObject *
math_fmod_impl(PyObject *module, double x, double y);
static PyObject *
math_fmod(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
double x;
double y;
if (!_PyArg_ParseStack(args, nargs, "dd:fmod",
&x, &y)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("fmod", kwnames)) {
goto exit;
}
return_value = math_fmod_impl(module, x, y);
exit:
return return_value;
}
PyDoc_STRVAR(math_hypot__doc__,
"hypot($module, x, y, /)\n"
"--\n"
"\n"
"Return the Euclidean distance, sqrt(x*x + y*y).");
#define MATH_HYPOT_METHODDEF \
{"hypot", (PyCFunction)math_hypot, METH_FASTCALL, math_hypot__doc__},
static PyObject *
math_hypot_impl(PyObject *module, double x, double y);
static PyObject *
math_hypot(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
double x;
double y;
if (!_PyArg_ParseStack(args, nargs, "dd:hypot",
&x, &y)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("hypot", kwnames)) {
goto exit;
}
return_value = math_hypot_impl(module, x, y);
exit:
return return_value;
}
PyDoc_STRVAR(math_pow__doc__,
"pow($module, x, y, /)\n"
"--\n"
"\n"
"Return x**y (x to the power of y).");
#define MATH_POW_METHODDEF \
{"pow", (PyCFunction)math_pow, METH_FASTCALL, math_pow__doc__},
static PyObject *
math_pow_impl(PyObject *module, double x, double y);
static PyObject *
math_pow(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
double x;
double y;
if (!_PyArg_ParseStack(args, nargs, "dd:pow",
&x, &y)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("pow", kwnames)) {
goto exit;
}
return_value = math_pow_impl(module, x, y);
exit:
return return_value;
}
PyDoc_STRVAR(math_degrees__doc__,
"degrees($module, x, /)\n"
"--\n"
"\n"
"Convert angle x from radians to degrees.");
#define MATH_DEGREES_METHODDEF \
{"degrees", (PyCFunction)math_degrees, METH_O, math_degrees__doc__},
static PyObject *
math_degrees_impl(PyObject *module, double x);
static PyObject *
math_degrees(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
double x;
if (!PyArg_Parse(arg, "d:degrees", &x)) {
goto exit;
}
return_value = math_degrees_impl(module, x);
exit:
return return_value;
}
PyDoc_STRVAR(math_radians__doc__,
"radians($module, x, /)\n"
"--\n"
"\n"
"Convert angle x from degrees to radians.");
#define MATH_RADIANS_METHODDEF \
{"radians", (PyCFunction)math_radians, METH_O, math_radians__doc__},
static PyObject *
math_radians_impl(PyObject *module, double x);
static PyObject *
math_radians(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
double x;
if (!PyArg_Parse(arg, "d:radians", &x)) {
goto exit;
}
return_value = math_radians_impl(module, x);
exit:
return return_value;
}
PyDoc_STRVAR(math_isfinite__doc__,
"isfinite($module, x, /)\n"
"--\n"
"\n"
"Return True if x is neither an infinity nor a NaN, and False otherwise.");
#define MATH_ISFINITE_METHODDEF \
{"isfinite", (PyCFunction)math_isfinite, METH_O, math_isfinite__doc__},
static PyObject *
math_isfinite_impl(PyObject *module, double x);
static PyObject *
math_isfinite(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
double x;
if (!PyArg_Parse(arg, "d:isfinite", &x)) {
goto exit;
}
return_value = math_isfinite_impl(module, x);
exit:
return return_value;
}
PyDoc_STRVAR(math_isnan__doc__,
"isnan($module, x, /)\n"
"--\n"
"\n"
"Return True if x is a NaN (not a number), and False otherwise.");
#define MATH_ISNAN_METHODDEF \
{"isnan", (PyCFunction)math_isnan, METH_O, math_isnan__doc__},
static PyObject *
math_isnan_impl(PyObject *module, double x);
static PyObject *
math_isnan(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
double x;
if (!PyArg_Parse(arg, "d:isnan", &x)) {
goto exit;
}
return_value = math_isnan_impl(module, x);
exit:
return return_value;
}
PyDoc_STRVAR(math_isinf__doc__,
"isinf($module, x, /)\n"
"--\n"
"\n"
"Return True if x is a positive or negative infinity, and False otherwise.");
#define MATH_ISINF_METHODDEF \
{"isinf", (PyCFunction)math_isinf, METH_O, math_isinf__doc__},
static PyObject *
math_isinf_impl(PyObject *module, double x);
static PyObject *
math_isinf(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
double x;
if (!PyArg_Parse(arg, "d:isinf", &x)) {
goto exit;
}
return_value = math_isinf_impl(module, x);
exit:
return return_value;
}
PyDoc_STRVAR(math_isclose__doc__,
"isclose($module, /, a, b, *, rel_tol=1e-09, abs_tol=0.0)\n"
"--\n"
"\n"
"Determine whether two floating point numbers are close in value.\n"
"\n"
" rel_tol\n"
" maximum difference for being considered \"close\", relative to the\n"
" magnitude of the input values\n"
" abs_tol\n"
" maximum difference for being considered \"close\", regardless of the\n"
" magnitude of the input values\n"
"\n"
"Return True if a is close in value to b, and False otherwise.\n"
"\n"
"For the values to be considered close, the difference between them\n"
"must be smaller than at least one of the tolerances.\n"
"\n"
"-inf, inf and NaN behave similarly to the IEEE 754 Standard. That\n"
"is, NaN is not close to anything, even itself. inf and -inf are\n"
"only close to themselves.");
#define MATH_ISCLOSE_METHODDEF \
{"isclose", (PyCFunction)math_isclose, METH_FASTCALL, math_isclose__doc__},
static int
math_isclose_impl(PyObject *module, double a, double b, double rel_tol,
double abs_tol);
static PyObject *
math_isclose(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"a", "b", "rel_tol", "abs_tol", NULL};
static _PyArg_Parser _parser = {"dd|$dd:isclose", _keywords, 0};
double a;
double b;
double rel_tol = 1e-09;
double abs_tol = 0.0;
int _return_value;
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&a, &b, &rel_tol, &abs_tol)) {
goto exit;
}
_return_value = math_isclose_impl(module, a, b, rel_tol, abs_tol);
if ((_return_value == -1) && PyErr_Occurred()) {
goto exit;
}
return_value = PyBool_FromLong((long)_return_value);
exit:
return return_value;
}
/*[clinic end generated code: output=71806f73a5c4bf0b input=a9049054013a1b77]*/

View File

@ -55,6 +55,14 @@ raised for division by zero and mod by zero.
#include "Python.h"
#include "_math.h"
#include "clinic/mathmodule.c.h"
/*[clinic input]
module math
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=76bc7002685dd942]*/
/*
sin(pi*x), giving accurate results for all finite x (especially x
integral or close to an integer). This is here for use in the
@ -684,13 +692,21 @@ m_log10(double x)
}
static PyObject *
math_gcd(PyObject *self, PyObject *args)
{
PyObject *a, *b, *g;
/*[clinic input]
math.gcd
if (!PyArg_ParseTuple(args, "OO:gcd", &a, &b))
return NULL;
x as a: object
y as b: object
/
greatest common divisor of x and y
[clinic start generated code]*/
static PyObject *
math_gcd_impl(PyObject *module, PyObject *a, PyObject *b)
/*[clinic end generated code: output=7b2e0c151bd7a5d8 input=c2691e57fb2a98fa]*/
{
PyObject *g;
a = PyNumber_Index(a);
if (a == NULL)
@ -706,10 +722,6 @@ math_gcd(PyObject *self, PyObject *args)
return g;
}
PyDoc_STRVAR(math_gcd_doc,
"gcd(x, y) -> int\n\
greatest common divisor of x and y");
/* Call is_error when errno != 0, and where x is the result libm
* returned. is_error will usually set up an exception and return
@ -753,7 +765,7 @@ is_error(double x)
/*
math_1 is used to wrap a libm function f that takes a double
arguments and returns a double.
argument and returns a double.
The error reporting follows these rules, which are designed to do
the right thing on C89/C99 platforms and IEEE 754/non IEEE 754
@ -926,22 +938,43 @@ math_2(PyObject *args, double (*func) (double, double), const char *funcname)
PyDoc_STRVAR(math_##funcname##_doc, docstring);
FUNC1(acos, acos, 0,
"acos(x)\n\nReturn the arc cosine (measured in radians) of x.")
"acos($module, x, /)\n--\n\n"
"Return the arc cosine (measured in radians) of x.")
FUNC1(acosh, m_acosh, 0,
"acosh(x)\n\nReturn the inverse hyperbolic cosine of x.")
"acosh($module, x, /)\n--\n\n"
"Return the inverse hyperbolic cosine of x.")
FUNC1(asin, asin, 0,
"asin(x)\n\nReturn the arc sine (measured in radians) of x.")
"asin($module, x, /)\n--\n\n"
"Return the arc sine (measured in radians) of x.")
FUNC1(asinh, m_asinh, 0,
"asinh(x)\n\nReturn the inverse hyperbolic sine of x.")
"asinh($module, x, /)\n--\n\n"
"Return the inverse hyperbolic sine of x.")
FUNC1(atan, atan, 0,
"atan(x)\n\nReturn the arc tangent (measured in radians) of x.")
"atan($module, x, /)\n--\n\n"
"Return the arc tangent (measured in radians) of x.")
FUNC2(atan2, m_atan2,
"atan2(y, x)\n\nReturn the arc tangent (measured in radians) of y/x.\n"
"atan2($module, y, x, /)\n--\n\n"
"Return the arc tangent (measured in radians) of y/x.\n\n"
"Unlike atan(y/x), the signs of both x and y are considered.")
FUNC1(atanh, m_atanh, 0,
"atanh(x)\n\nReturn the inverse hyperbolic tangent of x.")
"atanh($module, x, /)\n--\n\n"
"Return the inverse hyperbolic tangent of x.")
static PyObject * math_ceil(PyObject *self, PyObject *number) {
/*[clinic input]
math.ceil
x as number: object
/
Return the ceiling of x as an Integral.
This is the smallest integer >= x.
[clinic start generated code]*/
static PyObject *
math_ceil(PyObject *module, PyObject *number)
/*[clinic end generated code: output=6c3b8a78bc201c67 input=2725352806399cab]*/
{
_Py_IDENTIFIER(__ceil__);
PyObject *method, *result;
@ -956,32 +989,50 @@ static PyObject * math_ceil(PyObject *self, PyObject *number) {
return result;
}
PyDoc_STRVAR(math_ceil_doc,
"ceil(x)\n\nReturn the ceiling of x as an Integral.\n"
"This is the smallest integer >= x.");
FUNC2(copysign, copysign,
"copysign(x, y)\n\nReturn a float with the magnitude (absolute value) "
"of x but the sign \nof y. On platforms that support signed zeros, "
"copysign(1.0, -0.0) \nreturns -1.0.\n")
"copysign($module, x, y, /)\n--\n\n"
"Return a float with the magnitude (absolute value) of x but the sign of y.\n\n"
"On platforms that support signed zeros, copysign(1.0, -0.0)\n"
"returns -1.0.\n")
FUNC1(cos, cos, 0,
"cos(x)\n\nReturn the cosine of x (measured in radians).")
"cos($module, x, /)\n--\n\n"
"Return the cosine of x (measured in radians).")
FUNC1(cosh, cosh, 1,
"cosh(x)\n\nReturn the hyperbolic cosine of x.")
"cosh($module, x, /)\n--\n\n"
"Return the hyperbolic cosine of x.")
FUNC1A(erf, m_erf,
"erf(x)\n\nError function at x.")
"erf($module, x, /)\n--\n\n"
"Error function at x.")
FUNC1A(erfc, m_erfc,
"erfc(x)\n\nComplementary error function at x.")
"erfc($module, x, /)\n--\n\n"
"Complementary error function at x.")
FUNC1(exp, exp, 1,
"exp(x)\n\nReturn e raised to the power of x.")
"exp($module, x, /)\n--\n\n"
"Return e raised to the power of x.")
FUNC1(expm1, m_expm1, 1,
"expm1(x)\n\nReturn exp(x)-1.\n"
"expm1($module, x, /)\n--\n\n"
"Return exp(x)-1.\n\n"
"This function avoids the loss of precision involved in the direct "
"evaluation of exp(x)-1 for small x.")
FUNC1(fabs, fabs, 0,
"fabs(x)\n\nReturn the absolute value of the float x.")
"fabs($module, x, /)\n--\n\n"
"Return the absolute value of the float x.")
static PyObject * math_floor(PyObject *self, PyObject *number) {
/*[clinic input]
math.floor
x as number: object
/
Return the floor of x as an Integral.
This is the largest integer <= x.
[clinic start generated code]*/
static PyObject *
math_floor(PyObject *module, PyObject *number)
/*[clinic end generated code: output=c6a65c4884884b8a input=63af6b5d7ebcc3d6]*/
{
_Py_IDENTIFIER(__floor__);
PyObject *method, *result;
@ -996,27 +1047,31 @@ static PyObject * math_floor(PyObject *self, PyObject *number) {
return result;
}
PyDoc_STRVAR(math_floor_doc,
"floor(x)\n\nReturn the floor of x as an Integral.\n"
"This is the largest integer <= x.");
FUNC1A(gamma, m_tgamma,
"gamma(x)\n\nGamma function at x.")
"gamma($module, x, /)\n--\n\n"
"Gamma function at x.")
FUNC1A(lgamma, m_lgamma,
"lgamma(x)\n\nNatural logarithm of absolute value of Gamma function at x.")
"lgamma($module, x, /)\n--\n\n"
"Natural logarithm of absolute value of Gamma function at x.")
FUNC1(log1p, m_log1p, 0,
"log1p(x)\n\nReturn the natural logarithm of 1+x (base e).\n"
"log1p($module, x, /)\n--\n\n"
"Return the natural logarithm of 1+x (base e).\n\n"
"The result is computed in a way which is accurate for x near zero.")
FUNC1(sin, sin, 0,
"sin(x)\n\nReturn the sine of x (measured in radians).")
"sin($module, x, /)\n--\n\n"
"Return the sine of x (measured in radians).")
FUNC1(sinh, sinh, 1,
"sinh(x)\n\nReturn the hyperbolic sine of x.")
"sinh($module, x, /)\n--\n\n"
"Return the hyperbolic sine of x.")
FUNC1(sqrt, sqrt, 0,
"sqrt(x)\n\nReturn the square root of x.")
"sqrt($module, x, /)\n--\n\n"
"Return the square root of x.")
FUNC1(tan, tan, 0,
"tan(x)\n\nReturn the tangent of x (measured in radians).")
"tan($module, x, /)\n--\n\n"
"Return the tangent of x (measured in radians).")
FUNC1(tanh, tanh, 0,
"tanh(x)\n\nReturn the hyperbolic tangent of x.")
"tanh($module, x, /)\n--\n\n"
"Return the hyperbolic tangent of x.")
/* Precision summation function as msum() by Raymond Hettinger in
<http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/393090>,
@ -1114,8 +1169,20 @@ _fsum_realloc(double **p_ptr, Py_ssize_t n,
Depends on IEEE 754 arithmetic guarantees and half-even rounding.
*/
static PyObject*
math_fsum(PyObject *self, PyObject *seq)
/*[clinic input]
math.fsum
seq: object
/
Return an accurate floating point sum of values in the iterable seq.
Assumes IEEE-754 floating point arithmetic.
[clinic start generated code]*/
static PyObject *
math_fsum(PyObject *module, PyObject *seq)
/*[clinic end generated code: output=ba5c672b87fe34fc input=c51b7d8caf6f6e82]*/
{
PyObject *item, *iter, *sum = NULL;
Py_ssize_t i, j, n = 0, m = NUM_PARTIALS;
@ -1234,10 +1301,6 @@ _fsum_error:
#undef NUM_PARTIALS
PyDoc_STRVAR(math_fsum_doc,
"fsum(iterable)\n\n\
Return an accurate floating point sum of values in the iterable.\n\
Assumes IEEE-754 floating point arithmetic.");
/* Return the smallest integer k such that n < 2**k, or 0 if n == 0.
* Equivalent to floor(lg(x))+1. Also equivalent to: bitwidth_of_type -
@ -1447,6 +1510,7 @@ factorial_odd_part(unsigned long n)
return NULL;
}
/* Lookup table for small factorial values */
static const unsigned long SmallFactorials[] = {
@ -1459,8 +1523,20 @@ static const unsigned long SmallFactorials[] = {
#endif
};
/*[clinic input]
math.factorial
x as arg: object
/
Find x!.
Raise a ValueError if x is negative or non-integral.
[clinic start generated code]*/
static PyObject *
math_factorial(PyObject *self, PyObject *arg)
math_factorial(PyObject *module, PyObject *arg)
/*[clinic end generated code: output=6686f26fae00e9ca input=6d1c8105c0d91fb4]*/
{
long x;
int overflow;
@ -1518,28 +1594,36 @@ math_factorial(PyObject *self, PyObject *arg)
return result;
}
PyDoc_STRVAR(math_factorial_doc,
"factorial(x) -> Integral\n"
"\n"
"Find x!. Raise a ValueError if x is negative or non-integral.");
/*[clinic input]
math.trunc
x: object
/
Truncates the Real x to the nearest Integral toward 0.
Uses the __trunc__ magic method.
[clinic start generated code]*/
static PyObject *
math_trunc(PyObject *self, PyObject *number)
math_trunc(PyObject *module, PyObject *x)
/*[clinic end generated code: output=34b9697b707e1031 input=2168b34e0a09134d]*/
{
_Py_IDENTIFIER(__trunc__);
PyObject *trunc, *result;
if (Py_TYPE(number)->tp_dict == NULL) {
if (PyType_Ready(Py_TYPE(number)) < 0)
if (Py_TYPE(x)->tp_dict == NULL) {
if (PyType_Ready(Py_TYPE(x)) < 0)
return NULL;
}
trunc = _PyObject_LookupSpecial(number, &PyId___trunc__);
trunc = _PyObject_LookupSpecial(x, &PyId___trunc__);
if (trunc == NULL) {
if (!PyErr_Occurred())
PyErr_Format(PyExc_TypeError,
"type %.100s doesn't define __trunc__ method",
Py_TYPE(number)->tp_name);
Py_TYPE(x)->tp_name);
return NULL;
}
result = _PyObject_CallNoArg(trunc);
@ -1547,18 +1631,24 @@ math_trunc(PyObject *self, PyObject *number)
return result;
}
PyDoc_STRVAR(math_trunc_doc,
"trunc(x:Real) -> Integral\n"
"\n"
"Truncates x to the nearest Integral toward 0. Uses the __trunc__ magic method.");
/*[clinic input]
math.frexp
x: double
/
Return the mantissa and exponent of x, as pair (m, e).
m is a float and e is an int, such that x = m * 2.**e.
If x is 0, m and e are both 0. Else 0.5 <= abs(m) < 1.0.
[clinic start generated code]*/
static PyObject *
math_frexp(PyObject *self, PyObject *arg)
math_frexp_impl(PyObject *module, double x)
/*[clinic end generated code: output=03e30d252a15ad4a input=96251c9e208bc6e9]*/
{
int i;
double x = PyFloat_AsDouble(arg);
if (x == -1.0 && PyErr_Occurred())
return NULL;
/* deal with special cases directly, to sidestep platform
differences */
if (Py_IS_NAN(x) || Py_IS_INFINITY(x) || !x) {
@ -1572,27 +1662,31 @@ math_frexp(PyObject *self, PyObject *arg)
return Py_BuildValue("(di)", x, i);
}
PyDoc_STRVAR(math_frexp_doc,
"frexp(x)\n"
"\n"
"Return the mantissa and exponent of x, as pair (m, e).\n"
"m is a float and e is an int, such that x = m * 2.**e.\n"
"If x is 0, m and e are both 0. Else 0.5 <= abs(m) < 1.0.");
/*[clinic input]
math.ldexp
x: double
i: object
/
Return x * (2**i).
This is essentially the inverse of frexp().
[clinic start generated code]*/
static PyObject *
math_ldexp(PyObject *self, PyObject *args)
math_ldexp_impl(PyObject *module, double x, PyObject *i)
/*[clinic end generated code: output=b6892f3c2df9cc6a input=17d5970c1a40a8c1]*/
{
double x, r;
PyObject *oexp;
double r;
long exp;
int overflow;
if (! PyArg_ParseTuple(args, "dO:ldexp", &x, &oexp))
return NULL;
if (PyLong_Check(oexp)) {
if (PyLong_Check(i)) {
/* on overflow, replace exponent with either LONG_MAX
or LONG_MIN, depending on the sign. */
exp = PyLong_AsLongAndOverflow(oexp, &overflow);
exp = PyLong_AsLongAndOverflow(i, &overflow);
if (exp == -1 && PyErr_Occurred())
return NULL;
if (overflow)
@ -1630,16 +1724,23 @@ math_ldexp(PyObject *self, PyObject *args)
return PyFloat_FromDouble(r);
}
PyDoc_STRVAR(math_ldexp_doc,
"ldexp(x, i)\n\n\
Return x * (2**i).");
/*[clinic input]
math.modf
x: double
/
Return the fractional and integer parts of x.
Both results carry the sign of x and are floats.
[clinic start generated code]*/
static PyObject *
math_modf(PyObject *self, PyObject *arg)
math_modf_impl(PyObject *module, double x)
/*[clinic end generated code: output=90cee0260014c3c0 input=b4cfb6786afd9035]*/
{
double y, x = PyFloat_AsDouble(arg);
if (x == -1.0 && PyErr_Occurred())
return NULL;
double y;
/* some platforms don't do the right thing for NaNs and
infinities, so we take care of special cases directly. */
if (!Py_IS_FINITE(x)) {
@ -1656,11 +1757,6 @@ math_modf(PyObject *self, PyObject *arg)
return Py_BuildValue("(dd)", x, y);
}
PyDoc_STRVAR(math_modf_doc,
"modf(x)\n"
"\n"
"Return the fractional and integer parts of x. Both results carry the sign\n"
"of x and are floats.");
/* A decent logarithm is easy to compute even for huge ints, but libm can't
do that by itself -- loghelper can. func is log or log10, and name is
@ -1709,18 +1805,30 @@ loghelper(PyObject* arg, double (*func)(double), const char *funcname)
return math_1(arg, func, 0);
}
/*[clinic input]
math.log
x: object
[
base: object(c_default="NULL") = math.e
]
/
Return the logarithm of x to the given base.
If the base not specified, returns the natural logarithm (base e) of x.
[clinic start generated code]*/
static PyObject *
math_log(PyObject *self, PyObject *args)
math_log_impl(PyObject *module, PyObject *x, int group_right_1,
PyObject *base)
/*[clinic end generated code: output=7b5a39e526b73fc9 input=0f62d5726cbfebbd]*/
{
PyObject *arg;
PyObject *base = NULL;
PyObject *num, *den;
PyObject *ans;
if (!PyArg_UnpackTuple(args, "log", 1, 2, &arg, &base))
return NULL;
num = loghelper(arg, m_log, "log");
num = loghelper(x, m_log, "log");
if (num == NULL || base == NULL)
return num;
@ -1736,40 +1844,58 @@ math_log(PyObject *self, PyObject *args)
return ans;
}
PyDoc_STRVAR(math_log_doc,
"log(x[, base])\n\n\
Return the logarithm of x to the given base.\n\
If the base not specified, returns the natural logarithm (base e) of x.");
/*[clinic input]
math.log2
x: object
/
Return the base 2 logarithm of x.
[clinic start generated code]*/
static PyObject *
math_log2(PyObject *self, PyObject *arg)
math_log2(PyObject *module, PyObject *x)
/*[clinic end generated code: output=5425899a4d5d6acb input=08321262bae4f39b]*/
{
return loghelper(arg, m_log2, "log2");
return loghelper(x, m_log2, "log2");
}
PyDoc_STRVAR(math_log2_doc,
"log2(x)\n\nReturn the base 2 logarithm of x.");
/*[clinic input]
math.log10
x: object
/
Return the base 10 logarithm of x.
[clinic start generated code]*/
static PyObject *
math_log10(PyObject *self, PyObject *arg)
math_log10(PyObject *module, PyObject *x)
/*[clinic end generated code: output=be72a64617df9c6f input=b2469d02c6469e53]*/
{
return loghelper(arg, m_log10, "log10");
return loghelper(x, m_log10, "log10");
}
PyDoc_STRVAR(math_log10_doc,
"log10(x)\n\nReturn the base 10 logarithm of x.");
/*[clinic input]
math.fmod
x: double
y: double
/
Return fmod(x, y), according to platform C.
x % y may differ.
[clinic start generated code]*/
static PyObject *
math_fmod(PyObject *self, PyObject *args)
math_fmod_impl(PyObject *module, double x, double y)
/*[clinic end generated code: output=7559d794343a27b5 input=4f84caa8cfc26a03]*/
{
PyObject *ox, *oy;
double r, x, y;
if (! PyArg_UnpackTuple(args, "fmod", 2, 2, &ox, &oy))
return NULL;
x = PyFloat_AsDouble(ox);
y = PyFloat_AsDouble(oy);
if ((x == -1.0 || y == -1.0) && PyErr_Occurred())
return NULL;
double r;
/* fmod(x, +/-Inf) returns x for finite x. */
if (Py_IS_INFINITY(y) && Py_IS_FINITE(x))
return PyFloat_FromDouble(x);
@ -1789,21 +1915,22 @@ math_fmod(PyObject *self, PyObject *args)
return PyFloat_FromDouble(r);
}
PyDoc_STRVAR(math_fmod_doc,
"fmod(x, y)\n\nReturn fmod(x, y), according to platform C."
" x % y may differ.");
/*[clinic input]
math.hypot
x: double
y: double
/
Return the Euclidean distance, sqrt(x*x + y*y).
[clinic start generated code]*/
static PyObject *
math_hypot(PyObject *self, PyObject *args)
math_hypot_impl(PyObject *module, double x, double y)
/*[clinic end generated code: output=b7686e5be468ef87 input=7f8eea70406474aa]*/
{
PyObject *ox, *oy;
double r, x, y;
if (! PyArg_UnpackTuple(args, "hypot", 2, 2, &ox, &oy))
return NULL;
x = PyFloat_AsDouble(ox);
y = PyFloat_AsDouble(oy);
if ((x == -1.0 || y == -1.0) && PyErr_Occurred())
return NULL;
double r;
/* hypot(x, +/-Inf) returns Inf, even if x is a NaN. */
if (Py_IS_INFINITY(x))
return PyFloat_FromDouble(fabs(x));
@ -1831,8 +1958,6 @@ math_hypot(PyObject *self, PyObject *args)
return PyFloat_FromDouble(r);
}
PyDoc_STRVAR(math_hypot_doc,
"hypot(x, y)\n\nReturn the Euclidean distance, sqrt(x*x + y*y).");
/* pow can't use math_2, but needs its own wrapper: the problem is
that an infinite result can arise either as a result of overflow
@ -1840,19 +1965,22 @@ PyDoc_STRVAR(math_hypot_doc,
e.g. 0.**-5. (for which ValueError needs to be raised.)
*/
static PyObject *
math_pow(PyObject *self, PyObject *args)
{
PyObject *ox, *oy;
double r, x, y;
int odd_y;
/*[clinic input]
math.pow
if (! PyArg_UnpackTuple(args, "pow", 2, 2, &ox, &oy))
return NULL;
x = PyFloat_AsDouble(ox);
y = PyFloat_AsDouble(oy);
if ((x == -1.0 || y == -1.0) && PyErr_Occurred())
return NULL;
x: double
y: double
/
Return x**y (x to the power of y).
[clinic start generated code]*/
static PyObject *
math_pow_impl(PyObject *module, double x, double y)
/*[clinic end generated code: output=fff93e65abccd6b0 input=c26f1f6075088bfd]*/
{
double r;
int odd_y;
/* deal directly with IEEE specials, to cope with problems on various
platforms whose semantics don't exactly match C99 */
@ -1918,107 +2046,139 @@ math_pow(PyObject *self, PyObject *args)
return PyFloat_FromDouble(r);
}
PyDoc_STRVAR(math_pow_doc,
"pow(x, y)\n\nReturn x**y (x to the power of y).");
static const double degToRad = Py_MATH_PI / 180.0;
static const double radToDeg = 180.0 / Py_MATH_PI;
/*[clinic input]
math.degrees
x: double
/
Convert angle x from radians to degrees.
[clinic start generated code]*/
static PyObject *
math_degrees(PyObject *self, PyObject *arg)
math_degrees_impl(PyObject *module, double x)
/*[clinic end generated code: output=7fea78b294acd12f input=81e016555d6e3660]*/
{
double x = PyFloat_AsDouble(arg);
if (x == -1.0 && PyErr_Occurred())
return NULL;
return PyFloat_FromDouble(x * radToDeg);
}
PyDoc_STRVAR(math_degrees_doc,
"degrees(x)\n\n\
Convert angle x from radians to degrees.");
/*[clinic input]
math.radians
x: double
/
Convert angle x from degrees to radians.
[clinic start generated code]*/
static PyObject *
math_radians(PyObject *self, PyObject *arg)
math_radians_impl(PyObject *module, double x)
/*[clinic end generated code: output=34daa47caf9b1590 input=91626fc489fe3d63]*/
{
double x = PyFloat_AsDouble(arg);
if (x == -1.0 && PyErr_Occurred())
return NULL;
return PyFloat_FromDouble(x * degToRad);
}
PyDoc_STRVAR(math_radians_doc,
"radians(x)\n\n\
Convert angle x from degrees to radians.");
/*[clinic input]
math.isfinite
x: double
/
Return True if x is neither an infinity nor a NaN, and False otherwise.
[clinic start generated code]*/
static PyObject *
math_isfinite(PyObject *self, PyObject *arg)
math_isfinite_impl(PyObject *module, double x)
/*[clinic end generated code: output=8ba1f396440c9901 input=46967d254812e54a]*/
{
double x = PyFloat_AsDouble(arg);
if (x == -1.0 && PyErr_Occurred())
return NULL;
return PyBool_FromLong((long)Py_IS_FINITE(x));
}
PyDoc_STRVAR(math_isfinite_doc,
"isfinite(x) -> bool\n\n\
Return True if x is neither an infinity nor a NaN, and False otherwise.");
/*[clinic input]
math.isnan
x: double
/
Return True if x is a NaN (not a number), and False otherwise.
[clinic start generated code]*/
static PyObject *
math_isnan(PyObject *self, PyObject *arg)
math_isnan_impl(PyObject *module, double x)
/*[clinic end generated code: output=f537b4d6df878c3e input=935891e66083f46a]*/
{
double x = PyFloat_AsDouble(arg);
if (x == -1.0 && PyErr_Occurred())
return NULL;
return PyBool_FromLong((long)Py_IS_NAN(x));
}
PyDoc_STRVAR(math_isnan_doc,
"isnan(x) -> bool\n\n\
Return True if x is a NaN (not a number), and False otherwise.");
/*[clinic input]
math.isinf
x: double
/
Return True if x is a positive or negative infinity, and False otherwise.
[clinic start generated code]*/
static PyObject *
math_isinf(PyObject *self, PyObject *arg)
math_isinf_impl(PyObject *module, double x)
/*[clinic end generated code: output=9f00cbec4de7b06b input=32630e4212cf961f]*/
{
double x = PyFloat_AsDouble(arg);
if (x == -1.0 && PyErr_Occurred())
return NULL;
return PyBool_FromLong((long)Py_IS_INFINITY(x));
}
PyDoc_STRVAR(math_isinf_doc,
"isinf(x) -> bool\n\n\
Return True if x is a positive or negative infinity, and False otherwise.");
static PyObject *
math_isclose(PyObject *self, PyObject *args, PyObject *kwargs)
/*[clinic input]
math.isclose -> bool
a: double
b: double
*
rel_tol: double = 1e-09
maximum difference for being considered "close", relative to the
magnitude of the input values
abs_tol: double = 0.0
maximum difference for being considered "close", regardless of the
magnitude of the input values
Determine whether two floating point numbers are close in value.
Return True if a is close in value to b, and False otherwise.
For the values to be considered close, the difference between them
must be smaller than at least one of the tolerances.
-inf, inf and NaN behave similarly to the IEEE 754 Standard. That
is, NaN is not close to anything, even itself. inf and -inf are
only close to themselves.
[clinic start generated code]*/
static int
math_isclose_impl(PyObject *module, double a, double b, double rel_tol,
double abs_tol)
/*[clinic end generated code: output=b73070207511952d input=f28671871ea5bfba]*/
{
double a, b;
double rel_tol = 1e-9;
double abs_tol = 0.0;
double diff = 0.0;
long result = 0;
static char *keywords[] = {"a", "b", "rel_tol", "abs_tol", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "dd|$dd:isclose",
keywords,
&a, &b, &rel_tol, &abs_tol
))
return NULL;
/* sanity check on the inputs */
if (rel_tol < 0.0 || abs_tol < 0.0 ) {
PyErr_SetString(PyExc_ValueError,
"tolerances must be non-negative");
return NULL;
return -1;
}
if ( a == b ) {
/* short circuit exact equality -- needed to catch two infinities of
the same sign. And perhaps speeds things up a bit sometimes.
*/
Py_RETURN_TRUE;
return 1;
}
/* This catches the case of two infinities of opposite sign, or
@ -2029,7 +2189,7 @@ math_isclose(PyObject *self, PyObject *args, PyObject *kwargs)
*/
if (Py_IS_INFINITY(a) || Py_IS_INFINITY(b)) {
Py_RETURN_FALSE;
return 0;
}
/* now do the regular computation
@ -2038,33 +2198,11 @@ math_isclose(PyObject *self, PyObject *args, PyObject *kwargs)
diff = fabs(b - a);
result = (((diff <= fabs(rel_tol * b)) ||
return (((diff <= fabs(rel_tol * b)) ||
(diff <= fabs(rel_tol * a))) ||
(diff <= abs_tol));
return PyBool_FromLong(result);
}
PyDoc_STRVAR(math_isclose_doc,
"isclose(a, b, *, rel_tol=1e-09, abs_tol=0.0) -> bool\n"
"\n"
"Determine whether two floating point numbers are close in value.\n"
"\n"
" rel_tol\n"
" maximum difference for being considered \"close\", relative to the\n"
" magnitude of the input values\n"
" abs_tol\n"
" maximum difference for being considered \"close\", regardless of the\n"
" magnitude of the input values\n"
"\n"
"Return True if a is close in value to b, and False otherwise.\n"
"\n"
"For the values to be considered close, the difference between them\n"
"must be smaller than at least one of the tolerances.\n"
"\n"
"-inf, inf and NaN behave similarly to the IEEE 754 Standard. That\n"
"is, NaN is not close to anything, even itself. inf and -inf are\n"
"only close to themselves.");
static PyMethodDef math_methods[] = {
{"acos", math_acos, METH_O, math_acos_doc},
@ -2074,44 +2212,43 @@ static PyMethodDef math_methods[] = {
{"atan", math_atan, METH_O, math_atan_doc},
{"atan2", math_atan2, METH_VARARGS, math_atan2_doc},
{"atanh", math_atanh, METH_O, math_atanh_doc},
{"ceil", math_ceil, METH_O, math_ceil_doc},
MATH_CEIL_METHODDEF
{"copysign", math_copysign, METH_VARARGS, math_copysign_doc},
{"cos", math_cos, METH_O, math_cos_doc},
{"cosh", math_cosh, METH_O, math_cosh_doc},
{"degrees", math_degrees, METH_O, math_degrees_doc},
MATH_DEGREES_METHODDEF
{"erf", math_erf, METH_O, math_erf_doc},
{"erfc", math_erfc, METH_O, math_erfc_doc},
{"exp", math_exp, METH_O, math_exp_doc},
{"expm1", math_expm1, METH_O, math_expm1_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},
{"fmod", math_fmod, METH_VARARGS, math_fmod_doc},
{"frexp", math_frexp, METH_O, math_frexp_doc},
{"fsum", math_fsum, METH_O, math_fsum_doc},
MATH_FACTORIAL_METHODDEF
MATH_FLOOR_METHODDEF
MATH_FMOD_METHODDEF
MATH_FREXP_METHODDEF
MATH_FSUM_METHODDEF
{"gamma", math_gamma, METH_O, math_gamma_doc},
{"gcd", math_gcd, METH_VARARGS, math_gcd_doc},
{"hypot", math_hypot, METH_VARARGS, math_hypot_doc},
{"isclose", (PyCFunction) math_isclose, METH_VARARGS | METH_KEYWORDS,
math_isclose_doc},
{"isfinite", math_isfinite, METH_O, math_isfinite_doc},
{"isinf", math_isinf, METH_O, math_isinf_doc},
{"isnan", math_isnan, METH_O, math_isnan_doc},
{"ldexp", math_ldexp, METH_VARARGS, math_ldexp_doc},
MATH_GCD_METHODDEF
MATH_HYPOT_METHODDEF
MATH_ISCLOSE_METHODDEF
MATH_ISFINITE_METHODDEF
MATH_ISINF_METHODDEF
MATH_ISNAN_METHODDEF
MATH_LDEXP_METHODDEF
{"lgamma", math_lgamma, METH_O, math_lgamma_doc},
{"log", math_log, METH_VARARGS, math_log_doc},
MATH_LOG_METHODDEF
{"log1p", math_log1p, METH_O, math_log1p_doc},
{"log10", math_log10, METH_O, math_log10_doc},
{"log2", math_log2, METH_O, math_log2_doc},
{"modf", math_modf, METH_O, math_modf_doc},
{"pow", math_pow, METH_VARARGS, math_pow_doc},
{"radians", math_radians, METH_O, math_radians_doc},
MATH_LOG10_METHODDEF
MATH_LOG2_METHODDEF
MATH_MODF_METHODDEF
MATH_POW_METHODDEF
MATH_RADIANS_METHODDEF
{"sin", math_sin, METH_O, math_sin_doc},
{"sinh", math_sinh, METH_O, math_sinh_doc},
{"sqrt", math_sqrt, METH_O, math_sqrt_doc},
{"tan", math_tan, METH_O, math_tan_doc},
{"tanh", math_tanh, METH_O, math_tanh_doc},
{"trunc", math_trunc, METH_O, math_trunc_doc},
MATH_TRUNC_METHODDEF
{NULL, NULL} /* sentinel */
};