Skip to content
Open
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
fa9c087
Initial version
skirpichev Dec 5, 2023
fea0b1d
Reserve number 812
skirpichev Oct 29, 2025
5665f85
+ format refs
skirpichev Oct 31, 2025
983e5da
+ set Sponsor & .github/CODEOWNERS
skirpichev Oct 31, 2025
d7d6f0e
cleanup: use extlinks
skirpichev Nov 1, 2025
ad7d448
+ imaginary literals and marshal
skirpichev Nov 1, 2025
369a213
+ NO latex
skirpichev Nov 1, 2025
f4c9c9c
link to Kahan paper
skirpichev Nov 1, 2025
a5bb13a
ad7d448f +1
skirpichev Nov 1, 2025
bc825bf
+ mention mpmath issue 473
skirpichev Nov 1, 2025
63140c2
Merge branch 'master' into imaginary
skirpichev Nov 2, 2025
f69e6c5
Merge branch 'master' into imaginary
skirpichev Nov 4, 2025
27a429f
Merge branch 'master' into imaginary
skirpichev Nov 5, 2025
29fef03
Apply suggestions from code review
skirpichev Nov 5, 2025
0df61c9
Merge branch 'imaginary' of github.com:skirpichev/peps into imaginary
skirpichev Nov 5, 2025
612f2af
address review: apply rest of suggestions
skirpichev Nov 5, 2025
a31d7c1
+ add another algorithm for multiplication
skirpichev Nov 6, 2025
e961ef7
fix formatting
skirpichev Nov 6, 2025
5f35d52
Update peps/pep-0812.rst
skirpichev Nov 7, 2025
b573c82
Merge branch 'main' into imaginary
skirpichev Nov 16, 2025
bf0d67f
address review: move inline footnotes 5-7
skirpichev Nov 16, 2025
27b45b9
+ expose imaginary builtin
skirpichev Nov 20, 2025
8fe6c41
+ ast
skirpichev Nov 20, 2025
e8c8803
separate section for arithmetic
skirpichev Nov 21, 2025
7353470
+ specify more properties for * and /
skirpichev Nov 21, 2025
8e12d53
footnote on complex infinity
skirpichev Nov 21, 2025
036d49c
Merge branch 'main' into imaginary
skirpichev Dec 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
+ NO latex
  • Loading branch information
skirpichev committed Nov 1, 2025
commit 369a213354e15a8aae32d14dda65f05792c949a3
87 changes: 41 additions & 46 deletions peps/pep-0812.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,61 +38,56 @@ Python) in such system is a complex number with zero real component.

Unfortunately, this doesn't work well, if components of the complex number are
floating-point numbers, used as model of the *extended* real line. Such as
ones, specified by the IEC 60559 standard, which beyond normal
(finite and nonzero) numbers has special values like signed zero, infinities
and nans. Lets take simple examples with multiplication (where
:math:`\rightarrow` denotes type coersion and :math:`\Rightarrow` is
substitution of :math:`0.0+i` for :math:`i`):
ones, specified by the IEC 60559 standard, which beyond normal (finite and
nonzero) numbers has special values like signed zero, infinities and nans.
Lets take simple examples with multiplication in Python-like pseudocode (where
``~>`` denotes type coersion and ``~=`` is substitution of ``complex(0, y)``
for ``yj``):

.. math::
:label: ex-mul1
.. code:: python

2.0 * (inf+3j) ~> complex(2, 0) * complex(inf, 3)
== complex(2.0*inf - 0.0*3.0, 2.0*3.0 + 0.0*inf)
== complex(inf, nan)

2.0 \times (\infty + 3.0 i) & \rightarrow (2.0 + 0.0 i) \times (\infty + 3.0 i) \\
& = (2.0\times\infty - 0.0\times 3.0) + i(0.0\times\infty + 2.0\times 3.0) \\
& = \infty + i\mathrm{nan}
.. code:: python

.. math::
:label: ex-mul2
2j * (inf+3j) ~= complex(0, 2) * complex(inf, 3)
== complex(0.0*inf - 2.0*3.0, 2.0*inf + 0.0*3.0)
== complex(nan, inf)

2.0 i \times (\infty + 3.0 i) & \Rightarrow (0.0 + 2.0 i) \times (\infty + 3.0 i) \\
& = (0.0\times\infty - 2.0\times 3.0) + i (0.0\times 3.0 + 2.0\times\infty) \\
& = \mathrm{nan} + i\infty
.. code:: python

.. math::
:label: ex-mul3
2j * complex(-0.0, 3) ~= complex(0, 2) * complex(-0.0, 3)
== complex(-0.0*0.0 - 2.0*3.0, -2.0*0.0 + 0.0*3.0)
== complex(-6.0, 0.0)

2.0 i \times (-0.0 + 3.0 i) & \Rightarrow (0.0 + 2.0 i) \times (-0.0 + 3.0 i) \\
& = (-0.0\times 0.0 - 2.0\times 3.0) + i (-2.0\times 0.0 + 0.0\times 3.0) \\
& = -6.0 + i 0.0

Users with some mathematical background instead would expect, that ``x+yj``
notation in the Python is just usual rectangular form for a complex number
with components ``x`` (real) and ``y`` (imaginary) and that above examples
will work, following rules of elementary algebra (with assumption that
:math:`i` is a symbol such that :math:`i^2=-1`):
notation in the Python is equal to ``complex(x, y)`` and is just the usual
rectangular form for a complex number with components ``x`` (real) and ``y``
(imaginary) and that above examples will work, following rules of elementary
algebra (with assumption that ``1j**2`` is ``-1``):

.. math::
.. code:: python

2.0 \times (\infty + 3.0 i) & = 2.0\times\infty + i 2.0\times 3.0 = \infty + i 6.0 \\
2.0 i \times (\infty + 3.0 i) & = -2.0\times 3.0 + i 2.0\times\infty = -6.0 + i\infty \\
2.0 i \times (-0.0 + 3.0 i) & = -2.0\times 3.0 - i 2.0\times 0.0 = -6.0 - i 0.0 \\
2.0 * (inf+3j) == complex(2.0*inf, 2.0*3.0) == complex(inf, 6)
2j * (inf+3j) == complex(-2.0*3.0, 2.0*inf) == complex(-6, inf)
2j * complex(-0.0, 3) == complex(-2.0*3.0, -2.0*0.0) == complex(-6, -0.0)


Same affects addition (or subtraction):

.. math::
:label: ex-add1
.. code:: python

2.0 - 0j ~= 2.0 - complex(0, 0) ~> complex(2.0, 0) - complex(0, 0)
== complex(2.0 - 0.0, 0.0 - 0.0) == complex(2, 0)

2.0 - 0.0 i & \rightarrow (2.0 + 0.0 i) - 0.0 i \\
& \Rightarrow (2.0 + 0.0 i) - (0.0 + 0.0 i) \\
& = 2.0 + 0.0 i
.. code:: python

.. math::
:label: ex-add2
-0.0 + 2j ~= -0.0 + complex(0, 2) ~> complex(-0.0, 0) + complex(0, 2)
== complex(-0.0 + 0.0, 0.0 + 2.0) == complex(0, 2)

-0.0 + 2.0 i & \rightarrow (-0.0 + 0.0 i) + 2.0 i \\
& \Rightarrow (-0.0 + 0.0 i) + (0.0 + 2.0 i) \\
& = 0.0 + 2.0 i

Simplistic approach for complex arithmetic is underlying reason for numerous
and reccuring issues in the CPython bugtracker (here is an incomplete list:
Expand Down Expand Up @@ -136,10 +131,10 @@ it's less useful to end users.

A more modern approach [2]_, reflecting advances in the IEC standard for real
floating-point arithmetic, instead avoid coersion of reals to complexes
(:math:`\rightarrow`) and use a separate data type (imaginary) to represent
the imaginary unit, *ignoring it's real component in arithmetic* (i.e. no
implicit cast (:math:`\Rightarrow`) to a complex number with zero real part).
The ``cmath.asin()`` would be implemented with this approach simply by:
(``~>``) and use a separate data type (imaginary) to represent the imaginary
unit, *ignoring it's real component in arithmetic* (i.e. no implicit cast
(``~=``) to a complex number with zero real part). The ``cmath.asin()`` would
be implemented with this approach simply by:

.. code:: python

Expand All @@ -158,8 +153,8 @@ Though it's more important, that in the IEC floating-point arithmetic results
here are uniquely determined by usual mathematical formulae.

For a first step, :cpython-pr:`124829` added in the CPython 3.14 mixed-mode
rules for complex arithmetic, combining real and complex operands. So,
examples like :eq:`ex-mul1` or :eq:`ex-add1` now are working correctly:
rules for complex arithmetic, combining real and complex operands. So, some
examples from above now are working correctly:

.. code:: pycon

Expand All @@ -170,8 +165,8 @@ examples like :eq:`ex-mul1` or :eq:`ex-add1` now are working correctly:
(2-0j)


Unfortunately, this is only a half-way solution. To fix the rest of above
examples we need a separate type for pure-imaginary complex numbers.
Unfortunately, this is only a half-way solution. To fix the rest of examples
we need a separate type for pure-imaginary complex numbers.


Rationale
Expand Down