Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

negative zero components are ignored in complex number literals #70026

Closed
MarkLundeberg mannequin opened this issue Dec 11, 2015 · 6 comments
Closed

negative zero components are ignored in complex number literals #70026

MarkLundeberg mannequin opened this issue Dec 11, 2015 · 6 comments
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error

Comments

@MarkLundeberg
Copy link
Mannequin

MarkLundeberg mannequin commented Dec 11, 2015

BPO 25839
Nosy @mdickinson, @vstinner

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = <Date 2015-12-11.14:43:14.482>
created_at = <Date 2015-12-11.08:44:59.024>
labels = ['interpreter-core', 'type-bug', 'invalid']
title = 'negative zero components are ignored in complex number literals'
updated_at = <Date 2015-12-11.14:48:51.343>
user = 'https://bugs.python.org/MarkLundeberg'

bugs.python.org fields:

activity = <Date 2015-12-11.14:48:51.343>
actor = 'mark.dickinson'
assignee = 'none'
closed = True
closed_date = <Date 2015-12-11.14:43:14.482>
closer = 'mark.dickinson'
components = ['Interpreter Core']
creation = <Date 2015-12-11.08:44:59.024>
creator = 'Mark Lundeberg'
dependencies = []
files = []
hgrepos = []
issue_num = 25839
keywords = []
message_count = 6.0
messages = ['256209', '256210', '256211', '256215', '256216', '256217']
nosy_count = 3.0
nosy_names = ['mark.dickinson', 'vstinner', 'Mark Lundeberg']
pr_nums = []
priority = 'normal'
resolution = 'not a bug'
stage = None
status = 'closed'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue25839'
versions = ['Python 2.7', 'Python 3.4']

@MarkLundeberg
Copy link
Mannequin Author

MarkLundeberg mannequin commented Dec 11, 2015

Although -0.0 and +0.0 compare as equal using the == operator, they are distinct floating point numbers and in some cases behave differently. (See more information on the wikipedia article "Signed zero".) The distinction between +0.0 and -0.0 is most important in complex arithmetic, for example it is conventional and useful that sqrt(-1+0i) ==> +i and sqrt(-1-0i) ==> -i. Python currently allows the floating point number -0.0 to be entered as a literal:

>>> -0.0
-0.0

Complex floating point numbers in python also can hold negative zero components, as shown in their repr()

>>> -(1+0j)
(-1-0j)

However they cannot be input directly as literals; it is currently necessary to use the above construction. Unfortunately the output of the repr() cannot be used as a string literal to obtain the same number:

>>> (-1-0j)
(-1+0j)

except, in contrast:

>>> complex('-1-0j')
(-1-0j)

The literal -1-0j should yield a complex number with negative zero imaginary part. Note also that complex literals with negative zero real parts have the same bug, e.g. -0+1j is not the same as -(0-1j)

@MarkLundeberg MarkLundeberg mannequin added interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error labels Dec 11, 2015
@vstinner
Copy link
Member

You should use complex(a, b) to have a reliable behaviour.

Python parse doesn't see "-1-0j" as a complex literal, but as (-1)-(0j): int-complex. Example with the AST output:

>>> ast.dump(ast.parse('-1-0j'))
'Module(body=[Expr(value=BinOp(left=UnaryOp(op=USub(), operand=Num(n=1)), op=Sub(), right=Num(n=0j)))])'

It looks like complex has the same behaviour than float:

>>> x=-0.0; x=0+x; x.real
0.0
>>> x=-0.0; x=0-x; x.real
0.0
>>> x=complex(0.0, -0.0); x=0+x; (x.real, x.imag)
(0.0, 0.0)
>>> x=complex(0.0, -0.0); x=0-x; (x.real, x.imag)
(0.0, 0.0)

zero sign is lost on int+complex, int-complex, int+complex, int-complex.

@MarkLundeberg
Copy link
Mannequin Author

MarkLundeberg mannequin commented Dec 11, 2015

Good point, it is doing (int-complex), observe also the following pecularities:

>>> -0 - 0j
0j
>>> -0. - 0j
(-0+0j)
>>> -0j
-0j
>>> 0-0j
0j
>>> -(0j)
(-0-0j)
>>> 0.+(-0j)
0j

Does this mean the bug is in repr() ? As I understand the output of repr() is supposed to be something that can evaluated to recreate the same object. However I am unsure whether it would be nicer if repr() were to yield 'complex(-0.,-0.)' or '-(-0.+0j)'.

@mdickinson
Copy link
Member

This is something that comes up repeatedly on the bug tracker. There's no bug here in the complex type or the repr. What there *is* is a limitation resulting from the fact that Python doesn't have *imaginary* literals, only *complex* literals. So in:

-1-0j

the 0j is already a complex number with both real and imaginary parts equal to 0.0. Then -1 gets promoted to a complex number with real part -1 and imaginary part 0.0. And now you're doing:

complex(-1.0, 0.0) - complex(0.0, 0.0)

which naturally gives an imaginary part of +0.0 rather than 0.0.

You'll see the same issue in C: there was an attempt to fix it in C99 by introducing Imaginary types, but those Imaginary types haven't been widely adopted. The most recent reincarnation of the C standard finally introduces a macro that lets you instantiate a complex number in terms of its real and imaginary components (instead of doing real_part + imag_part * I); this is something that Python already has in the form of the complex constructor.

Closing as not a bug.

@mdickinson
Copy link
Member

As I understand the output of repr() is supposed to be something that can evaluated to recreate the same object.

Right, but that's an ideal that's not always achieved in practice. If I had my druthers, I'd 'fix' the repr of the complex object to return something that's written in terms of the constructor (for example, "complex(2.3, -0.0)"). I don't think that's a reasonable change from the POV of backwards compatibility though.

@mdickinson
Copy link
Member

Previous discussions: bpo-17336, bpo-22548

@ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

2 participants