This issue tracker has been migrated to GitHub ,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2020年04月13日 00:03 by rushilu, last changed 2022年04月11日 14:59 by admin. This issue is now closed.
| Pull Requests | |||
|---|---|---|---|
| URL | Status | Linked | Edit |
| PR 19498 | closed | mark.dickinson, 2020年04月13日 10:11 | |
| PR 19593 | open | serhiy.storchaka, 2020年04月19日 08:18 | |
| Messages (15) | |||
|---|---|---|---|
| msg366276 - (view) | Author: Rushil Udani (rushilu) | Date: 2020年04月13日 00:03 | |
In a Python REPL: >>> -1j (-0-1j) >>> (-1j) (-0-1j) >>> 0-1j -1j >>> -0-1j -1j This is clearly inconsistent behavior! -1j and (-1j) should report as -1j, as the other two do. |
|||
| msg366278 - (view) | Author: Josh Rosenberg (josh.r) * (Python triager) | Date: 2020年04月13日 00:38 | |
The final entry is identical to the second to last, because ints have no concept of -0. If you used a float literal, it would match the first two: >>> -0.-1j (-0-1j) I suspect the behavior here is due to -1j not actually being a literal on its own; it's interpreted as the negation of 1j, where 1j is actually 0.0+1.0j, and negating it flips the sign on both the real and imaginary component. From what I can read of the grammar rules, this is expected; the negation isn't ever part of the literal (minus signs aren't part of the grammar aside from exponents in scientific notation). https://docs.python.org/3/reference/lexical_analysis.html#floating-point-literals If this is a bug, it's a bug in the grammar. I suspect the correct solution here is to include the real part explicitly, as 0.0-1j works just fine. |
|||
| msg366280 - (view) | Author: Raymond Hettinger (rhettinger) * (Python committer) | Date: 2020年04月13日 01:46 | |
The docs for complex literals1 could be improved to show that: -1j is interpreted as -complex(0.0, 1.0) giving a real component of -0.0 and an imaginary component of -1.0 and that: 0-1j is interpreted as 0.0-complex(0.0, 1.0) giving a real component of 0.0 and an imaginary component of -1.0 It is unfortunate the repr for complex numbers uses integers at all. That hides what is going on. 1 https://docs.python.org/3/reference/lexical_analysis.html#imaginary-literals |
|||
| msg366283 - (view) | Author: Steven D'Aprano (steven.daprano) * (Python committer) | Date: 2020年04月13日 03:22 | |
Would we be willing to consider an enhancement to have complex numbers always display using float format rather than ints? 1+1j --> 1.0+1.0j We could still suppress an unsigned real zero: 1j --> 1.0j but negative zero would show: -(1j) --> -0.0-1.0j I daresay this would break some doctests (CC'ing Tim, as he is a heavy user of doctests) but perhaps it would be worthwhile. Aside from the backwards-compatibility issue, going against this suggestion we have the popular Texas Instruments Nspire calculator, which shows complex numbers as ints when possible. On the other hand, the imaginary unit is shown as the symbolic constant i with no coefficient, and it also shows complex numbers with an explicit multiplication sign: 2⋅i rather than 2i. Similarly, Julia shows complex numbers with integer coefficients when possible: https://docs.julialang.org/en/v1/manual/complex-and-rational-numbers/ |
|||
| msg366287 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) | Date: 2020年04月13日 08:48 | |
It is a known issue, but I have no references to previous discussions. Outputting numbers with decimal point will not help in case of complex(-0.0, 1.0). Maybe the only way to solve this problem is to implement special Imaginary type (as a subclass of complex). |
|||
| msg366289 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2020年04月13日 09:29 | |
See also #25839, #22548; there's lot of discussion of the core issue on those tickets. As Serhiy says, the only reasonable "true" fix would be to have 1j be a genuine imaginary literal, but that's a lot of work and potential disruption (not just to core Python, but to 3rd party libraries that care about complex numbers) for not a lot of gain. A documentation improvement as suggested by Raymond sounds good. I'm not keen on messing with the complex __repr__ again, but if we did, I'd propose not only representing real and imaginary parts in a way that's consistent with floats (so with both real and imaginary parts having either decimal points or exponents), but also showing _both_ the real and imaginary parts in all complex numbers. That is: >>> 1j 0.0 + 1.0j Or if we're willing to accept more backwards compatibility breakage, there's a case for having the __repr__ (but not the __str__) of a complex number take the form >>> 1j complex(0.0, 1.0) since this the only way that allows easy round-tripping. Otherwise you still have this problem: >>> complex(-0.0, 1.0) (-0+1j) >>> -0 + 1j 1j BTW, I still dislike the parentheses around the current complex repr. Let's keep this issue open for potential documentation improvements. If we want to change the repr of complex, let's open another issue for that. |
|||
| msg366293 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) | Date: 2020年04月13日 09:49 | |
The Imaginary type could help to solve other "gotchas". For example, in Python
>>> complex(0, float('inf')) * 1
(nan+infj)
But in C++ you will get the real component 0, because multiplication of complex and real numbers is component wise.
With the Imaginary type we could get that 1j * x == complex(0, x) for all float x, including infinity and NaN.
Returning to the repr, the other way to correctly represent the repr of complex(-0.0, 1.0) is writing it as "-(0.0-1j)", but it looks unnatural to me.
|
|||
| msg366294 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2020年04月13日 10:04 | |
> The Imaginary type could help to solve other "gotchas". Yes, it's an attractive proposition from many angles: e.g., multiplying by 1j could do the correct quarter-turn rotation in the complex plane, keeping all signs correct, so that multiplying a complex number z by 1j 4 times exactly recovers z, regardless of nans, infinities and signed zeros. C99's specification of (optional) imaginary types was supposed to solve exactly this problem, but it doesn't look as though it received widespread adoption, and I suspect it would have difficult getting traction in Python world, too. I'll have a PR with a documentation update shortly. |
|||
| msg366298 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2020年04月13日 10:40 | |
Another related issue is #23229, where Guido says (in msg233963): > BTW I don't want repr() of a complex number to use the > complex(..., ...) notation -- it's too verbose. |
|||
| msg366733 - (view) | Author: Raymond Hettinger (rhettinger) * (Python committer) | Date: 2020年04月18日 18:35 | |
Since integers don't have signed zeros, the use of integers in the complex repr is a little weird: >>> (-0-1j) # The unary minus in the repr has no effect. -1j >>> (0-1j) -1j |
|||
| msg366764 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) | Date: 2020年04月19日 08:26 | |
I tried to make repr of floats producing a string which rounds up with eval() (see PR 19593). >>> complex(0.0, 1.0) 1j >>> complex(0.0, -1.0) (0-1j) >>> complex(-0.0, 1.0) -(0-1j) >>> complex(-0.0, -1.0) (-0.0-1j) >>> complex(1.0, 0.0) (1+0j) >>> complex(-1.0, 0.0) (-1+0j) >>> complex(1.0, -0.0) -(-1+0j) >>> complex(-1.0, -0.0) -(1+0j) The largest problem is with complex(-0.0, 0.0) and complex(-0.0, 0.0). The only forms which evaluate to these numbers are: >>> complex(-0.0, 0.0) (-0.0-0j) >>> complex(0.0, -0.0) -(-0.0-0j) But it conflicts with the constructor: >>> complex('(-0.0-0j)') -(0+0j) |
|||
| msg366773 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2020年04月19日 09:55 | |
> I tried to make repr of floats producing a string which rounds up with eval() We've looked at this before. There just isn't any sane and easy way to do this, except for changing the repr to be "complex(real, imag)", which is the solution that I favour. And this seems like a non-starter to me: >>> complex(0.0, -0.0) -(-0.0-0j) This is a case where the cure is worse than the disease. We should also not change the repr lightly: the last time it was changed, it caused disruption at least for Cython, and probably for NumPy too. As a corollary, if we _do_ change it, we should make sure we get it right so that we're changing it to something we're not going to want to change again in 5 years' time. And I suspect that if we don't solve the underlying roundtrip problem, then this is going to come up again. I'm +1 on changing the repr to "complex(..., ...)", +0 on modifying it to always include both real and imaginary parts _and_ format those parts as though they're floats; -1 on other changes. |
|||
| msg367553 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2020年04月28日 18:40 | |
Closing this. Please open a separate issue for changing the complex repr if that's the way that you want to go. |
|||
| msg367721 - (view) | Author: Terry J. Reedy (terry.reedy) * (Python committer) | Date: 2020年04月30日 00:22 | |
After reading through the comments, I don't think we should change repr(complex) unless there is computational issue, such as eval(repr(z) != z. Raymond, I agree with your overlooked doc tweek. If you submit a PR, you can ask me to review. |
|||
| msg374874 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2020年08月05日 11:14 | |
Updating resolution to "duplicate", in an effort to keep discussion in a single place. |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022年04月11日 14:59:29 | admin | set | github: 84450 |
| 2020年08月05日 11:14:17 | mark.dickinson | set | superseder: Complex number representation round-trip doesn't work with signed zero values resolution: not a bug -> duplicate messages: + msg374874 |
| 2020年04月30日 00:22:26 | terry.reedy | set | nosy:
+ terry.reedy messages: + msg367721 |
| 2020年04月28日 18:40:06 | mark.dickinson | set | status: open -> closed resolution: not a bug messages: + msg367553 stage: patch review -> resolved |
| 2020年04月19日 09:55:39 | mark.dickinson | set | messages: + msg366773 |
| 2020年04月19日 08:26:52 | serhiy.storchaka | set | messages: + msg366764 |
| 2020年04月19日 08:18:40 | serhiy.storchaka | set | pull_requests: + pull_request18928 |
| 2020年04月18日 18:35:11 | rhettinger | set | messages: + msg366733 |
| 2020年04月13日 10:40:14 | mark.dickinson | set | messages: + msg366298 |
| 2020年04月13日 10:11:59 | mark.dickinson | set | keywords:
+ patch stage: patch review pull_requests: + pull_request18849 |
| 2020年04月13日 10:04:58 | mark.dickinson | set | messages: + msg366294 |
| 2020年04月13日 09:49:20 | serhiy.storchaka | set | messages: + msg366293 |
| 2020年04月13日 09:29:58 | mark.dickinson | set | nosy:
+ docs@python messages: + msg366289 assignee: docs@python components: + Documentation, - Interpreter Core type: behavior -> enhancement |
| 2020年04月13日 08:48:55 | serhiy.storchaka | set | nosy:
+ serhiy.storchaka messages: + msg366287 |
| 2020年04月13日 03:22:41 | steven.daprano | set | nosy:
+ steven.daprano, tim.peters messages: + msg366283 |
| 2020年04月13日 01:46:55 | rhettinger | set | nosy:
+ rhettinger messages: + msg366280 |
| 2020年04月13日 01:23:10 | rhettinger | set | nosy:
+ mark.dickinson |
| 2020年04月13日 00:38:23 | josh.r | set | nosy:
+ josh.r messages: + msg366278 |
| 2020年04月13日 00:03:28 | rushilu | create | |