diff --git a/Doc/c-api/concrete.rst b/Doc/c-api/concrete.rst index a02332abfc8..aad031b4cb2 100644 --- a/Doc/c-api/concrete.rst +++ b/Doc/c-api/concrete.rst @@ -557,6 +557,23 @@ Floating Point Objects without error checking. +.. cfunction:: PyObject* PyFloat_GetInfo(void) + + Return a :ctype:`PyDictObject` object which contains information about the + precision, minimum and maximum values of a float. It's a thin wrapper + around the header file :file:`float.h`. + + +.. cfunction:: double PyFloat_GetMax(void) + + Return the maximum representable finite float *DBL_MAX* as C :ctype:`double`. + + +.. cfunction:: double PyFloat_GetMin(void) + + Return the minimum normalized positive float *DBL_MIN* as C :ctype:`double`. + + .. _complexobjects: Complex Number Objects diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index f2540032369..d33f5320845 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -240,6 +240,48 @@ always available. Use :mod:`atexit` instead. +.. data:: float_info + + A dict holding information about the float type. It contains low level + information about the precision and internal representation. Please study + your system's :file:`float.h` for more information. + + +---------------------+--------------------------------------------------+ + | key | explanation | + +=====================+==================================================+ + | :const:`epsilon` | Difference between 1 and the next representable | + | | floating point number | + +---------------------+--------------------------------------------------+ + | :const:`dig` | digits (see :file:`float.h`) | + +---------------------+--------------------------------------------------+ + | :const:`mant_dig` | mantissa digits (see :file:`float.h`) | + +---------------------+--------------------------------------------------+ + | :const:`max` | maximum representable finite float | + +---------------------+--------------------------------------------------+ + | :const:`max_exp` | maximum int e such that radix**(e-1) is in the | + | | range of finite representable floats | + +---------------------+--------------------------------------------------+ + | :const:`max_10_exp` | maximum int e such that 10**e is in the | + | | range of finite representable floats | + +---------------------+--------------------------------------------------+ + | :const:`min` | Minimum positive normalizer float | + +---------------------+--------------------------------------------------+ + | :const:`min_exp` | minimum int e such that radix**(e-1) is a | + | | normalized float | + +---------------------+--------------------------------------------------+ + | :const:`min_10_exp` | minimum int e such that 10**e is a normalized | + | | float | + +---------------------+--------------------------------------------------+ + | :const:`radix` | radix of exponent | + +---------------------+--------------------------------------------------+ + | :const:`rounds` | addition rounds (see :file:`float.h`) | + +---------------------+--------------------------------------------------+ + + .. note:: + + The information in the table is simplified. + + .. function:: getcheckinterval() Return the interpreter's "check interval"; see :func:`setcheckinterval`. diff --git a/Include/floatobject.h b/Include/floatobject.h index bfbc580126f..be1a80c04e6 100644 --- a/Include/floatobject.h +++ b/Include/floatobject.h @@ -21,6 +21,10 @@ PyAPI_DATA(PyTypeObject) PyFloat_Type; #define PyFloat_Check(op) PyObject_TypeCheck(op, &PyFloat_Type) #define PyFloat_CheckExact(op) (Py_Type(op) == &PyFloat_Type) +PyAPI_FUNC(double) PyFloat_GetMax(void); +PyAPI_FUNC(double) PyFloat_GetMin(void); +PyAPI_FUNC(PyObject *) PyFloat_GetInfo(void); + /* Return Python float from string PyObject. Second argument ignored on input, and, if non-NULL, NULL is stored into *junk (this tried to serve a purpose once but can't be made to work as intended). */ diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index f1f1524c06d..d02412fd74e 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -329,6 +329,8 @@ class SysModuleTest(unittest.TestCase): self.assert_(isinstance(sys.copyright, basestring)) self.assert_(isinstance(sys.exec_prefix, basestring)) self.assert_(isinstance(sys.executable, basestring)) + self.assert_(isinstance(sys.float_info, dict)) + self.assertEqual(len(sys.float_info), 11) self.assert_(isinstance(sys.hexversion, int)) self.assert_(isinstance(sys.maxint, int)) if test.test_support.have_unicode: diff --git a/Misc/NEWS b/Misc/NEWS index 4fa85c68362..2023143f523 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ What's New in Python 2.6 alpha 1? Core and builtins ----------------- +- Issue #1534: Added ``PyFloat_GetMax()``, ``PyFloat_GetMin()`` and + ``PyFloat_GetInfo()`` to the float API. + - Issue #1521: On 64bit platforms, using PyArgs_ParseTuple with the t# of w# format code incorrectly truncated the length to an int, even when PY_SSIZE_T_CLEAN is set. The str.decode method used to return incorrect @@ -301,6 +304,9 @@ Core and builtins Library ------- +- Issue #1534: Added a dictionary sys.float_info with information about the + internal floating point type to the sys module. + - Issue 1429818: patch for trace and doctest modules so they play nicely together. diff --git a/Objects/floatobject.c b/Objects/floatobject.c index bf9b1728621..c76956a6698 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -7,6 +7,7 @@ #include "Python.h" #include +#include #if !defined(__STDC__) extern double fmod(double, double); @@ -46,6 +47,52 @@ fill_free_list(void) return p + N_FLOATOBJECTS - 1; } +double +PyFloat_GetMax(void) +{ + return DBL_MAX; +} + +double +PyFloat_GetMin(void) +{ + return DBL_MIN; +} + +PyObject * +PyFloat_GetInfo(void) +{ + PyObject *d, *tmp; + +#define SET_FLOAT_CONST(d, key, const) \ + tmp = PyFloat_FromDouble(const); \ + if (tmp == NULL) return NULL; \ + if (PyDict_SetItemString(d, key, tmp)) return NULL; \ + Py_DECREF(tmp) +#define SET_INT_CONST(d, key, const) \ + tmp = PyInt_FromLong(const); \ + if (tmp == NULL) return NULL; \ + if (PyDict_SetItemString(d, key, tmp)) return NULL; \ + Py_DECREF(tmp) + + d = PyDict_New(); + + SET_FLOAT_CONST(d, "max", DBL_MAX); + SET_INT_CONST(d, "max_exp", DBL_MAX_EXP); + SET_INT_CONST(d, "max_10_exp", DBL_MAX_10_EXP); + SET_FLOAT_CONST(d, "min", DBL_MIN); + SET_INT_CONST(d, "min_exp", DBL_MIN_EXP); + SET_INT_CONST(d, "min_10_exp", DBL_MIN_10_EXP); + SET_INT_CONST(d, "dig", DBL_DIG); + SET_INT_CONST(d, "mant_dig", DBL_MANT_DIG); + SET_FLOAT_CONST(d, "epsilon", DBL_EPSILON); + SET_INT_CONST(d, "radix", FLT_RADIX); + SET_INT_CONST(d, "rounds", FLT_ROUNDS); + + return d; +} + + PyObject * PyFloat_FromDouble(double fval) { diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 617c38a2d75..2a6a8c3e57a 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1169,6 +1169,8 @@ _PySys_Init(void) PyInt_FromLong(PyInt_GetMax())); SET_SYS_FROM_STRING("py3kwarning", PyBool_FromLong(Py_Py3kWarningFlag)); + SET_SYS_FROM_STRING("float_info", + PyFloat_GetInfo()); #ifdef Py_USING_UNICODE SET_SYS_FROM_STRING("maxunicode", PyInt_FromLong(PyUnicode_GetMax()));