r51525 - in python/trunk: Lib/test/test_float.py Objects/floatobject.c
Author: alex.martelli Date: Wed Aug 23 22:42:02 2006 New Revision: 51525 Modified: python/trunk/Lib/test/test_float.py python/trunk/Objects/floatobject.c Log: x**2 should about equal x*x (including for a float x such that the result is inf) but didn't; added a test to test_float to verify that, and ignored the ERANGE value for errno in the pow operation to make the new test pass (with help from Marilyn Davis at the Google Python Sprint -- thanks!). Modified: python/trunk/Lib/test/test_float.py ============================================================================== --- python/trunk/Lib/test/test_float.py (original) +++ python/trunk/Lib/test/test_float.py Wed Aug 23 22:42:02 2006 @@ -99,12 +99,25 @@ ('<f', LE_FLOAT_NAN)]: struct.unpack(fmt, data) +# on an IEEE platform, "overflowing" operations produce infinity + +class IEEEOperationsTestCase(unittest.TestCase): + if float.__getformat__("double").startswith("IEEE"): + def test_double_infinity(self): + big = 4.8e159 + pro = big*big + self.assertEquals(repr(pro), 'inf') + sqr = big**2 + self.assertEquals(repr(sqr), 'inf') + def test_main(): test_support.run_unittest( FormatFunctionsTestCase, UnknownFormatTestCase, - IEEEFormatTestCase) + IEEEFormatTestCase, + IEEEOperationsTestCase, + ) if __name__ == '__main__': test_main() Modified: python/trunk/Objects/floatobject.c ============================================================================== --- python/trunk/Objects/floatobject.c (original) +++ python/trunk/Objects/floatobject.c Wed Aug 23 22:42:02 2006 @@ -821,12 +821,12 @@ ix = pow(iv, iw); PyFPE_END_PROTECT(ix) Py_ADJUST_ERANGE1(ix); - if (errno != 0) { + /* we need to ignore ERANGE here and just return inf */ + if (errno != 0 && errno != ERANGE) { /* We don't expect any errno value other than ERANGE, but * the range of libm bugs appears unbounded. */ - PyErr_SetFromErrno(errno == ERANGE ? PyExc_OverflowError : - PyExc_ValueError); + PyErr_SetFromErrno(PyExc_ValueError); return NULL; } return PyFloat_FromDouble(ix);
Author: alex.martelli Date: Wed Aug 23 22:42:02 2006 New Revision: 51525
Modified: python/trunk/Lib/test/test_float.py python/trunk/Objects/floatobject.c Log: x**2 should about equal x*x (including for a float x such that the result is inf) but didn't; added a test to test_float to verify that, and ignored the ERANGE value for errno in the pow operation to make the new test pass (with help from Marilyn Davis at the Google Python Sprint -- thanks!).
Huh. It's been a (mildly controversial, but intentional all the same) feature that Python tries to raise raise OverflowError on overflowing libm operations. Doesn't work all that well, since there's no consistency across platforms about when libm sets errno, or to what (when it does).
Modified: python/trunk/Lib/test/test_float.py ============================================================================== --- python/trunk/Lib/test/test_float.py (original) +++ python/trunk/Lib/test/test_float.py Wed Aug 23 22:42:02 2006 @@ -99,12 +99,25 @@ ('<f', LE_FLOAT_NAN)]: struct.unpack(fmt, data)
+# on an IEEE platform, "overflowing" operations produce infinity + +class IEEEOperationsTestCase(unittest.TestCase): + if float.__getformat__("double").startswith("IEEE"): + def test_double_infinity(self): + big = 4.8e159 + pro = big*big + self.assertEquals(repr(pro), 'inf')
You must have run this on Linux? Can't pass on Windows (at least).
+ sqr = big**2 + self.assertEquals(repr(sqr), 'inf')
Same as above. C89 defines nothing about what the platform double->string routines produce for IEEE inf, NaN, or signed zeroes, and there's no consistency across platforms for that either. A better test is suggested by pyport.h's default implementation if its "is it an infinity?" macro: #define Py_IS_INFINITY(X) ((X) && (X)*0.5 == (X)) Since you expect a postive infinity here, specialize to: self.assert_(sqr > 0.0 and sqr * 0.5 == sqr)
On 8/23/06, alex.martelli <python-checkins@python.org> wrote:
--- python/trunk/Objects/floatobject.c (original) +++ python/trunk/Objects/floatobject.c Wed Aug 23 22:42:02 2006 @@ -821,12 +821,12 @@ ix = pow(iv, iw); PyFPE_END_PROTECT(ix) Py_ADJUST_ERANGE1(ix); - if (errno != 0) { + /* we need to ignore ERANGE here and just return inf */ + if (errno != 0 && errno != ERANGE) { /* We don't expect any errno value other than ERANGE, but * the range of libm bugs appears unbounded. */ - PyErr_SetFromErrno(errno == ERANGE ? PyExc_OverflowError : - PyExc_ValueError); + PyErr_SetFromErrno(PyExc_ValueError); return NULL;
I don't think this can be right. The returnvalue of pow() in the case of ERANGE isn't defined anywhere that I can find, at least. How can we assume it is +Infinity? As I tried to say over the visiphone, you can't even use compile-time or startup-time checks for the behaviour because 'undefined' also means it need not be consistent, either. The best we could do, if we really wanted to return +inf instead of raising OverflowError (which I don't, but don't really care about either), is generate +Infinity in some guaranteed way. I'm sure Tim can come up with a convenient, portable way < 0.9 wink>. But I'd prefer to keep it the way it was: x*x and x**2 don't always do the same thing. Floats have a lot more confusing features like that, such as 10*x - 9*x need not be x. I don't see the added value of trying to make it consistent in just this case, even if it's portable. -- Thomas Wouters <thomas@python.org> Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
participants (3)
-
alex.martelli
-
Thomas Wouters
-
Tim Peters