Skip to content

Invalid "equivalents" of the complex type constructor in docs #109218

@skirpichev

Description

@skirpichev
Contributor

The sphinx docs says:

class complex(real=0, imag=0)
[...]
Return a complex number with the value real + imag*1j or convert a string or number to a complex number.
[...]

The docstring (btw it doesn't mention a string as an argument):

>>> print(complex.__doc__)
Create a complex number from a real part and an optional imaginary part.

This is equivalent to (real + imag*1j) where imag defaults to 0.

That wrong, e.g.:

>>> complex(0.0, -0.0)
-0j
>>> 0.0 + (-0.0)*1j
0j
>>> complex(-0.0, -0.0)
(-0-0j)
>>> -0.0 + (-0.0)*1j
(-0+0j)
>>> complex(-0.0, 0.0)
(-0+0j)
>>> -0.0 + 0.0*1j
0j
Here is an attempt (patch) to solve, let me know if this is worth a PR:
diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index d9974c6350..78b85658ef 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -373,8 +373,8 @@ are always available.  They are listed here in alphabetical order.
 .. class:: complex(real=0, imag=0)
            complex(string)

-   Return a complex number with the value *real* + *imag*\*1j or convert a string
-   or number to a complex number.  If the first parameter is a string, it will
+   Create a complex number from a real part and an optional imaginary part
+   or convert a string to a complex number.  If the first parameter is a string, it will
    be interpreted as a complex number and the function must be called without a
    second parameter.  The second parameter can never be a string. Each argument
    may be any numeric type (including complex).  If *imag* is omitted, it
diff --git a/Objects/complexobject.c b/Objects/complexobject.c
index 0e96f54584..336b703233 100644
--- a/Objects/complexobject.c
+++ b/Objects/complexobject.c
@@ -886,9 +886,8 @@ complex.__new__ as complex_new
     real as r: object(c_default="NULL") = 0
     imag as i: object(c_default="NULL") = 0

-Create a complex number from a real part and an optional imaginary part.
-
-This is equivalent to (real + imag*1j) where imag defaults to 0.
+Create a complex number from a real part and an optional imaginary part
+or convert a string to a complex number.
 [clinic start generated code]*/

 static PyObject *

Edit:
Another instance of this issue is in the cmath docs:

A Python complex number ``z`` is stored internally using *rectangular*
or *Cartesian* coordinates.  It is completely determined by its *real
part* ``z.real`` and its *imaginary part* ``z.imag``.  In other
words::

   z == z.real + z.imag*1j

E.g.:

>>> from cmath import inf
>>> complex(0.0, inf)
infj
>>> 0.0 + inf*1j
(nan+infj)

Linked PRs

Activity

mdickinson

mdickinson commented on Sep 11, 2023

@mdickinson
Member

Note that the two arguments to complex can themselves be complex numbers, so describing them as the real and imaginary part isn't always accurate:

>>> complex(1+2j, 1-2j)
(3+3j)
skirpichev

skirpichev commented on Sep 12, 2023

@skirpichev
ContributorAuthor

two arguments to complex can themselves be complex numbers

Indeed, but in this form the "equivalency" complex(r, i) == r + i*1j is also broken:

>>> complex(r := nan-infj, i := -inf+infj)
(nan-infj)
>>> r + i*1j
(nan+nanj)
>>> complex(r := -0.0-0j, i := 1+0j)
(-0+1j)
>>> r + i*1j
1j

Under the hood, instead, we have:

>>> complex(r.real - i.imag, i.real + r.imag)
(-0+1j)

describing them as the real and imaginary part isn't always accurate

It's used in the current docstring, anyway.

Lets decide, however, whether this is a bug, regardless from the outcome in the mentioned discussion. Or not (as for complex vs eval(repr(complex))).

added 3 commits that reference this issue on May 25, 2024
skirpichev

skirpichev commented on May 25, 2024

@skirpichev
ContributorAuthor

@mdickinson, does this looks as an issue for you or we should accept imprecise docs? I don't see good ways to reword docs, while keeping them short and expressive.

Not sure, if this is a good idea to revival the d.p.o thread. On another hand, mentioned in the d.p.o variant with the imaginary type isn't explored well. Here is an implementation of the imaginary type & mixed-mode arithmetic rules: skirpichev#1 Among others, that should address current issue.
@serhiy-storchaka, do you think that it worth to discuss this proposal as a PEP?

So far major arguments against were:

  • (a) it’s a fairly large and involved change in comparison to the size of the problem it’s solving
  • (b) adoption of the C99 imaginary types has been disappointing

I think that above implementation is more or less complete to estimate (a): so far most changes limited to arithmetic methods. (b) - this looks to be a strong one. On another hand, this feature of the C99+ standards is optional - that might be an explanation of partial adoption, while in the Python - complex arithmetic is a part of the language. For numeric C libraries, the GSL, for example, has own routines to do mixed-mode arithmetic...

serhiy-storchaka

serhiy-storchaka commented on May 27, 2024

@serhiy-storchaka
Member

Currently the signature of complex is:

complex(real=0, imag=0)

Both real and imag are positional-or-keyword parameters. This allows absurd calls like complex(real="1j").

I think that it should support several more limited signatures:

  • complex(number=0, /)
  • complex(string, /)
  • complex(real=0, imag=0)

A string and complex number arguments should only be passed as a positional argument. real and imag should only be real numbers.

skirpichev

skirpichev commented on May 27, 2024

@skirpichev
ContributorAuthor

@serhiy-storchaka, yes I think this could solve the current issue like proposed in it's description. (I.e. we should remove all mentions of broken identities.)

At price of breaking compatibility. It seems, support for imaginary arguments exists since v2.2 (6d6c1a3). Not sure on what ground it was added, I doubt it's practically used.

This allows absurd calls like complex(real="1j").

... on another hand it might be viewed as a bug.

Shall I open a separate issue or it would be better to discuss this first on d.p.o?

mdickinson

mdickinson commented on May 27, 2024

@mdickinson
Member

I think that it should support several more limited signatures:

+1. I'd particularly like to see the form complex(1 + 1j, 3 - 4j) deprecated, and eventually dropped.

added 2 commits that reference this issue on May 27, 2024

32 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    docsDocumentation in the Doc dir

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @mdickinson@skirpichev@serhiy-storchaka@AA-Turner

        Issue actions

          Invalid "equivalents" of the complex type constructor in docs · Issue #109218 · python/cpython