msg31479 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2007-03-11 17:16 |
The identification of -0.0 and 0.0 in scripts leads to some surprising results. In particular, code that behaves one way in the interpreter can behave differently in a script. For example: Python 2.6a0 (trunk:54183M, Mar 6 2007, 20:16:00) [GCC 4.0.1 (Apple Computer, Inc. build 5367)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> from math import atan2; >>> x = -0. >>> y = 0. >>> print atan2(y, -1.) 3.14159265359 But: >>> exec("from math import atan2; x = -0.; y = 0.; print atan2(y, -1.)") -3.14159265359 A simpler example: >>> x, y = -0., 0. >>> x, y (-0.0, -0.0) >>> id(x) == id(y) True But: >>> x = -0. >>> y = 0. >>> x, y (-0.0, 0.0) This occurs both on SuSE Linux 9.3/i686 and on OS X 10.4.8/PowerPC. |
|
|
msg31480 - (view) |
Author: Martin v. Löwis (loewis) *  |
Date: 2007-03-11 18:35 |
This is not a bug, at least not one that will be fixed. Details of the floating-point can vary across platforms, and they may behave in suprising ways in various contexts. Users shouldn't rely on Python differentiating between -0 and +0. |
|
|
msg31481 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2007-03-11 19:21 |
May I beg for reconsideration. Is the following really considered acceptable? >>> x = -0.; atan2(0., -1) -3.1415926535897931 >>> x = -(0.); atan2(0., -1) 3.1415926535897931 >>> atan2(0., -1) 3.1415926535897931 A single x = -0. at the start of a script can have side effects several hundred lines later, even when the variable x is never referred to again. I guess the advice should be: "To avoid surprises, -0. should never appear in any script." |
|
|
msg31482 - (view) |
Author: Gabriel Genellina (ggenellina) |
Date: 2007-03-11 20:10 |
It appears to be a problem in the way compile.c handles literals. See http://mail.python.org/pipermail/python-list/2007-March/430302.html |
|
|
msg31483 - (view) |
Author: Martin v. Löwis (loewis) *  |
Date: 2007-03-11 22:27 |
marketdickinson, you should ask this question (is this really acceptable) on python-dev. I find it perfectly acceptable. No program should rely on -0 and +0 being two different things (and thus also not relying on atan2 giving two different results). |
|
|
msg31484 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2007-03-12 01:15 |
I expressed myself badly. I apologise. This really isn't about +0. and -0. being different, or not. I'm perfectly comfortable with the idea that +0. and -0. may or may not be distinguishable on any given platform. The surprise is the other way around: two *identical* calls to atan(0., -1.) (or to repr(0.) for that matter) give *different* results, depending solely on whether a -0. literal has appeared earlier on in the code unit being compiled. So if the first float zero literal encountered in a source file just happens to be a -0. rather than a 0., the meaning of str(0.) later on suddenly becomes "-0.0" rather than "0.0". I'd like to be able to rely on str(0.) meaning "0.0" without having to worry about whether there might be a -0. literal appearing in some faraway and otherwise completely irrelevant portion of the file. |
|
|
msg31485 - (view) |
Author: Alex Martelli (aleax) *  |
Date: 2007-03-12 01:51 |
Also see my patch 1678380 which fixes this bug (and checks for it in a new unittest). |
|
|
msg31486 - (view) |
Author: Alex Martelli (aleax) *  |
Date: 2007-03-12 01:54 |
Oops,sorry, I meant patch 1678668 (copy-and-pasted the wrong ID:-). Alex |
|
|
msg31487 - (view) |
Author: Martin v. Löwis (loewis) *  |
Date: 2007-03-12 09:04 |
I also expressed myself badly. I not only meant that programs should not rely on +0 and -0 being different things across platforms, but that they should also not rely on them being either always different or always the same in a single program. If Python would randomly chose to interpret +0 as -0, or would do so for every third occurence, I still couldn't see a problem. |
|
|
msg31488 - (view) |
Author: Alex Martelli (aleax) *  |
Date: 2007-03-12 14:57 |
and yet, peephole.c does specialcase -0 (with a comment and all!-) avoiding constant-folding optimization for it -- making things work fine in Python 2.4.x for high enough x -- it's just that peephole.c's efforts are defeated by a similar optimization applied without specialcase checking in ast.c in Python 2.5. This is inconsistent: it makes no sense to take SOME of the precautions needed to avoid an issue but not ALL of them, since this makes the issue appear anyway, so those precautions that ARE taken are there for no purpose (except a miniscule slowdown and enlargement of the interpreter:-). Either we save those few lines of code in peephole.c or add the few lines to ast.c that I suggest in my patch 1678668 -- the current situation makes no sense. |
|
|
msg31489 - (view) |
Author: Raymond Hettinger (rhettinger) *  |
Date: 2007-04-02 19:02 |
The distinction between +0.0 and -0.0 was important to Tim for get the branch cuts to work correctly. That was the reason for the special-casing in earlier versions in pre-ast versions of compile.c and in the peephole optimizer. Alex's patch looks correct. It should go into Py2.5.1. |
|
|
msg57339 - (view) |
Author: Christian Heimes (christian.heimes) *  |
Date: 2007-11-09 22:24 |
It's fixed in 2.6 but still broken in 2.5. |
|
|
msg61455 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2008-01-21 21:58 |
This was fixed in the trunk in revision 57284. I've backported the fix to Python 2.5.2 in revision 60183. Leaving this open because there's still a problem for complex numbers, though I guess this is less likely to bite people: Python 2.6a0 (trunk:60158M, Jan 21 2008, 16:21:41) [GCC 4.0.1 (Apple Computer, Inc. build 5370)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> 0j 0j >>> -0j -0j >>> [0j, -0j] [0j, 0j] |
|
|
msg61462 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2008-01-21 22:58 |
Here's a patch, against the trunk, that imitates Alex's fix for the complex case. |
|
|
msg61935 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2008-01-31 22:19 |
Bug identifying 0j and -0j fixed for Python 2.6 in revision 60483. Martin, can this be backported to 2.5.2? I'll assume not, unless I hear otherwise from you. |
|
|
msg62370 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2008-02-13 22:26 |
Closing. |
|
|
msg94418 - (view) |
Author: Mancausoft (mancausoft) |
Date: 2009-10-24 14:13 |
This bug is still present on arm. Python 2.6.3 cs-e9302# cat ../prova.py import math print math.atan2(0., -0.) print (math.copysign(4., -0.), -4.0) print math.atan2(0., -0.) print (math.copysign(4., -0.), -4.0) print math.atan2(0., -0.) cs-e9302# cat ../prova1.py import math print (math.copysign(4., -0.), -4.0) print math.atan2(0., -0.) print (math.copysign(4., -0.), -4.0) print math.atan2(0., -0.) cs-e9302# ./python ../prova1.py (-4.0, -4.0) -3.14159265359 (-4.0, -4.0) -3.14159265359 cs-e9302# ./python ../prova.py 0.0 (4.0, -4.0) 0.0 (4.0, -4.0) 0.0 >>> from math import atan2 >>> x = -0. >>> y = 0. >>> print atan2(y, -1.) 3.14159265359 >>> exec("from math import atan2; x = -0.; y = 0.; print atan2(y, -1.)") -3.14159265359 >>> x = -0.; atan2(0., -1) -3.1415926535897931 >>> x = 0.; atan2(0., -1) 3.1415926535897931 ====================================================================== FAIL: testAtan2 (__main__.MathTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "Lib/test/test_math.py", line 131, in testAtan2 self.ftest('atan2(0., -0.)', math.atan2(0., -0.), math.pi) File "Lib/test/test_math.py", line 57, in ftest (name, value, expected)) AssertionError: atan2(0., -0.) returned 0.0, expected 3.1415926535897931 ====================================================================== FAIL: testCopysign (__main__.MathTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "Lib/test/test_math.py", line 806, in testCopysign self.assertEqual(math.copysign(4., -0.), -4.0) AssertionError: 4.0 != -4.0 ---------------------------------------------------------------------- |
|
|
msg94419 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-10-24 14:19 |
Mancausoft: is this little-endian, OABI? If so, then I think I know what the problem is: the disambiguation code in compile.c looks at the first and last bytes of the double to distinguish 0.0 and -0.0; for mixed-endian (aka little-endian, swapped words) doubles this will fail. The solution is to use copysign instead. |
|
|
msg94422 - (view) |
Author: Mancausoft (mancausoft) |
Date: 2009-10-24 15:14 |
Mark Dickinson <report@bugs.python.org> scrisse: > Mancausoft: is this little-endian, OABI? Mixed endian > If so, then I think I know what the problem is: the disambiguation > code in compile.c looks at the first and last bytes of the double to > distinguish 0.0 and -0.0; for mixed-endian (aka little-endian, > swapped words) doubles this will fail. > > The solution is to use copysign instead. I try: *p==0 && p[sizeof(double)-1]==0 && p[(sizeof(double)-1)/2]==0; and now the test_math result is: Ran 39 tests in 21.323s OK It's a safe patch? Mancausoft |
|
|
msg94423 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-10-24 15:21 |
> I try: *p==0 && p[sizeof(double)-1]==0 && p[(sizeof(double)-1)/2]==0; Sure, that should work. It would seem cleaner and safer to use copysign, though: that way, things will still work when some other byte layout comes along, or when some version of Python starts using 128-bit IEEE 754 doubles instead of 64-bit, or ... Reopening: I've been meaning to fix these checks to use copysign for a while now, anyway. |
|
|
msg94424 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-10-24 15:29 |
Here's a patch for floats. Mancausoft, could you give this a try and let me know whether it fixes the issue? The same fix would also need to be applied for complex numbers. |
|
|
msg94426 - (view) |
Author: Mancausoft (mancausoft) |
Date: 2009-10-24 15:45 |
Mark Dickinson <report@bugs.python.org> scrisse: > > Mark Dickinson <dickinsm@gmail.com> added the comment: > > Here's a patch for floats. Mancausoft, could you give this a try and > let me know whether it fixes the issue? it works. test_math Ran 39 tests in 23.561s OK test_float Ran 19 tests in 275.241s OK Mancausoft |
|
|
msg94427 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-10-24 16:02 |
Thanks for testing! I'll apply the fix once the 2.6 branch is unfrozen. |
|
|
msg95794 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-11-28 16:40 |
Applied (along with a corresponding fix for the complex type) in revisions r76575 through r76578. |
|
|