-
-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
Invalid "equivalents" of the complex type constructor in docs #109218
Comments
|
See also https://discuss.python.org/t/33433/ A |
|
Note that the two arguments to |
Indeed, but in this form the "equivalency" >>> 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
1jUnder the hood, instead, we have: >>> complex(r.real - i.imag, i.real + r.imag)
(-0+1j)
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 |
…hmetic
"Generally, mixed-mode arithmetic combining real and complex variables should
be performed directly, not by first coercing the real to complex, lest the sign
of zero be rendered uninformative; the same goes for combinations of pure
imaginary quantities with complex variables." (c) Kahan, W: Branch cuts for
complex elementary functions.
That's why C standards since C99 introduce imaginary types. This patch
proposes similar extension to the Python language:
* Added a new subtype (imaginary) of the complex type. New type
has few overloaded methods (conjugate() and __getnewargs__()).
* Complex and imaginary types implement IEC 60559-compatible complex
arithmetic (as specified by C11 Annex G).
* Imaginary literals now produce instances of imaginary type.
* cmath.infj/nanj were changed to be of imaginary type.
* Modules ast, code, copy, marshal got support for imaginary type.
* Few tests adapted to use complex, instead of imaginary literals
- Lib/test/test_fractions.py
- Lib/test/test_socket.py
- Lib/test/test_str.py
Lets consider some (actually interrelated) problems, shown for unpatched code,
which could be solved on this way.
1) First, new code allows to use complex arithmetic for implementation of
mathematical functions without special "corner cases". Take the inverse
hyperbolic sine as an example:
>>> z = complex(-0.0, 2)
>>> cmath.asinh(z)
(-1.3169578969248166+1.5707963267948966j)
>>> # naive textbook formula doesn't work:
>>> cmath.log(z + cmath.sqrt(1 + z*z))
(1.3169578969248166+1.5707963267948966j)
>>> # "fixed" version does:
>>> cmath.log(z + cmath.sqrt(complex(1 + (z*z).real, (z*z).imag)))
(-1.3169578969248164+1.5707963267948966j)
2) Previously, we have only unsigned imaginary literals with the following
semantics:
±a±bj = complex(±float(a), 0.0) ± complex(0.0, float(b))
While this behaviour was well documented, most users would expect
instead here:
±a±bj = complex(±float(a), ±float(b))
i.e. that it follows to the rectangular notation for complex numbers.
Things are worse, because the CPython docs sometimes asserts that the
rectangular form is used and that some simple invariants holds. For
example, sphinx docs for the complex class says: "complex(real=0,
imag=0) ... Return a complex number with the value real + imag*1j ...".
But:
>>> complex(0.0, cmath.inf)
infj
>>> 0.0 + cmath.inf*1j
(nan+infj)
3) The ``eval(repr(x)) == x`` invariant was broken for the complex type. Below
are simple examples with signed zero:
>>> complex(-0.0, 1.0) # also note funny signed integer zero below
(-0+1j)
>>> -0+1j
1j
>> -(0.0-1j) # "correct" input for above with Python numeric literals
(-0+1j)
>>> -(0-1j) # also "correct"; integer 0 matters!
(-0+1j)
>>> complex(1.0, -0.0)
(1-0j)
>>> 1-0j
(1+0j)
>>> -(-1 + 0j)
(1-0j)
Similar is true for complex numbers with other special components:
>>> complex(0.0, -cmath.inf)
-infj
>>> -cmath.infj
(-0-infj)
…hmetic
"Generally, mixed-mode arithmetic combining real and complex variables should
be performed directly, not by first coercing the real to complex, lest the sign
of zero be rendered uninformative; the same goes for combinations of pure
imaginary quantities with complex variables." (c) Kahan, W: Branch cuts for
complex elementary functions.
That's why C standards since C99 introduce imaginary types. This patch
proposes similar extension to the Python language:
* Added a new subtype (imaginary) of the complex type. New type
has few overloaded methods (conjugate() and __getnewargs__()).
* Complex and imaginary types implement IEC 60559-compatible complex
arithmetic (as specified by C11 Annex G).
* Imaginary literals now produce instances of imaginary type.
* cmath.infj/nanj were changed to be of imaginary type.
* Modules ast, code, copy, marshal got support for imaginary type.
* Few tests adapted to use complex, instead of imaginary literals
- Lib/test/test_fractions.py
- Lib/test/test_socket.py
- Lib/test/test_str.py
Lets consider some (actually interrelated) problems, shown for unpatched code,
which could be solved on this way.
1) First, new code allows to use complex arithmetic for implementation of
mathematical functions without special "corner cases". Take the inverse
hyperbolic sine as an example:
>>> z = complex(-0.0, 2)
>>> cmath.asinh(z)
(-1.3169578969248166+1.5707963267948966j)
>>> # naive textbook formula doesn't work:
>>> cmath.log(z + cmath.sqrt(1 + z*z))
(1.3169578969248166+1.5707963267948966j)
>>> # "fixed" version does:
>>> cmath.log(z + cmath.sqrt(complex(1 + (z*z).real, (z*z).imag)))
(-1.3169578969248164+1.5707963267948966j)
2) Previously, we have only unsigned imaginary literals with the following
semantics:
±a±bj = complex(±float(a), 0.0) ± complex(0.0, float(b))
While this behaviour was well documented, most users would expect
instead here:
±a±bj = complex(±float(a), ±float(b))
i.e. that it follows to the rectangular notation for complex numbers.
Things are worse, because the CPython docs sometimes asserts that the
rectangular form is used and that some simple invariants holds. For
example, sphinx docs for the complex class says: "complex(real=0,
imag=0) ... Return a complex number with the value real + imag*1j ...".
But:
>>> complex(0.0, cmath.inf)
infj
>>> 0.0 + cmath.inf*1j
(nan+infj)
3) The ``eval(repr(x)) == x`` invariant was broken for the complex type. Below
are simple examples with signed zero:
>>> complex(-0.0, 1.0) # also note funny signed integer zero below
(-0+1j)
>>> -0+1j
1j
>> -(0.0-1j) # "correct" input for above with Python numeric literals
(-0+1j)
>>> -(0-1j) # also "correct"; integer 0 matters!
(-0+1j)
>>> complex(1.0, -0.0)
(1-0j)
>>> 1-0j
(1+0j)
>>> -(-1 + 0j)
(1-0j)
Similar is true for complex numbers with other special components:
>>> complex(0.0, -cmath.inf)
-infj
>>> -cmath.infj
(-0-infj)
…hmetic
"Generally, mixed-mode arithmetic combining real and complex variables should
be performed directly, not by first coercing the real to complex, lest the sign
of zero be rendered uninformative; the same goes for combinations of pure
imaginary quantities with complex variables." (c) Kahan, W: Branch cuts for
complex elementary functions.
That's why C standards since C99 introduce imaginary types. This patch
proposes similar extension to the Python language:
* Added a new subtype (imaginary) of the complex type. New type
has few overloaded methods (conjugate() and __getnewargs__()).
* Complex and imaginary types implement IEC 60559-compatible complex
arithmetic (as specified by C11 Annex G).
* Imaginary literals now produce instances of imaginary type.
* cmath.infj/nanj were changed to be of imaginary type.
* Modules ast, code, copy, marshal got support for imaginary type.
* Few tests adapted to use complex, instead of imaginary literals
- Lib/test/test_fractions.py
- Lib/test/test_socket.py
- Lib/test/test_str.py
Lets consider some (actually interrelated) problems, shown for unpatched code,
which could be solved on this way.
1) First, new code allows to use complex arithmetic for implementation of
mathematical functions without special "corner cases". Take the inverse
hyperbolic sine as an example:
>>> z = complex(-0.0, 2)
>>> cmath.asinh(z)
(-1.3169578969248166+1.5707963267948966j)
>>> # naive textbook formula doesn't work:
>>> cmath.log(z + cmath.sqrt(1 + z*z))
(1.3169578969248166+1.5707963267948966j)
>>> # "fixed" version does:
>>> cmath.log(z + cmath.sqrt(complex(1 + (z*z).real, (z*z).imag)))
(-1.3169578969248164+1.5707963267948966j)
2) Previously, we have only unsigned imaginary literals with the following
semantics:
±a±bj = complex(±float(a), 0.0) ± complex(0.0, float(b))
While this behaviour was well documented, most users would expect
instead here:
±a±bj = complex(±float(a), ±float(b))
i.e. that it follows to the rectangular notation for complex numbers.
Things are worse, because the CPython docs sometimes asserts that the
rectangular form is used and that some simple invariants holds. For
example, sphinx docs for the complex class says: "complex(real=0,
imag=0) ... Return a complex number with the value real + imag*1j ...".
But:
>>> complex(0.0, cmath.inf)
infj
>>> 0.0 + cmath.inf*1j
(nan+infj)
3) The ``eval(repr(x)) == x`` invariant was broken for the complex type. Below
are simple examples with signed zero:
>>> complex(-0.0, 1.0) # also note funny signed integer zero below
(-0+1j)
>>> -0+1j
1j
>> -(0.0-1j) # "correct" input for above with Python numeric literals
(-0+1j)
>>> -(0-1j) # also "correct"; integer 0 matters!
(-0+1j)
>>> complex(1.0, -0.0)
(1-0j)
>>> 1-0j
(1+0j)
>>> -(-1 + 0j)
(1-0j)
Similar is true for complex numbers with other special components:
>>> complex(0.0, -cmath.inf)
-infj
>>> -cmath.infj
(-0-infj)
|
@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. So far major arguments against were:
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... |
|
Currently the signature of complex is: Both I think that it should support several more limited signatures:
A string and complex number arguments should only be passed as a positional argument. |
|
@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.
... 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? |
+1. I'd particularly like to see the form |
* Passing a string as the "real" keyword argument is now an error; it should only be passed as a single positional argument. * Passing a complex number as the *real* or *imag* argument is now deprecated; it should only be passed as a single positional argument.
* Passing a string as the "real" keyword argument is now an error; it should only be passed as a single positional argument. * Passing a complex number as the *real* or *imag* argument is now deprecated; it should only be passed as a single positional argument.
|
I think this is the right issue, and no need to open another issue. My plan:
#119620 implements the last two items. |
* Passing a string as the "real" keyword argument is now an error; it should only be passed as a single positional argument. * Passing a complex number as the *real* or *imag* argument is now deprecated; it should only be passed as a single positional argument.
* Share common classes. * Use exactly representable floats and exact tests. * Check the sign of zero components. * Remove duplicated tests (mostly left after merging int and long). * Reorder tests in more consistent way. * Test more error messages. * Add tests for missed cases.
|
And #119687 is the documentation part. It adds more details and avoids using the |
* Share common classes. * Use exactly representable floats and exact tests. * Check the sign of zero components. * Remove duplicated tests (mostly left after merging int and long). * Reorder tests in more consistent way. * Test more error messages. * Add tests for missed cases.
…GH-119635) * Share common classes. * Use exactly representable floats and exact tests. * Check the sign of zero components. * Remove duplicated tests (mostly left after merging int and long). * Reorder tests in more consistent way. * Test more error messages. * Add tests for missed cases. (cherry picked from commit bf098d4) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
…GH-119635) * Share common classes. * Use exactly representable floats and exact tests. * Check the sign of zero components. * Remove duplicated tests (mostly left after merging int and long). * Reorder tests in more consistent way. * Test more error messages. * Add tests for missed cases. (cherry picked from commit bf098d4) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
…9635) (GH-119796) * Share common classes. * Use exactly representable floats and exact tests. * Check the sign of zero components. * Remove duplicated tests (mostly left after merging int and long). * Reorder tests in more consistent way. * Test more error messages. * Add tests for missed cases. (cherry picked from commit bf098d4) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
…9687) * Remove the equivalence with real+imag*1j which can be incorrect in corner cases (non-finite numbers, the sign of zeroes). * Separately document the three roles of the constructor: parsing a string, converting a number, and constructing a complex from components. * Document positional-only parameters of complex(), float(), int() and bool() as positional-only. * Add examples for complex() and int(). * Specify the grammar of the string for complex(). * Improve the grammar of the string for float(). * Describe more explicitly the behavior when real and/or imag arguments are complex numbers. (This will be deprecated in future.)
…ythonGH-119687) * Remove the equivalence with real+imag*1j which can be incorrect in corner cases (non-finite numbers, the sign of zeroes). * Separately document the three roles of the constructor: parsing a string, converting a number, and constructing a complex from components. * Document positional-only parameters of complex(), float(), int() and bool() as positional-only. * Add examples for complex() and int(). * Specify the grammar of the string for complex(). * Improve the grammar of the string for float(). * Describe more explicitly the behavior when real and/or imag arguments are complex numbers. (This will be deprecated in future.) (cherry picked from commit ec1ba26) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
…ructor (pythonGH-119687) * Remove the equivalence with real+imag*1j which can be incorrect in corner cases (non-finite numbers, the sign of zeroes). * Separately document the three roles of the constructor: parsing a string, converting a number, and constructing a complex from components. * Document positional-only parameters of complex(), float(), int() and bool() as positional-only. * Add examples for complex() and int(). * Specify the grammar of the string for complex(). * Improve the grammar of the string for float(). * Describe more explicitly the behavior when real and/or imag arguments are complex numbers. (This will be deprecated in future.) (cherry picked from commit ec1ba26) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
|
Thank you for your reviews @skirpichev and @mdickinson. |
…GH-119687) (GH-119803) * Remove the equivalence with real+imag*1j which can be incorrect in corner cases (non-finite numbers, the sign of zeroes). * Separately document the three roles of the constructor: parsing a string, converting a number, and constructing a complex from components. * Document positional-only parameters of complex(), float(), int() and bool() as positional-only. * Add examples for complex() and int(). * Specify the grammar of the string for complex(). * Improve the grammar of the string for float(). * Describe more explicitly the behavior when real and/or imag arguments are complex numbers. (This will be deprecated in future.) (cherry picked from commit ec1ba26) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
…GH-119687) (ПР-119805) * Remove the equivalence with real+imag*1j which can be incorrect in corner cases (non-finite numbers, the sign of zeroes). * Separately document the three roles of the constructor: parsing a string, converting a number, and constructing a complex from components. * Document positional-only parameters of complex(), float(), int() and bool() as positional-only. * Add examples for complex() and int(). * Specify the grammar of the string for complex(). * Improve the grammar of the string for float(). * Describe more explicitly the behavior when real and/or imag arguments are complex numbers. (This will be deprecated in future.) (cherry picked from commit ec1ba26)
…GH-119635) * Share common classes. * Use exactly representable floats and exact tests. * Check the sign of zero components. * Remove duplicated tests (mostly left after merging int and long). * Reorder tests in more consistent way. * Test more error messages. * Add tests for missed cases.
…ythonGH-119687) * Remove the equivalence with real+imag*1j which can be incorrect in corner cases (non-finite numbers, the sign of zeroes). * Separately document the three roles of the constructor: parsing a string, converting a number, and constructing a complex from components. * Document positional-only parameters of complex(), float(), int() and bool() as positional-only. * Add examples for complex() and int(). * Specify the grammar of the string for complex(). * Improve the grammar of the string for float(). * Describe more explicitly the behavior when real and/or imag arguments are complex numbers. (This will be deprecated in future.)
…ythonGH-119620) * Passing a string as the "real" keyword argument is now an error; it should only be passed as a single positional argument. * Passing a complex number as the "real" or "imag" argument is now deprecated; it should only be passed as a single positional argument.
…GH-119635) * Share common classes. * Use exactly representable floats and exact tests. * Check the sign of zero components. * Remove duplicated tests (mostly left after merging int and long). * Reorder tests in more consistent way. * Test more error messages. * Add tests for missed cases.
…ythonGH-119687) * Remove the equivalence with real+imag*1j which can be incorrect in corner cases (non-finite numbers, the sign of zeroes). * Separately document the three roles of the constructor: parsing a string, converting a number, and constructing a complex from components. * Document positional-only parameters of complex(), float(), int() and bool() as positional-only. * Add examples for complex() and int(). * Specify the grammar of the string for complex(). * Improve the grammar of the string for float(). * Describe more explicitly the behavior when real and/or imag arguments are complex numbers. (This will be deprecated in future.)
…ythonGH-119620) * Passing a string as the "real" keyword argument is now an error; it should only be passed as a single positional argument. * Passing a complex number as the "real" or "imag" argument is now deprecated; it should only be passed as a single positional argument.
…9635) (GH-119795) * Share common classes. * Use exactly representable floats and exact tests. * Check the sign of zero components. * Remove duplicated tests (mostly left after merging int and long). * Reorder tests in more consistent way. * Test more error messages. * Add tests for missed cases. (cherry picked from commit bf098d4) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>


Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.

The sphinx docs says:
The docstring (btw it doesn't mention a string as an argument):
That wrong, e.g.:
Here is an attempt (patch) to solve, let me know if this is worth a PR:
Edit:
Another instance of this issue is in the cmath docs:
E.g.:
Linked PRs
The text was updated successfully, but these errors were encountered: