Signed zeros: is this a bug?

M

Mark Dickinson

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
 
P

Paul Rubin

Mark Dickinson said:
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.
 
P

Paddy

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.
 
M

Michael Spencer

Gabriel said:
(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/pycompiler/branches/new_ast/

Michael
 
P

Paul Rubin

Paddy said:
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.
 
?

=?iso-8859-1?B?QW5kcuk=?=

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é
 
A

Alex Martelli

Gabriel Genellina said:
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/trunk/Python/peephole.c?rev=54086&view
=auto

to browse the current version on the trunk. Right under the Python
toplevel subdirectory in the sources, IOW.


Alex
 
A

Alex Martelli

Alex Martelli said:
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
 
A

Alex Martelli

Tim Peters said:
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.php> and 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
 
A

Alex Martelli

Mark Dickinson said:
[...]
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)

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
 
A

Alex Martelli

Paul Rubin said:
(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
 
J

Jorge Godoy

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... ;-)
 
A

Alex Martelli

Jorge Godoy said:
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
 
J

Jorge Godoy

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,
 
A

Alex Martelli

Jorge Godoy said:
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
 
M

Mark Dickinson

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
 
P

Paddy

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!
 
J

Jorge Godoy

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,
 
B

Ben Finney

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.
 
H

Hendrik van Rooyen

Paddy said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,789
Messages
2,569,634
Members
45,342
Latest member
Sicuro

Latest Threads

Top