473,395 Members | 1,915 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Signed zeros: is this a bug?

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.

Mark

Mar 11 '07 #1
38 2253
On Mar 11, 9:31 am, "Mark Dickinson" <dicki...@gmail.comwrote:
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.
IIRC, float.__repr__ just does whatever libc does. Have you tried
using printf("%g, %g", 0.0, -0.0) in a C program?

Mar 11 '07 #2
On Sunday 11 March 2007 10:31, Mark Dickinson
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.

Mark


This works for some reason
instead of x,y = -0.0, 0.0
clumpy but the results are right.

x = -0.0
y= 0.0

x,y
(-0.0, 0.0)


jim-on-linux
http:\\inqvista.com



Mar 11 '07 #3

"Dan Bishop" <da*****@yahoo.comwrote in message
news:11*********************@30g2000cwc.googlegrou ps.com...
| On Mar 11, 9:31 am, "Mark Dickinson" <dicki...@gmail.comwrote:
| 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)
|| IIRC, float.__repr__ just does whatever libc does. Have you tried
| using printf("%g, %g", 0.0, -0.0) in a C program?

Detailed FP behavior like this is system (and yes, libc) dependent. On
WinXP
IDLE 1.1.3
>>x,y = 0.0, -0.0
x,y
(0.0, 0.0)
>>x,y = -0.0, 0.0
x,y
(0.0, 0.0)
>>-0.0
0.0

Terry Jan Reedy

Mar 11 '07 #4
On Mar 11, 12:13 pm, "Terry Reedy" <tjre...@udel.eduwrote:
"Dan Bishop" <danb...@yahoo.comwrote in message

news:11*********************@30g2000cwc.googlegrou ps.com...
| On Mar 11, 9:31 am, "Mark Dickinson" <dicki...@gmail.comwrote:
| 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)
|| IIRC, float.__repr__ just does whatever libc does. Have you tried
| using printf("%g, %g", 0.0, -0.0) in a C program?

Detailed FP behavior like this is system (and yes, libc) dependent. On
WinXP
IDLE 1.1.3>>x,y = 0.0, -0.0
>x,y
(0.0, 0.0)
>x,y = -0.0, 0.0
x,y
(0.0, 0.0)
>-0.0

0.0

Terry Jan Reedy
Interesting. So on Windows there's probably no hope of what I want to
do working.
But on a platform where the C library does the right thing with signed
zeros, this
behaviour is still a little surprising. I guess what's happening is
that there's
some optimization that avoids creating two separate float objects for
a float literal
that appears twice, and that optimization doesn't see the difference
between 0. and -0.
>>x, y = 0., -0.
id(x) == id(y)
True

jim-on-linux's solution works in the interpreter, but not in a script,
presumably because we've got file-wide optimization rather than
line-by-line optimization.

#test.py
x = -0.0
y = 0.0
print x, y
#end test.py
>>import test
-0.0 -0.0

Mark

Mar 11 '07 #5
"Mark Dickinson" <di******@gmail.comwrote:
I guess what's happening is that there's some optimization that avoids
creating two separate float objects for a float literal that appears
twice, and that optimization doesn't see the difference between 0. and
-0.
Don't guess. Test.
>>def f():
x = 0.0
y = -0.0
return x, y
>>dis.dis(f)
2 0 LOAD_CONST 1 (0.0)
3 STORE_FAST 0 (x)

3 6 LOAD_CONST 1 (0.0)
9 STORE_FAST 1 (y)

4 12 LOAD_FAST 0 (x)
15 LOAD_FAST 1 (y)
18 BUILD_TUPLE 2
21 RETURN_VALUE

Yes. Just the one constant there.
Tim Peters wrote in
http://blog.gmane.org/gmane.comp.pyt.../day=20050409:
All Python behavior in the presence of a NaN, infinity, or signed zero
is a platform-dependent accident. This is because C89 has no such
concepts, and Python is written to the C89 standard. It's not easy to
fix across all platforms (because there is no portable way to do so in
standard C), although it may be reasonably easy to fix if all anyone
cares about is gcc and MSVC (every platform C compiler has its own set
of gimmicks for "dealing with" these things).
Mar 11 '07 #6
Mark Dickinson <di******@gmail.comwrote:
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 <expressionat 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=5470I 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.

Mar 11 '07 #7
On Mar 11, 1:21 pm, Duncan Booth <duncan.bo...@invalid.invalidwrote:
Tim Peters wrote inhttp://blog.gmane.org/gmane.comp.python.devel/day=20050409:
All Python behavior in the presence of a NaN, infinity, or signed zero
is a platform-dependent accident. This is because C89 has no such
concepts, and Python is written to the C89 standard. It's not easy to
fix across all platforms (because there is no portable way to do so in
standard C), although it may be reasonably easy to fix if all anyone
cares about is gcc and MSVC (every platform C compiler has its own set
of gimmicks for "dealing with" these things).
Understood. Platform dependent is fine. But does this really excuse
results
like the following?
>>from math import atan2
x = -0.; print atan2(0., -1.)
-3.14159265359
>>print atan2(0., -1.)
3.14159265359

Mark

Mar 11 '07 #8
Duncan Booth <du**********@invalid.invalidwrote:
"Mark Dickinson" <di******@gmail.comwrote:
I guess what's happening is that there's some optimization that avoids
creating two separate float objects for a float literal that appears
twice, and that optimization doesn't see the difference between 0. and
-0.

Don't guess. Test.
>def f():
x = 0.0
y = -0.0
return x, y
>dis.dis(f)
2 0 LOAD_CONST 1 (0.0)
3 STORE_FAST 0 (x)

3 6 LOAD_CONST 1 (0.0)
9 STORE_FAST 1 (y)

4 12 LOAD_FAST 0 (x)
15 LOAD_FAST 1 (y)
18 BUILD_TUPLE 2
21 RETURN_VALUE

Yes. Just the one constant there.
And yet, as I wrote in a parallel post (the result of quite some
exploration), Python/peephole.c takes specific precautions against
improperly "constant folding" for the unary-minus of 0.0 -- the
collapsing of 0.0 and -0.0 into the "same" constant must happen
elsewhere (I haven't found out where, yet) and doesn't happen in the
Python-coded compiler module. So (on platforms where the underlying C
libraries do the right thing) I think this specific "overzealous
constant folding" must be considered a small bug -- and should be easy
to fix (by specialcasing -0.0 like Python/peephole.c does) if I could
but find out where in the Python sources the folding is happening...
Alex
Mar 11 '07 #9
On Mar 11, 1:26 pm, a...@mac.com (Alex Martelli) wrote:
[Long analysis of probable cause of the problem]
Thank you for this. I was suspecting something along these lines,
but I don't yet know my way around the source well enough to figure
out where the problem was coming from.
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.
Yup: the workaround seems to be as simple as replacing all occurrences
of -0.0 with -(0.0). I'm embarrassed that I didn't figure this out
sooner.
>>x, y = -(0.0), 0.0
x, y
(-0.0, 0.0)

Mark

Mar 11 '07 #10

#########
>
Interesting. So on Windows there's probably no
hope of what I want to do working.
But on a platform where the C library does the
right thing with signed zeros, this
behaviour is still a little surprising. I
guess what's happening is that there's
some optimization that avoids creating two
separate float objects for a float literal
that appears twice, and that optimization
doesn't see the difference between 0. and -0.
>x, y = 0., -0.
id(x) == id(y)

True

jim-on-linux's solution works in the
interpreter, but not in a script, presumably
because we've got file-wide optimization rather
than line-by-line optimization.

#test.py
x = -0.0
y = 0.0
print x, y
#end test.py
>import test

-0.0 -0.0

Mark

This is the only way I could make this work in a
script.

from decimal import Decimal

x = Decimal( "-0.0")
y= Decimal("0.0")
print x,y
x = Decimal( "0.0")
y= Decimal("-0.0")
print x,y

jim-on-linux
http:\\www.inqvista.com




Mar 11 '07 #11
Mark Dickinson <di******@gmail.comwrote:
On Mar 11, 1:26 pm, a...@mac.com (Alex Martelli) wrote:
[Long analysis of probable cause of the problem]

Thank you for this. I was suspecting something along these lines,
but I don't yet know my way around the source well enough to figure
out where the problem was coming from.
The parser/compiler/etc are unfortunately some of the hardest parts of
the sources -- I'm not all that familiar with that part myself, which is
why it took me quite some digging.

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.

Yup: the workaround seems to be as simple as replacing all occurrences
of -0.0 with -(0.0). I'm embarrassed that I didn't figure this out
sooner.
>x, y = -(0.0), 0.0
x, y
(-0.0, 0.0)
Glad it works for you, but it's the kind of workaround that could break
with any minor tweak/optimization to the compiler... very fragile:-(.

I think i found the cause of the bug, BTW. The collection of constants
in a code object is built in Python/compile.c and it's built as a
dictionary, field u_consts in struct compiler_unit. The "visitor" for
an expression that is a number is (in a case statement)

case Num_kind:
ADDOP_O(c, LOAD_CONST, e->v.Num.n, consts);
break;

(line 2947 of compile.c in Python's current sources from svn). ADDOP_O
just calls compiler_addop_o, which in turn does compiler_add_o before
adding the opcode (LOAD_CONST)

compiler_add_o (at lines 903-933) is used for all of the temporary
dictionaries in compiler_unit; a Python equivalent, basically, would be:

def eqv_cao(somedict, someobj):
# make sure types aren't coerced, e.g. int and long
t = someobj, type(someobj)
if t in somedict:
return somedict[t]
somedict[t] = index = len(somedict)
return index

a simple and fast way to provide a distinct numeric index (0 and up) to
each of a bunch of (hashable) objects.

Alas, here is the problem...: 0.0 and -0.0 are NOT separate as dict
keys! They are == to each other. So are 0, 0L, and 0+j0, but the
compiler smartly distinguishes these cases by using (obj, type) as the
key (the *types* are distinguished, even though the *values*) are; this
doesn't help with 0.0 and -0.0 since both have type float.

So, the first occurrence of either 0.0 or -0.0 in the compilation unit
ends up in the table of constants, and every other occurrence of either
value later in the unit is mapped to that one constant value:-(

This is not trivial to fix cleanly...:-(. compiler_add_o would have to
test "is the object I'm storing -0.0" (I don't even know how to do that
in portable C...) and then do some kludge -- e.g. use as the key into
the dict (-0.0, 0) instead of (-0.0, float) for this one special case.
(I think the table of constants would still be emitted OK, since the
type part of the key is elided anyway in that table as placed in the
bytecode). Or maybe we should give up ever storing -0.0 in the tables
of constant and ALWAYS have "0.0, unary-minus" wherever it appears (that
would presumably require working on the AST-to-bytecode visitors that
currently work ever-so-slightly-differently for this specific
troublespot in the C-coded version vs the Python-coded one...).

If you know the proper way to test for -0.0 in portable C code (or some
feature macro to use in a #if to protect nonportable code) I could try
proposing the first of these two solutions as a patch (I'm not going to
keep delving into that AST and visitors much longer...:-), but I suspect
it would be rejected as "too tricky [and minisculely slowing down every
compilation] for something that's too much of special case [and Python
does not undertake to support in general anyway]". Still, we can't be
sure unless we try (and maybe somebody can think of a cleaner
workaround...).
Alex
Mar 11 '07 #12
Alex Martelli <al***@mac.comwrote:
...
Yup: the workaround seems to be as simple as replacing all occurrences
of -0.0 with -(0.0). I'm embarrassed that I didn't figure this out
sooner.
>>x, y = -(0.0), 0.0
>>x, y
(-0.0, 0.0)

Glad it works for you, but it's the kind of workaround that could break
with any minor tweak/optimization to the compiler... very fragile:-(.
OTOH, Python 2.4 works just fine...:

Python 2.4.3 (#1, Apr 7 2006, 10:54:33)
[GCC 4.0.1 (Apple Computer, Inc. build 5250)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>0.0,-0.0
(0.0, -0.0)
>>-0.0,0.0
(-0.0, 0.0)

so it seems to be very specifically a 2.5 problem.
Alex
Mar 11 '07 #13
Alex Martelli wrote:
Alas, here is the problem...: 0.0 and -0.0 are NOT separate as dict
keys! They are == to each other. So are 0, 0L, and 0+j0, but the
compiler smartly distinguishes these cases by using (obj, type) as the
key (the *types* are distinguished, even though the *values*) are; this
doesn't help with 0.0 and -0.0 since both have type float....
If you know the proper way to test for -0.0 in portable C code (or some
feature macro to use in a #if to protect nonportable code) ....
Perhaps you could add a type "NegativeFloat" -- a subtype of float,
and distinguish negative zero from zero that way. Not saying I know how
in portable C, but ....

--Scott David Daniels
sc***********@acm.org
Mar 11 '07 #14
On Mar 11, 2:59 pm, a...@mac.com (Alex Martelli) wrote:
[...]
OTOH, Python 2.4 works just fine...:

Python 2.4.3 (#1, Apr 7 2006, 10:54:33)
[GCC 4.0.1 (Apple Computer, Inc. build 5250)] on darwin
Type "help", "copyright", "credits" or "license" for more information.>>0.0,-0.0
(0.0, -0.0)
>-0.0,0.0

(-0.0, 0.0)

so it seems to be very specifically a 2.5 problem.
I've filed a bug report (bug #1678380) and got an impressively
quick response from MvL. It looks like this is a `won't fix'.
Oh well.

Thanks for all your help.

Mark

Mar 11 '07 #15
En Sun, 11 Mar 2007 15:26:01 -0300, Alex Martelli <al***@mac.comescribió:
Or maybe we should give up ever storing -0.0 in the tables
of constant and ALWAYS have "0.0, unary-minus" wherever it appears (that
would presumably require working on the AST-to-bytecode visitors that
currently work ever-so-slightly-differently for this specific
troublespot in the C-coded version vs the Python-coded one...).
I think that way is the less intrusive, doesn't rely on a particular FP
implementation, and the more likely to be accepted.
Looking at ast.c, the culprit is some optimization in ast_for_factor, line
1506
/* If the unary - operator is applied to a constant, don't generate
a UNARY_NEGATIVE opcode. Just store the approriate value as a
constant. The peephole optimizer already does something like
this but it doesn't handle the case where the constant is
(sys.maxint - 1). In that case, we want a PyIntObject, not a
PyLongObject.
*/

After the long "if", I would use parsenumber(STR(pnum)) and check the type
and value of the resulting object; if it's a float and 0.0, skip the
optimization and continue below as a normal case.
Unfortunately I'm not able to compile and test the code right now, so I
can't provide an actual patch. (At least, not until tuesday). But I hope
this simple comment is useful anyway...

(I cannot find peephole.c on the source distribution for Python 2.5, but
you menctioned it on a previous message, and the comment above refers to
the peephole optimizer... where is it?)

--
Gabriel Genellina

Mar 11 '07 #16
[attribution lost]
....
>>Yup: the workaround seems to be as simple as replacing all
occurrences
>>of -0.0 with -(0.0). I'm embarrassed that I didn't figure this out
sooner.

x, y = -(0.0), 0.0
x, y
(-0.0, 0.0)
[Alex Martelli]
>Glad it works for you, but it's the kind of workaround that could
break with any minor tweak/optimization to the compiler...
very fragile:-(.
[also Alex]
OTOH, Python 2.4 works just fine...:

Python 2.4.3 (#1, Apr 7 2006, 10:54:33)
[GCC 4.0.1 (Apple Computer, Inc. build 5250)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>0.0,-0.0
(0.0, -0.0)
>-0.0,0.0
(-0.0, 0.0)

so it seems to be very specifically a 2.5 problem.
It's a bug that keeps resurfacing, probably because there's no portable
way to test that it stays fixed :-( (it's not an accident that the OP
relied on atan2 to distinguish +0.0 from -0.0! they act the same in
/almost/ all contexts).

Python's grammar doesn't have negative numeric literals. Instead

"-" CONSTANT_LITERAL

looks like unary minus applied to the non-negative CONSTANT_LITERAL.
All early versions of Python worked that way too.

The first time the +/- 0.0 bug occurred is when the front end was
changed to act as if

"-" CONSTANT_LITERAL

were a literal in its own right, and then that +0.0 == -0.0 caused the
first instance of either in a compilation unit to be used as the value
for all instances of both throughout the compilation unit. That was
fixed by refusing to apply the optimimization if the value of
CONSTANT_LITERAL was a float that compared equal to 0.0.

2.5 introduced a new front end and more ambitious constant-folding, and
I expect the bug showed up again due to one of those.

Note: printing the value of a float 0 may not reveal its sign. IIRC,
glibc's float-to-string routines do display the sign of 0, but
Microsoft's do not. However, atan2() is sensitive to the sign under
both glibm and Microsoft's libm equivalent.
Mar 11 '07 #17
Tim Peters <ti*****@comcast.netwrites:
2.5 introduced a new front end and more ambitious constant-folding, and
I expect the bug showed up again due to one of those.
I hope it does get fixed. Not having referential transparency in a
basic math function like atan2 is pretty disturbing in a modern
computer language.
Mar 11 '07 #18
Dennis Lee Bieber <wl*****@ix.netcom.comwrites:
Pardon? What is "the right thing with signed zeros"... In the last
30 years I've been on machines that normalize floating zero into a true
zero (all bits are zero: mantissa, exponent, and sign). This is the
first time I've even seen a variable output as a negative 0.0!
Most machines these days use IEEE 754 which supports negative zero.

http://en.wikipedia.org/wiki/Negative_zero
Mar 11 '07 #19
On Mar 11, 5:15 pm, Tim Peters <tim....@comcast.netwrote:
It's a bug that keeps resurfacing, probably because there's no
portable
way to test that it stays fixed :-( (it's not an accident that the OP
relied on atan2 to distinguish +0.0 from -0.0! they act the same in
/almost/ all contexts).
Not an accident, but not a contrived example either. I'd rewritten
all the cmath routines (in pure Python) to be more numerically aware
and use the
`correct' (= those recommended by Kahan) branch cuts. It was in
writing the unit tests for this that the problems above surfaced.

By the way, I don't suppose that anybody would be interested in
a rewritten cmath for Python 2.6? It wouldn't be hard for me to
rewrite what I already have in C, and add suitable documentation
and tests.

Mark

Mar 11 '07 #20
"Mark Dickinson" <di******@gmail.comwrites:
By the way, I don't suppose that anybody would be interested in
a rewritten cmath for Python 2.6? It wouldn't be hard for me to
rewrite what I already have in C, and add suitable documentation
and tests.
I can't speak for the developers but my personal opinion is that this
is worthwhile. I'm pretty Common Lisp and Scheme specify the branch
cuts and I believe Java does the same. That is to help with the
consistency and predicability of program behavior as well as to help
various numerical algorithms. C has a different goal, which is to be
a semi-portable assembly language, putting priority instead on
minimizing intermediation between the programmer and the machine,
instead of on predicability. Python should take the approach of the
higher level languages and implement this stuff precisely, instead of
just going along with whatever loose semantics the underlying C
implementation happens to supply.
Mar 11 '07 #21
On Mar 11, 9:28 pm, Paul Rubin <http://phr...@NOSPAM.invalidwrote:
Dennis Lee Bieber <wlfr...@ix.netcom.comwrites:
Pardon? What is "the right thing with signed zeros"... In the last
30 years I've been on machines that normalize floating zero into a true
zero (all bits are zero: mantissa, exponent, and sign). This is the
first time I've even seen a variable output as a negative 0.0!

Most machines these days use IEEE 754 which supports negative zero.

http://en.wikipedia.org/wiki/Negative_zero
Isn't negative zero mathematically the same as zero? Isn't -0 just an
artefact of the representation of floating point numbers? Shouldn't
f(0) == f(-0) for all functions f?
I read the wikipedia article about meteorologists using -0 to denote a
negative number rounded to zero for the purposes of binning, i.e. if
you want to tally days with temperature above and below zero, but it
doesn't seem right. You should arrange for any temperature to be in
only one range and record temperatures to their determined accuracy. a
temperature of zero would only be in one bin and if a temperature is
read as -0.2 and th rounding says it should be taken as zero then it
should go in the same bin as any positive reading that is rounded to
zero.
Getting back to Python, shouldn't we strive to remove any distinction?
a zero is a zero regardless of sign and a function like atan returning
one of two different vaues for an argument of zero is actually
mathematically not a bad thing to do?

- Paddy.

Mar 11 '07 #22
Gabriel Genellina wrote:
>
(I cannot find peephole.c on the source distribution for Python 2.5, but
you menctioned it on a previous message, and the comment above refers to
the peephole optimizer... where is it?)
The peephole optimizer is in compile.c - the entry point is optimize_code

BTW, I have written a pure-Python compiler which aims to be functionally
identical to the Python 2.5 compiler, and is in fact very similar (much closer
than stdlib.compiler). It may be helpful in investigating alternative
workarounds for the -0.0 issue.

http://svn.brownspencer.com/pycompil...nches/new_ast/

Michael

Mar 11 '07 #23
"Paddy" <pa*******@googlemail.comwrites:
Most machines these days use IEEE 754 which supports negative zero.
http://en.wikipedia.org/wiki/Negative_zero

Isn't negative zero mathematically the same as zero? Isn't -0 just an
artefact of the representation of floating point numbers? Shouldn't
f(0) == f(-0) for all functions f?
Not sure what you mean. "Floating point numbers" and in particular
"IEEE 754 floating point numbers" are a set of values and operations
with particular characteristics, that computers happen to implement.
They are not the same thing as the mathematical real numbers. For
example, there are infinitely many real numbers, but there are only
finitely many 64-bit IEEE floating point numbers (at most 2**64 of
them). They don't satisfy the same algebraic laws as real numbers.
For example, (1e100 + 1) == 1e100, and as a consequence, (1e100 + 1) -
1e100 == 0, but (1e100 - 1e100) + 1 == 1, so the commutative addition
law doesn't hold. These are all part of a mesh of interlocking
compromises made in floating point computer arithmetic to approximate
real-number arithmetic with finite-precision values. At first (i.e.
from the early computer era through the 1970's or so) this stuff was
designed somewhat ad hoc by computer architects, but eventually
serious numerical mathemticians got into the act, figuring out how to
make the best possible choices of these compromises for numerical
computation. The result was IEEE 754, which resulted in Prof. Kahan
winning the Turing award in 1989.

IEEE 754 specifies that -0 and +0 are separate numbers. Yes it is an
artifact in the sense of being one of the compromises. But these
compromises all interact with each other to make the errors cancel in
various numerical algorithms. The existence of -0 in IEEE 754 is part
of an intricate framework designed very carefully over a long period
by extremely experienced and knowledgeable people who knew what they
were doing. It's not really wise to mess with it unless you're
planning to undertake a project to redesign computer arithmetic of
similar scope to the IEEE 754 effort.
Getting back to Python, shouldn't we strive to remove any distinction?
a zero is a zero regardless of sign and a function like atan returning
one of two different vaues for an argument of zero is actually
mathematically not a bad thing to do?
No. Floating point numbers are not the same as real numbers and they
don't satisfy the same laws. There have been some proposals
(rejected) for Python to support exact rational arithmetic in addition
to floating point and exact integer arithmetic. Exact rationals in
Python (if implemented) should behave like mathematical rationals.
But Python floating point arithmetic should follow IEEE 754, at least
when the hardware supports it, which these days is almost always.
Mar 11 '07 #24
On Mar 11, 7:49 pm, "Paddy" <paddy3...@googlemail.comwrote:
>
Isn't negative zero mathematically the same as zero? Isn't -0 just an
artefact of the representation of floating point numbers? Shouldn't
f(0) == f(-0) for all functions f?
Read the original post again... The relevant part is:
====
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.
====

You may want to read about branch cuts and complex arithmetics. I
don't mean this as a putdown - simply as a useful suggestion for you
to read.

André

Mar 11 '07 #25
Gabriel Genellina <ga*******@yahoo.com.arwrote:
En Sun, 11 Mar 2007 15:26:01 -0300, Alex Martelli <al***@mac.comescribió:
Or maybe we should give up ever storing -0.0 in the tables
of constant and ALWAYS have "0.0, unary-minus" wherever it appears (that
would presumably require working on the AST-to-bytecode visitors that
currently work ever-so-slightly-differently for this specific
troublespot in the C-coded version vs the Python-coded one...).

I think that way is the less intrusive, doesn't rely on a particular FP
implementation, and the more likely to be accepted.
Looking at ast.c, the culprit is some optimization in ast_for_factor, line
1506
/* If the unary - operator is applied to a constant, don't generate
a UNARY_NEGATIVE opcode. Just store the approriate value as a
constant. The peephole optimizer already does something like
this but it doesn't handle the case where the constant is
(sys.maxint - 1). In that case, we want a PyIntObject, not a
PyLongObject.
*/

After the long "if", I would use parsenumber(STR(pnum)) and check the type
and value of the resulting object; if it's a float and 0.0, skip the
optimization and continue below as a normal case.
Unfortunately I'm not able to compile and test the code right now, so I
can't provide an actual patch. (At least, not until tuesday). But I hope
this simple comment is useful anyway...
Yep, it sure might, if I can make time to act on it:-).

(I cannot find peephole.c on the source distribution for Python 2.5, but
you menctioned it on a previous message, and the comment above refers to
the peephole optimizer... where is it?)
http://svn.python.org/view/python/tr...rev=54086&view
=auto

to browse the current version on the trunk. Right under the Python
toplevel subdirectory in the sources, IOW.
Alex
Mar 12 '07 #26
Alex Martelli <al***@mac.comwrote:
...
Yep, it sure might, if I can make time to act on it:-).
....and I did -- patch 1678668 is right there, brand newm at
<http://sourceforge.net/tracker/index.php.

I hope it also satisfies the timbot's very reasonable lament about the
bug resurfacing once in a while, since it included one more unittest to
check whether the bug is there (TDD rocks!-).
Alex
Mar 12 '07 #27
Tim Peters <ti*****@comcast.netwrote:
...
It's a bug that keeps resurfacing, probably because there's no portable
way to test that it stays fixed :-( (it's not an accident that the OP
relied on atan2 to distinguish +0.0 from -0.0! they act the same in
Please take a look at my patch 1678668, brand new at
<http://sourceforge.net/tracker/index.phpand as yet unassigned (hint,
hint:-).

I hope it satisfies your very reasonable lament about the bug
resurfacing once in a while, since it included one more unittest to
check whether the bug is there (TDD rocks!-), based exactly on the
behavior of atan2 (only on IEEE-format machines, though).
2.5 introduced a new front end and more ambitious constant-folding, and
I expect the bug showed up again due to one of those.
Yep, in ast.c's ast_for_factor -- it lacks the specialcasing that
peephole.c does have (and my patch essentially adds it back).

If it's worth specialcasing in peephole.c (and I strongly agree with
Raymond's implicit opinion that it is), it should be just as worth
specialcasing in ast.c, no?-)
Alex
Mar 12 '07 #28
Mark Dickinson <di******@gmail.comwrote:
On Mar 11, 2:59 pm, a...@mac.com (Alex Martelli) wrote:
[...]
OTOH, Python 2.4 works just fine...:

Python 2.4.3 (#1, Apr 7 2006, 10:54:33) [GCC 4.0.1 (Apple Computer,
Inc. build 5250)] on darwin Type "help", "copyright", "credits" or
"license" for more information.>>0.0,-0.0
(0.0, -0.0)
>>-0.0,0.0
(-0.0, 0.0)

so it seems to be very specifically a 2.5 problem.

I've filed a bug report (bug #1678380) and got an impressively
quick response from MvL. It looks like this is a `won't fix'.
Oh well.
That bug isn't formally closed yet, and the discussion's going on, we'll
see. Meanwhile can you try my patch 1678668 just to double check it
does fix everything? (It's agains the current HEAD of Python's svn).
Alex
Mar 12 '07 #29
Paul Rubin <http://ph****@NOSPAM.invalidwrote:
(rejected) for Python to support exact rational arithmetic in addition
to floating point and exact integer arithmetic. Exact rationals in
Python (if implemented) should behave like mathematical rationals.
But Python floating point arithmetic should follow IEEE 754, at least
when the hardware supports it, which these days is almost always.
Incidentally (and I know you know that, Paul, but others interested in
this thread might not) fast exact rational arithmetic (based on the LGPL
library named GMP) is supplied, among other functionality, by module
gmpy, currently found at http://code.google.com/p/gmpy/ (this version is
more recent than the older one at sourceforce, which for some reason
doesn't let me update things right any more).
Alex
Mar 12 '07 #30
al***@mac.com (Alex Martelli) writes:
Incidentally (and I know you know that, Paul, but others interested in
this thread might not) fast exact rational arithmetic (based on the LGPL
library named GMP) is supplied, among other functionality, by module
gmpy, currently found at http://code.google.com/p/gmpy/ (this version is
more recent than the older one at sourceforce, which for some reason
doesn't let me update things right any more).
For some reason setuptools isn't finding it:

jupiter:~ # easy_install gmpy
Searching for gmpy
Reading http://cheeseshop.python.org/pypi/gmpy/
Reading http://code.google.com/p/gmpy/
Reading http://cheeseshop.python.org/pypi/gmpy/1.02
No local packages or download links found for gmpy
error: Could not find suitable distribution for Requirement.parse('gmpy')
I believe that setuptools isn't ready to find packages on code.google.com
yet... ;-)

--
Jorge Godoy <jg****@gmail.com>
Mar 12 '07 #31
Jorge Godoy <jg****@gmail.comwrote:
al***@mac.com (Alex Martelli) writes:
Incidentally (and I know you know that, Paul, but others interested in
this thread might not) fast exact rational arithmetic (based on the LGPL
library named GMP) is supplied, among other functionality, by module
gmpy, currently found at http://code.google.com/p/gmpy/ (this version is
more recent than the older one at sourceforce, which for some reason
doesn't let me update things right any more).

For some reason setuptools isn't finding it:

jupiter:~ # easy_install gmpy
Searching for gmpy
Reading http://cheeseshop.python.org/pypi/gmpy/
Reading http://code.google.com/p/gmpy/
Reading http://cheeseshop.python.org/pypi/gmpy/1.02
No local packages or download links found for gmpy
error: Could not find suitable distribution for Requirement.parse('gmpy')
I believe that setuptools isn't ready to find packages on code.google.com
yet... ;-)
I'm not familiar with setuptools, what exactly is it looking for?

If it's looking for stuff to download it should start at

http://code.google.com/p/gmpy/downloads/list

(but what does it want -- the sources' zipfile, or some binary, and in
what format and with what naming convention?) -- I'll be glad to edit
the URL for gmpy at cheeseshop if some setuptools expert can explain
these subtleties... thanks for pointing out that there's a problem
btw!-)
Alex
Mar 12 '07 #32
al***@mac.com (Alex Martelli) writes:
I'm not familiar with setuptools, what exactly is it looking for?

If it's looking for stuff to download it should start at

http://code.google.com/p/gmpy/downloads/list

(but what does it want -- the sources' zipfile, or some binary, and in
what format and with what naming convention?) -- I'll be glad to edit
the URL for gmpy at cheeseshop if some setuptools expert can explain
these subtleties... thanks for pointing out that there's a problem
btw!-)
Thanks for caring ;-)
It looks for several things: eggs (for the Python version it is being used),
zipfiles and tarballs (I dunno if it looks for more things).

If it finds, for example, gmpy-1.0.2-py2.4.egg it won't install here 'cause I
use Python 2.5 and then it will continue searching for gmpy-1.0.2-py2.5.egg or
an alternative format that can be used. The last resort is the tarball / zip
with the sources so that the package can be rebuilt.

Probably other people that are more experienced with it can help more. I'm
more an end user of it and I know the essential for my needs.

I just pointed out because setuptools helps a lot on obtaining a package and
installing it (even if there's some building needed before installing).
Sorry for not being able to help more.
With regards to the hyperlink, I believe that if the link on Pypi was to the
URL above it would be easier. Another alternative is a link at the first
page. And, of course, the last alternative is teaching setuptools how to work
with code.google.com -- if it doesn't already know -- as it learnt how to work
with SourceForge and its "random" mirrors. I don't know how to write that
code, though.
Be seeing you,
--
Jorge Godoy <jg****@gmail.com>
Mar 12 '07 #33
Jorge Godoy <jg****@gmail.comwrote:
...
these subtleties... thanks for pointing out that there's a problem
btw!-)

Thanks for caring ;-)
Hey, I'd just love to make it as easy as possible to get gmpy -- that's
why I (shudder!-) even build and upload Windows installers...

It looks for several things: eggs (for the Python version it is being used),
zipfiles and tarballs (I dunno if it looks for more things).

If it finds, for example, gmpy-1.0.2-py2.4.egg it won't install here 'cause I
use Python 2.5 and then it will continue searching for gmpy-1.0.2-py2.5.egg or
an alternative format that can be used. The last resort is the tarball / zip
with the sources so that the package can be rebuilt.
OK, the .zip file IS there -- I don't know how to build .egg ones but of
course I could study up on it -- can you suggest a URL?

To be usable on Windows w/o effort, the packaged format must contain a
..pyd (and, on Mac, a .so, etc). Can a .egg deal w/that?

I need to find out w/certainty, because once I've uploaded a file w/a
certain name I can't change the name, nor the contents -- the URLs on
code.google.com are meant to be permanent...
Probably other people that are more experienced with it can help more. I'm
more an end user of it and I know the essential for my needs.

I just pointed out because setuptools helps a lot on obtaining a package and
installing it (even if there's some building needed before installing).
OK, but since most Windows users don't have a suitable C compiler, and
many Mac ones never bother installing the C compiler that comes with
their OS DVDs, if I'm to make things easy I definitely need to pack up
binaries. How do I pack binaries (for dynamic link libraries) that need
to be very different on Win, Mac, various Linux distros...?
Sorry for not being able to help more.
With regards to the hyperlink, I believe that if the link on Pypi was to the
URL above it would be easier. Another alternative is a link at the first
page. And, of course, the last alternative is teaching setuptools how to work
with code.google.com -- if it doesn't already know -- as it learnt how to work
with SourceForge and its "random" mirrors. I don't know how to write that
code, though.
Me neither, knowing near to nothing about setuptools (I'm not even a
user of it...). Let's hope some expert does speak up -- I can't just
freely experiment with uploads and the like...
Alex
Mar 12 '07 #34
On Mar 11, 9:56 pm, a...@mac.com (Alex Martelli) wrote:
That bug isn't formally closed yet, and the discussion's going on, we'll
see. Meanwhile can you try my patch 1678668 just to double check it
does fix everything? (It's agains the current HEAD of Python's svn).
It does, and all tests pass. (Still on OS X 10.4.8/PowerPC; I'll
test
it tomorrow on my Linux machine at work.)

Mark

Mar 12 '07 #35
On Mar 11, 10:49 pm, "Paddy" <paddy3...@googlemail.comwrote:
On Mar 11, 9:28 pm, Paul Rubin <http://phr...@NOSPAM.invalidwrote:
Dennis Lee Bieber <wlfr...@ix.netcom.comwrites:
Pardon? What is "the right thing with signed zeros"... In the last
30 years I've been on machines that normalize floating zero into a true
zero (all bits are zero: mantissa, exponent, and sign). This is the
first time I've even seen a variable output as a negative 0.0!
Most machines these days use IEEE 754 which supports negative zero.
http://en.wikipedia.org/wiki/Negative_zero

Isn't negative zero mathematically the same as zero? Isn't -0 just an
artefact of the representation of floating point numbers? Shouldn't
f(0) == f(-0) for all functions f?
I read the wikipedia article about meteorologists using -0 to denote a
negative number rounded to zero for the purposes of binning, i.e. if
you want to tally days with temperature above and below zero, but it
doesn't seem right. You should arrange for any temperature to be in
only one range and record temperatures to their determined accuracy. a
temperature of zero would only be in one bin and if a temperature is
read as -0.2 and th rounding says it should be taken as zero then it
should go in the same bin as any positive reading that is rounded to
zero.
Getting back to Python, shouldn't we strive to remove any distinction?
a zero is a zero regardless of sign and a function like atan returning
one of two different vaues for an argument of zero is actually
mathematically not a bad thing to do?

- Paddy.
A big thanks to Paul and Andre,
I think I have it now. The OP is investigating multivalued functions
where the function converges to different values when approached from
different directions. Floating point arithmetic being a best
compromise solution to the rational number system, distinguishes
between zero and minus zero as an important part of the compromise.
The OP wants to compute a function of zero and minus zero distinctly
and is hampered by Python not preserving the zero/minus zero
distinction in some cases - hence it being a bug.

Swell, Ta!

- Paddy.

Hey, I'm still learnin'. Sweet!

Mar 12 '07 #36
al***@mac.com (Alex Martelli) writes:
Hey, I'd just love to make it as easy as possible to get gmpy -- that's
why I (shudder!-) even build and upload Windows installers...
Brave man! :-)
OK, the .zip file IS there -- I don't know how to build .egg ones but of
course I could study up on it -- can you suggest a URL?
The .egg is nice because it can be an already built binary.

http://peak.telecommunity.com/DevCenter/setuptools

The URL above contains examples and instructions on how to use setuptools.
To be usable on Windows w/o effort, the packaged format must contain a
.pyd (and, on Mac, a .so, etc). Can a .egg deal w/that?
Yes. I have a .egg that has a .so here, for rpy (http://rpy.sf.net/).
I need to find out w/certainty, because once I've uploaded a file w/a
certain name I can't change the name, nor the contents -- the URLs on
code.google.com are meant to be permanent...
Hmmm... I'd suggest you to build only locally then... I don't like this kind
of "permanent" things. They could have a flag "publish this" to make it
permanent and make the standard "unpublished". Here's a suggestion for you to
forward there inside Google... ;-)
OK, but since most Windows users don't have a suitable C compiler, and
many Mac ones never bother installing the C compiler that comes with
their OS DVDs, if I'm to make things easy I definitely need to pack up
binaries. How do I pack binaries (for dynamic link libraries) that need
to be very different on Win, Mac, various Linux distros...?
One build per platform would be my choice. Packing everything together would
make the package too big (specially if you start supporting other OSs).
Me neither, knowing near to nothing about setuptools (I'm not even a
user of it...). Let's hope some expert does speak up -- I can't just
freely experiment with uploads and the like...
Lets wait. ;-)

Thanks again,
--
Jorge Godoy <jg****@gmail.com>
Mar 12 '07 #37
al***@mac.com (Alex Martelli) writes:
This is not trivial to fix cleanly...:-(. compiler_add_o would have
to test "is the object I'm storing -0.0" (I don't even know how to
do that in portable C...) and then do some kludge -- e.g. use as the
key into the dict (-0.0, 0) instead of (-0.0, float) for this one
special case.
Another way, which avoids making this decision, is to always store the
sign *and* value of the number as part of the key. I don't know if
that tradeoff is the right one though.

--
\ "Our products just aren't engineered for security." -- Brian |
`\ Valentine, senior vice-president of Microsoft Windows |
_o__) development |
Ben Finney

Mar 12 '07 #38
"Paddy" <pa...y3***@googlemail.comwrote
>
Hey, I'm still learnin'. Sweet!
contrary to popular belief, the answer to life,
the universe, happiness and everything is
not 42, but the above.

- Hendrik

Mar 13 '07 #39

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: TheTeapot | last post by:
Hi all, Here's a puzzle: // Say I have an array of numbers set up like so: $arr = array(15,16,17,100,121,1000); // How can I create a function so that I can use it like so:...
5
by: samik_tanik | last post by:
I need to export a datagrid to Excel. I could did this. But, also need to keep the leading zeros in the data. How can I acheive this? Any help would be appreciated. -- Thanking you in...
4
by: Ken Tough | last post by:
Seems like a simple thing to find out, but I'm struggling. I have googled, but everything I find is about implicit conversion, not explicit. Is this implementation-specific, or does ANSI/ISO...
2
by: Teep | last post by:
I have a simple text box called txtrefnum, if the user enters a number length less than 9 characters long than I need to have lead zeros added to it. Does anyone know how to do this? I couldn't...
6
by: TN Bella | last post by:
I have a simple text box called txtrefnum, if the user enters a number length less than 9 characters long than I need to have lead zeros added to it. Does anyone know how to do this? I couldn't...
15
by: Bob | last post by:
I'm about to convert to string and use regex, but I thought there must be something I'm missing here that already exists. Bob
18
by: Susan Rice | last post by:
I'm comparing characters via return(str1 - str2); and I'm having problems with 8-bit characters being treated as signed instead of unsigned integers. The disassembly is using movsx ...
6
by: JimmyKoolPantz | last post by:
Task: Customer wants a script of the data that was processed in a "CSV" file. Problem: Zip-Code leading zeros are dropped Basically we have a client that has requested a custom script for...
3
by: ManuelValdez | last post by:
Hello everybody! I need your valuable help to get an Excel macro to delete the single zeros only and no the zeros containing numbers like 360, 90, etc., because if I chose the search and replace...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.