[Python-checkins] r60724 - in python/branches/trunk-math: Include/floatobject.h Include/pystate.h Lib/contextlib.py Lib/test/test_contextlib.py Modules/mathmodule.c Objects/floatobject.c Python/pystate.c

christian.heimes python-checkins at python.org
Mon Feb 11 04:59:29 CET 2008


Author: christian.heimes
Date: Mon Feb 11 04:59:29 2008
New Revision: 60724

Modified:
   python/branches/trunk-math/Include/floatobject.h
   python/branches/trunk-math/Include/pystate.h
   python/branches/trunk-math/Lib/contextlib.py
   python/branches/trunk-math/Lib/test/test_contextlib.py
   python/branches/trunk-math/Modules/mathmodule.c
   python/branches/trunk-math/Objects/floatobject.c
   python/branches/trunk-math/Python/pystate.c
Log:
Added IEEE 754 context for f/0. as discussed on the Python general list. Inside the context f/0. returns NAN for f=0. and (negative) infinity for the (negative) rest.

Modified: python/branches/trunk-math/Include/floatobject.h
==============================================================================
--- python/branches/trunk-math/Include/floatobject.h	(original)
+++ python/branches/trunk-math/Include/floatobject.h	Mon Feb 11 04:59:29 2008
@@ -51,6 +51,9 @@
    preserve precision across conversions. */
 PyAPI_FUNC(void) PyFloat_AsString(char*, PyFloatObject *v);
 
+PyAPI_FUNC(int) PyFloat_GetIEEE754(void);
+PyAPI_FUNC(int) PyFloat_SetIEEE754(int);
+
 /* _PyFloat_{Pack,Unpack}{4,8}
  *
  * The struct and pickle (at least) modules need an efficient platform-

Modified: python/branches/trunk-math/Include/pystate.h
==============================================================================
--- python/branches/trunk-math/Include/pystate.h	(original)
+++ python/branches/trunk-math/Include/pystate.h	Mon Feb 11 04:59:29 2008
@@ -95,6 +95,8 @@
     PyObject *async_exc; /* Asynchronous exception to raise */
     long thread_id; /* Thread id where this tstate was created */
 
+    int float_ieee754; /* PyFloat behavior */
+
     /* XXX signal handlers should also be here */
 
 } PyThreadState;

Modified: python/branches/trunk-math/Lib/contextlib.py
==============================================================================
--- python/branches/trunk-math/Lib/contextlib.py	(original)
+++ python/branches/trunk-math/Lib/contextlib.py	Mon Feb 11 04:59:29 2008
@@ -1,8 +1,9 @@
 """Utilities for with-statement contexts.  See PEP 343."""
 
 import sys
+import math as _math
 
-__all__ = ["contextmanager", "nested", "closing"]
+__all__ = ["contextmanager", "nested", "closing", "ieee754"]
 
 class GeneratorContextManager(object):
     """Helper for @contextmanager decorator."""
@@ -155,3 +156,24 @@
         return self.thing
     def __exit__(self, *exc_info):
         self.thing.close()
+
+class ieee754(object):
+    """Context for IEEE 754 floating point behavior
+
+    Example:
+    >>> with ieee754():
+    ...     r1 = 42./0.
+    ...     r2 = -23./0.
+    ...     r2 = 0./0.
+    ...
+    >>> print r1, r2, r3
+    (inf, -inf, nan)
+    """
+    def __init__(self, state=True):
+        self.new_state = state
+
+    def __enter__(self):
+        self.old_state = _math.set_ieee754(self.new_state)
+
+    def __exit__(self, *args):
+        _math.set_ieee754(self.old_state)

Modified: python/branches/trunk-math/Lib/test/test_contextlib.py
==============================================================================
--- python/branches/trunk-math/Lib/test/test_contextlib.py	(original)
+++ python/branches/trunk-math/Lib/test/test_contextlib.py	Mon Feb 11 04:59:29 2008
@@ -10,6 +10,7 @@
 import threading
 from contextlib import *  # Tests __all__
 from test import test_support
+import math
 
 class ContextManagerTestCase(unittest.TestCase):
 
@@ -330,6 +331,25 @@
                 return True
         self.boilerPlate(lock, locked)
 
+class IEEE754TestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.state = math.get_ieee754()
+
+    def tearDown(self):
+        math.set_ieee754(self.state)
+
+    def test_ieee754(self):
+        with ieee754():
+            r1 = 42./0.
+            r2 = -23./0.
+            r3 = 0./0.
+        self.assert_(math.isinf(r1))
+        self.assert_(r1 > 0)
+        self.assert_(math.isinf(r2))
+        self.assert_(r2 < 0)
+        self.assert_(math.isnan(r3))
+
 # This is needed to make the test actually run under regrtest.py!
 def test_main():
     test_support.run_unittest(__name__)

Modified: python/branches/trunk-math/Modules/mathmodule.c
==============================================================================
--- python/branches/trunk-math/Modules/mathmodule.c	(original)
+++ python/branches/trunk-math/Modules/mathmodule.c	Mon Feb 11 04:59:29 2008
@@ -599,6 +599,29 @@
 "isinf(x) -> bool\n\
 Checks if float x is infinite (positive or negative)");
 
+static PyObject *
+math_set_ieee754(PyObject *self, PyObject *arg)
+{
+	int state;
+
+	state = PyObject_IsTrue(arg);
+	if (state == -1)
+		return NULL;
+	
+	return PyBool_FromLong((long)PyFloat_SetIEEE754(state));
+}
+
+PyDoc_STRVAR(math_set_ieee754_doc,
+"set_ieee754(bool) -> bool");
+
+static PyObject *
+math_get_ieee754(PyObject *self, PyObject *arg)
+{
+	return PyBool_FromLong((long)PyFloat_GetIEEE754());
+}
+
+PyDoc_STRVAR(math_get_ieee754_doc,
+"get_ieee754() -> bool");
 
 static PyMethodDef math_methods[] = {
 	{"acos",	math_acos,	METH_O,		math_acos_doc},
@@ -618,6 +641,7 @@
 	{"floor",	math_floor,	METH_O,		math_floor_doc},
 	{"fmod",	math_fmod,	METH_VARARGS,	math_fmod_doc},
 	{"frexp",	math_frexp,	METH_O,		math_frexp_doc},
+	{"get_ieee754",	math_get_ieee754,	METH_NOARGS,	math_get_ieee754_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},
@@ -628,6 +652,7 @@
 	{"modf",	math_modf,	METH_O,		math_modf_doc},
 	{"pow",		math_pow,	METH_VARARGS,	math_pow_doc},
 	{"radians",	math_radians,	METH_O,		math_radians_doc},
+	{"set_ieee754",	math_set_ieee754,	METH_O,	math_set_ieee754_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},

Modified: python/branches/trunk-math/Objects/floatobject.c
==============================================================================
--- python/branches/trunk-math/Objects/floatobject.c	(original)
+++ python/branches/trunk-math/Objects/floatobject.c	Mon Feb 11 04:59:29 2008
@@ -882,8 +882,11 @@
 	CONVERT_TO_DOUBLE(v, a);
 	CONVERT_TO_DOUBLE(w, b);
 	if (b == 0.0) {
-		PyErr_SetString(PyExc_ZeroDivisionError, "float division");
-		return NULL;
+		if (PyFloat_GetIEEE754() == 0) {
+			PyErr_SetString(PyExc_ZeroDivisionError,
+					"float division");
+			return NULL;
+		}
 	}
 	PyFPE_START_PROTECT("divide", return 0)
 	a = a / b;
@@ -901,10 +904,12 @@
 	    PyErr_Warn(PyExc_DeprecationWarning, "classic float division") < 0)
 		return NULL;
 	if (b == 0.0) {
-		PyErr_SetString(PyExc_ZeroDivisionError, "float division");
-		return NULL;
-	}
-	PyFPE_START_PROTECT("divide", return 0)
+		if (PyFloat_GetIEEE754() == 0) {
+			PyErr_SetString(PyExc_ZeroDivisionError,
+					"float division");
+			return NULL;
+		}
+	}	PyFPE_START_PROTECT("divide", return 0)
 	a = a / b;
 	PyFPE_END_PROTECT(a)
 	return PyFloat_FromDouble(a);
@@ -1746,6 +1751,25 @@
 	}
 }
 
+/* inline this */
+int
+PyFloat_GetIEEE754(void)
+{
+	PyThreadState *tstate = PyThreadState_GET();
+	return tstate->float_ieee754;
+}
+
+int
+PyFloat_SetIEEE754(state)
+{
+	int old_state;
+	PyThreadState *tstate = PyThreadState_GET();
+
+	old_state = tstate->float_ieee754;
+	tstate->float_ieee754 = state;
+	return old_state;
+}
+
 /*----------------------------------------------------------------------------
  * _PyFloat_{Pack,Unpack}{4,8}.  See floatobject.h.
  *

Modified: python/branches/trunk-math/Python/pystate.c
==============================================================================
--- python/branches/trunk-math/Python/pystate.c	(original)
+++ python/branches/trunk-math/Python/pystate.c	Mon Feb 11 04:59:29 2008
@@ -193,6 +193,8 @@
 		tstate->c_profileobj = NULL;
 		tstate->c_traceobj = NULL;
 
+		tstate->float_ieee754 = 0;
+
 #ifdef WITH_THREAD
 		_PyGILState_NoteThreadState(tstate);
 #endif


More information about the Python-checkins mailing list