cpython/Modules/mathmodule.c
Christian Heimes 969fe57baa Merged revisions 60245-60277 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r60246 | guido.van.rossum | 2008-01-24 18:58:05 +0100 (Thu, 24 Jan 2008) | 2 lines

  Fix test67.py from issue #1303614.
........
  r60248 | raymond.hettinger | 2008-01-24 19:05:54 +0100 (Thu, 24 Jan 2008) | 1 line

  Clean-up and speed-up code by accessing numerator/denominator directly.  There's no reason to enforce readonliness
........
  r60249 | raymond.hettinger | 2008-01-24 19:12:23 +0100 (Thu, 24 Jan 2008) | 1 line

  Revert 60189 and restore performance.
........
  r60250 | guido.van.rossum | 2008-01-24 19:21:02 +0100 (Thu, 24 Jan 2008) | 5 lines

  News about recently fixed crashers:
  - A few crashers fixed: weakref_in_del.py (issue #1377858);
    loosing_dict_ref.py (issue #1303614, test67.py);
    borrowed_ref_[34].py (not in tracker).
........
  r60252 | thomas.heller | 2008-01-24 19:36:27 +0100 (Thu, 24 Jan 2008) | 7 lines

  Use a PyDictObject again for the array type cache; retrieving items
  from the WeakValueDictionary was slower by nearly a factor of 3.

  To avoid leaks, weakref proxies for the array types are put into the
  cache dict, with weakref callbacks that removes the entries when the
  type goes away.
........
  r60253 | thomas.heller | 2008-01-24 19:54:12 +0100 (Thu, 24 Jan 2008) | 2 lines

  Replace Py_BuildValue with PyTuple_Pack because it is faster.
  Also add a missing DECREF.
........
  r60254 | raymond.hettinger | 2008-01-24 20:05:29 +0100 (Thu, 24 Jan 2008) | 1 line

  Add support for trunc().
........
  r60255 | thomas.heller | 2008-01-24 20:15:02 +0100 (Thu, 24 Jan 2008) | 5 lines

  Invert the checks in get_[u]long and get_[u]longlong.  The intent was
  to not accept float types; the result was that integer-like objects
  were not accepted.

  Ported from release25-maint.
........
  r60256 | raymond.hettinger | 2008-01-24 20:30:19 +0100 (Thu, 24 Jan 2008) | 1 line

  Add support for int(r) just like the other numeric classes.
........
  r60263 | raymond.hettinger | 2008-01-24 22:23:58 +0100 (Thu, 24 Jan 2008) | 1 line

  Expand tests to include nested graph structures.
........
  r60264 | raymond.hettinger | 2008-01-24 22:47:56 +0100 (Thu, 24 Jan 2008) | 1 line

  Shorter pprint's for empty sets and frozensets.  Fix indentation of frozensets.  Add tests including two complex data structures.
........
  r60265 | amaury.forgeotdarc | 2008-01-24 23:51:18 +0100 (Thu, 24 Jan 2008) | 14 lines

  #1920: when considering a block starting by "while 0", the compiler optimized the
  whole construct away, even when an 'else' clause is present::

      while 0:
          print("no")
      else:
          print("yes")

  did not generate any code at all.

  Now the compiler emits the 'else' block, like it already does for 'if' statements.

  Will backport.
........
  r60266 | amaury.forgeotdarc | 2008-01-24 23:59:25 +0100 (Thu, 24 Jan 2008) | 2 lines

  News entry for r60265 (Issue 1920).
........
  r60269 | raymond.hettinger | 2008-01-25 00:50:26 +0100 (Fri, 25 Jan 2008) | 1 line

  More code cleanup.  Remove unnecessary indirection to useless class methods.
........
  r60270 | raymond.hettinger | 2008-01-25 01:21:54 +0100 (Fri, 25 Jan 2008) | 1 line

  Add support for copy, deepcopy, and pickle.
........
  r60271 | raymond.hettinger | 2008-01-25 01:33:45 +0100 (Fri, 25 Jan 2008) | 1 line

  Mark todos and review comments.
........
  r60272 | raymond.hettinger | 2008-01-25 02:13:12 +0100 (Fri, 25 Jan 2008) | 1 line

  Add one other review comment.
........
  r60273 | raymond.hettinger | 2008-01-25 02:23:38 +0100 (Fri, 25 Jan 2008) | 1 line

  Fix-up signature for approximation.
........
  r60274 | raymond.hettinger | 2008-01-25 02:46:33 +0100 (Fri, 25 Jan 2008) | 1 line

  More design notes
........
  r60276 | neal.norwitz | 2008-01-25 07:37:23 +0100 (Fri, 25 Jan 2008) | 6 lines

  Make the test more robust by trying to reconnect up to 3 times
  in case there were transient failures.  This will hopefully silence
  the buildbots for this test.  As we find other tests that have a problem,
  we can fix with a similar strategy assuming it is successful.  It worked
  on my box in a loop for 10+ runs where it would have an exception otherwise.
........
  r60277 | neal.norwitz | 2008-01-25 09:04:16 +0100 (Fri, 25 Jan 2008) | 4 lines

  Add prototypes to get the mathmodule.c to compile on OSF1 5.1 (Tru64)
  and eliminate a compiler warning in floatobject.c.  There might be
  a better way to go about this, but it should be good enough for now.
........
2008-01-25 11:23:10 +00:00

466 lines
12 KiB
C

/* Math module -- standard C math library functions, pi and e */
#include "Python.h"
#include "longintrepr.h" /* just for SHIFT */
#ifndef _MSC_VER
#ifndef __STDC__
extern double fmod (double, double);
extern double frexp (double, int *);
extern double ldexp (double, int);
extern double modf (double, double *);
#endif /* __STDC__ */
#endif /* _MSC_VER */
#ifdef _OSF_SOURCE
/* OSF1 5.1 doesn't make this available with XOPEN_SOURCE_EXTENDED defined */
extern double copysign(double, double);
#endif
/* Call is_error when errno != 0, and where x is the result libm
* returned. is_error will usually set up an exception and return
* true (1), but may return false (0) without setting up an exception.
*/
static int
is_error(double x)
{
int result = 1; /* presumption of guilt */
assert(errno); /* non-zero errno is a precondition for calling */
if (errno == EDOM)
PyErr_SetString(PyExc_ValueError, "math domain error");
else if (errno == ERANGE) {
/* ANSI C generally requires libm functions to set ERANGE
* on overflow, but also generally *allows* them to set
* ERANGE on underflow too. There's no consistency about
* the latter across platforms.
* Alas, C99 never requires that errno be set.
* Here we suppress the underflow errors (libm functions
* should return a zero on underflow, and +- HUGE_VAL on
* overflow, so testing the result for zero suffices to
* distinguish the cases).
*/
if (x)
PyErr_SetString(PyExc_OverflowError,
"math range error");
else
result = 0;
}
else
/* Unexpected math error */
PyErr_SetFromErrno(PyExc_ValueError);
return result;
}
static PyObject *
math_1_to_whatever(PyObject *arg, double (*func) (double),
PyObject *(*from_double_func) (double))
{
double x = PyFloat_AsDouble(arg);
if (x == -1.0 && PyErr_Occurred())
return NULL;
errno = 0;
PyFPE_START_PROTECT("in math_1", return 0)
x = (*func)(x);
PyFPE_END_PROTECT(x)
Py_SET_ERRNO_ON_MATH_ERROR(x);
if (errno && is_error(x))
return NULL;
else
return (*from_double_func)(x);
}
static PyObject *
math_1(PyObject *arg, double (*func) (double))
{
return math_1_to_whatever(arg, func, PyFloat_FromDouble);
}
static PyObject *
math_1_to_int(PyObject *arg, double (*func) (double))
{
return math_1_to_whatever(arg, func, PyLong_FromDouble);
}
static PyObject *
math_2(PyObject *args, double (*func) (double, double), char *funcname)
{
PyObject *ox, *oy;
double x, y;
if (! PyArg_UnpackTuple(args, funcname, 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;
errno = 0;
PyFPE_START_PROTECT("in math_2", return 0)
x = (*func)(x, y);
PyFPE_END_PROTECT(x)
Py_SET_ERRNO_ON_MATH_ERROR(x);
if (errno && is_error(x))
return NULL;
else
return PyFloat_FromDouble(x);
}
#define FUNC1(funcname, func, docstring) \
static PyObject * math_##funcname(PyObject *self, PyObject *args) { \
return math_1(args, func); \
}\
PyDoc_STRVAR(math_##funcname##_doc, docstring);
#define FUNC2(funcname, func, docstring) \
static PyObject * math_##funcname(PyObject *self, PyObject *args) { \
return math_2(args, func, #funcname); \
}\
PyDoc_STRVAR(math_##funcname##_doc, docstring);
FUNC1(acos, acos,
"acos(x)\n\nReturn the arc cosine (measured in radians) of x.")
FUNC1(asin, asin,
"asin(x)\n\nReturn the arc sine (measured in radians) of x.")
FUNC1(atan, atan,
"atan(x)\n\nReturn the arc tangent (measured in radians) of x.")
FUNC2(atan2, atan2,
"atan2(y, x)\n\nReturn the arc tangent (measured in radians) of y/x.\n"
"Unlike atan(y/x), the signs of both x and y are considered.")
static PyObject * math_ceil(PyObject *self, PyObject *number) {
static PyObject *ceil_str = NULL;
PyObject *method;
if (ceil_str == NULL) {
ceil_str = PyUnicode_FromString("__ceil__");
if (ceil_str == NULL)
return NULL;
}
method = _PyType_Lookup(Py_TYPE(number), ceil_str);
if (method == NULL)
return math_1_to_int(number, ceil);
else
return PyObject_CallFunction(method, "O", number);
}
PyDoc_STRVAR(math_ceil_doc,
"ceil(x)\n\nReturn the ceiling of x as an int.\n"
"This is the smallest integral value >= x.");
FUNC1(cos, cos,
"cos(x)\n\nReturn the cosine of x (measured in radians).")
FUNC1(cosh, cosh,
"cosh(x)\n\nReturn the hyperbolic cosine of x.")
#ifdef MS_WINDOWS
# define copysign _copysign
# define HAVE_COPYSIGN 1
#endif
#ifdef HAVE_COPYSIGN
FUNC2(copysign, copysign,
"copysign(x,y)\n\nReturn x with the sign of y.");
#endif
FUNC1(exp, exp,
"exp(x)\n\nReturn e raised to the power of x.")
FUNC1(fabs, fabs,
"fabs(x)\n\nReturn the absolute value of the float x.")
static PyObject * math_floor(PyObject *self, PyObject *number) {
static PyObject *floor_str = NULL;
PyObject *method;
if (floor_str == NULL) {
floor_str = PyUnicode_FromString("__floor__");
if (floor_str == NULL)
return NULL;
}
method = _PyType_Lookup(Py_TYPE(number), floor_str);
if (method == NULL)
return math_1_to_int(number, floor);
else
return PyObject_CallFunction(method, "O", number);
}
PyDoc_STRVAR(math_floor_doc,
"floor(x)\n\nReturn the floor of x as an int.\n"
"This is the largest integral value <= x.");
FUNC2(fmod, fmod,
"fmod(x,y)\n\nReturn fmod(x, y), according to platform C."
" x % y may differ.")
FUNC2(hypot, hypot,
"hypot(x,y)\n\nReturn the Euclidean distance, sqrt(x*x + y*y).")
FUNC2(pow, pow,
"pow(x,y)\n\nReturn x**y (x to the power of y).")
FUNC1(sin, sin,
"sin(x)\n\nReturn the sine of x (measured in radians).")
FUNC1(sinh, sinh,
"sinh(x)\n\nReturn the hyperbolic sine of x.")
FUNC1(sqrt, sqrt,
"sqrt(x)\n\nReturn the square root of x.")
FUNC1(tan, tan,
"tan(x)\n\nReturn the tangent of x (measured in radians).")
FUNC1(tanh, tanh,
"tanh(x)\n\nReturn the hyperbolic tangent of x.")
static PyObject *
math_frexp(PyObject *self, PyObject *arg)
{
int i;
double x = PyFloat_AsDouble(arg);
if (x == -1.0 && PyErr_Occurred())
return NULL;
errno = 0;
x = frexp(x, &i);
Py_SET_ERRNO_ON_MATH_ERROR(x);
if (errno && is_error(x))
return NULL;
else
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.");
static PyObject *
math_ldexp(PyObject *self, PyObject *args)
{
double x;
int exp;
if (! PyArg_ParseTuple(args, "di:ldexp", &x, &exp))
return NULL;
errno = 0;
PyFPE_START_PROTECT("ldexp", return 0)
x = ldexp(x, exp);
PyFPE_END_PROTECT(x)
Py_SET_ERRNO_ON_MATH_ERROR(x);
if (errno && is_error(x))
return NULL;
else
return PyFloat_FromDouble(x);
}
PyDoc_STRVAR(math_ldexp_doc,
"ldexp(x, i) -> x * (2**i)");
static PyObject *
math_modf(PyObject *self, PyObject *arg)
{
double y, x = PyFloat_AsDouble(arg);
if (x == -1.0 && PyErr_Occurred())
return NULL;
errno = 0;
x = modf(x, &y);
Py_SET_ERRNO_ON_MATH_ERROR(x);
if (errno && is_error(x))
return NULL;
else
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. The integer part is returned as a real.");
/* A decent logarithm is easy to compute even for huge longs, but libm can't
do that by itself -- loghelper can. func is log or log10, and name is
"log" or "log10". Note that overflow isn't possible: a long can contain
no more than INT_MAX * SHIFT bits, so has value certainly less than
2**(2**64 * 2**16) == 2**2**80, and log2 of that is 2**80, which is
small enough to fit in an IEEE single. log and log10 are even smaller.
*/
static PyObject*
loghelper(PyObject* arg, double (*func)(double), char *funcname)
{
/* If it is long, do it ourselves. */
if (PyLong_Check(arg)) {
double x;
int e;
x = _PyLong_AsScaledDouble(arg, &e);
if (x <= 0.0) {
PyErr_SetString(PyExc_ValueError,
"math domain error");
return NULL;
}
/* Value is ~= x * 2**(e*SHIFT), so the log ~=
log(x) + log(2) * e * SHIFT.
CAUTION: e*SHIFT may overflow using int arithmetic,
so force use of double. */
x = func(x) + (e * (double)PyLong_SHIFT) * func(2.0);
return PyFloat_FromDouble(x);
}
/* Else let libm handle it by itself. */
return math_1(arg, func);
}
static PyObject *
math_log(PyObject *self, PyObject *args)
{
PyObject *arg;
PyObject *base = NULL;
PyObject *num, *den;
PyObject *ans;
if (!PyArg_UnpackTuple(args, "log", 1, 2, &arg, &base))
return NULL;
num = loghelper(arg, log, "log");
if (num == NULL || base == NULL)
return num;
den = loghelper(base, log, "log");
if (den == NULL) {
Py_DECREF(num);
return NULL;
}
ans = PyNumber_TrueDivide(num, den);
Py_DECREF(num);
Py_DECREF(den);
return ans;
}
PyDoc_STRVAR(math_log_doc,
"log(x[, base]) -> the logarithm of x to the given base.\n\
If the base not specified, returns the natural logarithm (base e) of x.");
static PyObject *
math_log10(PyObject *self, PyObject *arg)
{
return loghelper(arg, log10, "log10");
}
PyDoc_STRVAR(math_log10_doc,
"log10(x) -> the base 10 logarithm of x.");
static const double degToRad = Py_MATH_PI / 180.0;
static const double radToDeg = 180.0 / Py_MATH_PI;
static PyObject *
math_degrees(PyObject *self, PyObject *arg)
{
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) -> converts angle x from radians to degrees");
static PyObject *
math_radians(PyObject *self, PyObject *arg)
{
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) -> converts angle x from degrees to radians");
static PyObject *
math_isnan(PyObject *self, PyObject *arg)
{
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\
Checks if float x is not a number (NaN)");
static PyObject *
math_isinf(PyObject *self, PyObject *arg)
{
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\
Checks if float x is infinite (positive or negative)");
static PyMethodDef math_methods[] = {
{"acos", math_acos, METH_O, math_acos_doc},
{"asin", math_asin, METH_O, math_asin_doc},
{"atan", math_atan, METH_O, math_atan_doc},
{"atan2", math_atan2, METH_VARARGS, math_atan2_doc},
{"ceil", math_ceil, METH_O, math_ceil_doc},
#ifdef HAVE_COPYSIGN
{"copysign", math_copysign, METH_VARARGS, math_copysign_doc},
#endif
{"cos", math_cos, METH_O, math_cos_doc},
{"cosh", math_cosh, METH_O, math_cosh_doc},
{"degrees", math_degrees, METH_O, math_degrees_doc},
{"exp", math_exp, METH_O, math_exp_doc},
{"fabs", math_fabs, METH_O, math_fabs_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},
{"hypot", math_hypot, METH_VARARGS, math_hypot_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},
{"log", math_log, METH_VARARGS, math_log_doc},
{"log10", math_log10, METH_O, math_log10_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},
{"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},
{NULL, NULL} /* sentinel */
};
PyDoc_STRVAR(module_doc,
"This module is always available. It provides access to the\n"
"mathematical functions defined by the C standard.");
PyMODINIT_FUNC
initmath(void)
{
PyObject *m, *d, *v;
m = Py_InitModule3("math", math_methods, module_doc);
if (m == NULL)
goto finally;
d = PyModule_GetDict(m);
if (d == NULL)
goto finally;
if (!(v = PyFloat_FromDouble(Py_MATH_PI)))
goto finally;
if (PyDict_SetItemString(d, "pi", v) < 0)
goto finally;
Py_DECREF(v);
if (!(v = PyFloat_FromDouble(Py_MATH_E)))
goto finally;
if (PyDict_SetItemString(d, "e", v) < 0)
goto finally;
Py_DECREF(v);
finally:
return;
}