From c9ea933586ec0ac686c83d514c56876ac0e259e3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 19 Jan 2017 18:13:09 +0200 Subject: Issue #20186: Converted the math module to Argument Clinic. Patch by Tal Einat. --- Modules/clinic/mathmodule.c.h | 539 ++++++++++++++++++++++++++++++++++++ Modules/mathmodule.c | 631 +++++++++++++++++++++++++----------------- 2 files changed, 923 insertions(+), 247 deletions(-) create mode 100644 Modules/clinic/mathmodule.c.h diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h new file mode 100644 index 0000000..84a7a70 --- /dev/null +++ b/Modules/clinic/mathmodule.c.h @@ -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]*/ diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index e7e34ef..8bd38d0 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -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) } +/*[clinic input] +math.gcd + + x as a: object + y as b: object + / + +greatest common divisor of x and y +[clinic start generated code]*/ + static PyObject * -math_gcd(PyObject *self, PyObject *args) +math_gcd_impl(PyObject *module, PyObject *a, PyObject *b) +/*[clinic end generated code: output=7b2e0c151bd7a5d8 input=c2691e57fb2a98fa]*/ { - PyObject *a, *b, *g; - - if (!PyArg_ParseTuple(args, "OO:gcd", &a, &b)) - return NULL; + 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.") + +/*[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 *self, PyObject *number) { +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.") + +/*[clinic input] +math.floor -static PyObject * math_floor(PyObject *self, PyObject *number) { + 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 , @@ -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,20 +1965,23 @@ PyDoc_STRVAR(math_hypot_doc, e.g. 0.**-5. (for which ValueError needs to be raised.) */ +/*[clinic input] +math.pow + + x: double + y: double + / + +Return x**y (x to the power of y). +[clinic start generated code]*/ + static PyObject * -math_pow(PyObject *self, PyObject *args) +math_pow_impl(PyObject *module, double x, double y) +/*[clinic end generated code: output=fff93e65abccd6b0 input=c26f1f6075088bfd]*/ { - PyObject *ox, *oy; - double r, x, y; + double r; int odd_y; - 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; - /* deal directly with IEEE specials, to cope with problems on various platforms whose semantics don't exactly match C99 */ r = 0.; /* silence compiler warning */ @@ -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) -{ - double a, b; - double rel_tol = 1e-9; - double abs_tol = 0.0; - double diff = 0.0; - long result = 0; +/*[clinic input] +math.isclose -> bool - static char *keywords[] = {"a", "b", "rel_tol", "abs_tol", NULL}; + 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. - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "dd|$dd:isclose", - keywords, - &a, &b, &rel_tol, &abs_tol - )) - return NULL; +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 diff = 0.0; /* 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)) || - (diff <= fabs(rel_tol * a))) || - (diff <= abs_tol)); - - return PyBool_FromLong(result); + return (((diff <= fabs(rel_tol * b)) || + (diff <= fabs(rel_tol * a))) || + (diff <= abs_tol)); } -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 */ }; -- cgit v0.12