Index: Lib/test/test_math.py =================================================================== --- Lib/test/test_math.py (revision 59558) +++ Lib/test/test_math.py (working copy) @@ -203,6 +203,31 @@ self.ftest('tanh(0)', math.tanh(0), 0) self.ftest('tanh(1)+tanh(-1)', math.tanh(1)+math.tanh(-1), 0) + def testSign(self): + self.assertEqual(math.sign(0), 0) + self.assertEqual(math.sign(-2), -1) + self.assertEqual(math.sign(+2), 1) + self.assertEqual(math.sign(0.), 1) + self.assertEqual(math.sign(-0.), -1) + self.assertEqual(math.sign(-2.), -1) + self.assertEqual(math.sign(+2.), 1) + + def testIsnan(self): + self.assert_(math.isnan(float("nan"))) + self.assert_(math.isnan(float("inf")* 0.)) + self.failIf(math.isnan(float("inf"))) + self.failIf(math.isnan(0.)) + self.failIf(math.isnan(1.)) + + def testIsinf(self): + self.assert_(math.isinf(float("inf"))) + self.assert_(math.isinf(float("-inf"))) + self.assert_(math.isinf(1E400)) + self.assert_(math.isinf(-1E400)) + self.failIf(math.isinf(float("nan"))) + self.failIf(math.isinf(0.)) + self.failIf(math.isinf(1.)) + # RED_FLAG 16-Oct-2000 Tim # While 2.0 is more consistent about exceptions than previous releases, it # still fails this part of the test on some platforms. For now, we only @@ -247,3 +272,4 @@ if __name__ == '__main__': test_main() + Index: Modules/mathmodule.c =================================================================== --- Modules/mathmodule.c (revision 59558) +++ Modules/mathmodule.c (working copy) @@ -277,9 +277,8 @@ PyDoc_STRVAR(math_log10_doc, "log10(x) -> the base 10 logarithm of x."); -/* XXX(nnorwitz): Should we use the platform M_PI or something more accurate - like: 3.14159265358979323846264338327950288 */ -static const double degToRad = 3.141592653589793238462643383 / 180.0; +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) @@ -287,7 +286,7 @@ double x = PyFloat_AsDouble(arg); if (x == -1.0 && PyErr_Occurred()) return NULL; - return PyFloat_FromDouble(x / degToRad); + return PyFloat_FromDouble(x * radToDeg); } PyDoc_STRVAR(math_degrees_doc, @@ -305,6 +304,76 @@ 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 PyObject * +math_sign(PyObject *self, PyObject *arg) +{ + int result = -2; + if (PyInt_Check(arg)) { + long l = PyInt_AsLong(arg); + if (l == -1.0 && PyErr_Occurred()) + return NULL; + result = l > 0 ? 1 : + l < 0 ? -1 : 0; + + } + if (PyLong_Check(arg)) { + result = _PyLong_Sign(arg); + } + else if (PyFloat_Check(arg)) { + double x = PyFloat_AsDouble(arg); + if (x == -1.0 && PyErr_Occurred()) + return NULL; +#ifdef HAVE_COPYSIGN + result = (int)copysign(1., x); +#elif defined(MS_WINDOWS) + result = (int)_copysign(1.0, x); +#else + result = x > 0.0 ? 1 : + x < 0.0 ? -1 : 0; +#endif + } + if (result == -2) { + PyErr_Format(PyExc_TypeError, + "sign() expected int, long or float, found %s", + Py_Type(arg)->tp_name); + return NULL; + } + return PyInt_FromLong((long)result); +} + +PyDoc_STRVAR(math_sign_doc, +"sign(x) -> +1 / 0 / -1\n\ +Return the sign of an int, long or float. On platforms with full IEEE 754\n\ +semantic sign(0.) returns +1 and sign(-0.) returns -1. On other platforms\n\ +sign(0.) always returns 0."); + + static PyMethodDef math_methods[] = { {"acos", math_acos, METH_O, math_acos_doc}, {"asin", math_asin, METH_O, math_asin_doc}, @@ -320,12 +389,15 @@ {"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}, + {"sign", math_sign, METH_O, math_sign_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}, @@ -351,13 +423,13 @@ if (d == NULL) goto finally; - if (!(v = PyFloat_FromDouble(atan(1.0) * 4.0))) + 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(exp(1.0)))) + if (!(v = PyFloat_FromDouble(Py_MATH_E))) goto finally; if (PyDict_SetItemString(d, "e", v) < 0) goto finally;