473,699 Members | 2,525 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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
38 2280

#########
>
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.compil e 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(somedic t, 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.comw rote:
...
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 "NegativeFl oat" -- 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***********@a cm.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.come scribió:
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_LITERA L

looks like unary minus applied to the non-negative CONSTANT_LITERA L.
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_LITERA L

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_LITERA L 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*****@comcas t.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.net com.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....@comcas t.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

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

Similar topics

8
2738
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: addleadingzeros_arr($arr); // and have the output look like:
5
11506
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 anticipation, Regards,
4
2657
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 lay out what should happen for: -------------------------- signed char sc; unsigned char uc;
2
1595
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 find anything online on the subject... <asp:TextBox id="txtRefNum" runat="server"></asp:TextBox> I thought I could use a validator for the process and make the user add the zeros, but of course that is a big no-no! Please help!!
6
1411
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 find anything online on the subject... <asp:TextBox id="txtRefNum" runat="server"></asp:TextBox> I thought I could use a validator for the process and make the user add the zeros, but of course that is a big no-no! Please help!!
15
20097
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
1749
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 eax,byte ptr to load my character in to EAX register. I need it to use movzx.
6
7758
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 each file that he has us process. He wants this in a Comma Delimited Format.
3
9919
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 in the Edit option, then all the zeros containing the numbers 360, 90, 502, etc. will be deleted. Some nice person helped me with the following code to delete the zeros: Selection.Replace What:="0", Replacement:="" , but unfortunately this code...
0
8689
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8618
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
1
8916
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8885
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 protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
6534
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5875
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4631
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
2348
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2010
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.