Mark Dickinson <[EMAIL PROTECTED]> wrote: > I get the following behaviour on Python 2.5 (OS X 10.4.8 on PowerPC, > in case it's relevant.) > > >>> x, y = 0.0, -0.0 > >>> x, y > (0.0, 0.0) > >>> x, y = -0.0, 0.0 > >>> x, y > (-0.0, -0.0) > > I would have expected y to be -0.0 in the first case, and 0.0 in the > second. Should the above be considered a bug, or is Python not > expected to honour signs of zeros? I'm working in a situation > involving complex arithmetic where branch cuts, and hence signed > zeros, are important, and it would be handy if the above code could be > relied upon to do the right thing.
Looks to me like you've found a bug with the parser/compiler: >>> c=compile('-0.0,0.0', 'eval', 'eval') >>> eval(c) (-0.0, -0.0) >>> dis.dis(c) 1 0 LOAD_CONST 1 ((-0.0, -0.0)) 3 RETURN_VALUE Similar problems appear in parsing display forms of lists and dicts and calls to functions with constant arguments (among which a constant 0.0 and a constant -0.0) -- and more generally when both constants -0.0 and 0.0 appear within the same "unit of compilation" (expression, function, ...) as for example in: >>> def f(): ... a = -0.0 ... return a, 0.0 ... >>> f() (-0.0, -0.0) >>> Why I think it has specifically to do with parsing/compiling, e.g.: >>> {23:-0.0, 45:0.0} {45: -0.0, 23: -0.0} >>> x=0.0 >>> y=-0.0 >>> {23:x, 45:y} {45: -0.0, 23: 0.0} >>> so there appears to be no problem once the 0.0 and -0.0 values come from variables or the like -- only if they're both from constants within the same "unit of compilation". Indeed, if you put the code above in a function, rather than in separate entries to the toplevel interpreter...: >>> def g(): ... x = 0.0 ... y = -0.0 ... return {23:x, 45:y} ... >>> g() {45: 0.0, 23: 0.0} >>> ...the bug surfaces again. Looks a bit like the result of a slightly errant "peephole optimizer" pass which tries to roll multiple occurrences of "the same constant" within the same codeobject into a single one, and consider two immutables a "multiple occurrence" if they're == to each other (as, indeed, 0.0 and -0.0 must be). The Python-coded compiler package does NOT give the problem: >>> compiler.compile('-0.0,0.0','zap','eval') <code object <expression> at 0x70068, file "zap", line 1> >>> dis.dis(_) 1 0 LOAD_CONST 1 (0.0) 3 UNARY_NEGATIVE 4 LOAD_CONST 1 (0.0) 7 BUILD_TUPLE 2 10 RETURN_VALUE ...presumably because it doesn't do peephole optimization (nor any other kind of optimization). Unfortunately I've never really looked in depth into these parts of Python so I can't help much; however, if you open a bug at <http://sourceforge.net/tracker/?group_id=5470> I think you stand a good chance of eventually seeing it fixed in 2.5.x for some x. Python/peephole.c does appear to be taking some care in constant folding: 192 case UNARY_NEGATIVE: 193 /* Preserve the sign of -0.0 */ 194 if (PyObject_IsTrue(v) == 1) 195 newconst = PyNumber_Negative(v); so I suspect the problem is elsewhere, but I can't find it yet. Alex In the meantime, I hope that some available workarounds for the bug are clear from this discussion: avoid using multiple constants in a single compilation unit where one is 0.0 and another is -0.0, or, if you really can't avoid that, perhaps use compiler.compile to explicitly build the bytecode you need. -- http://mail.python.org/mailman/listinfo/python-list