diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a4254d43e5a..0062df25475 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -669,6 +669,7 @@ peps/pep-0788.rst @ZeroIntensity @vstinner # ... peps/pep-0789.rst @njsmith peps/pep-0790.rst @hugovk +peps/pep-0791.rst @vstinner # ... peps/pep-0801.rst @warsaw # ... diff --git a/peps/pep-0791.rst b/peps/pep-0791.rst new file mode 100644 index 00000000000..ce663dba9e5 --- /dev/null +++ b/peps/pep-0791.rst @@ -0,0 +1,183 @@ +PEP: 791 +Title: imath --- module for integer-specific mathematics functions +Author: Sergey B Kirpichev +Sponsor: Victor Stinner +Discussions-To: Pending +Status: Draft +Type: Standards Track +Created: 12-May-2025 +Python-Version: 3.15 +Post-History: `12-Jul-2018 `__, + 02-Jun-2019, + `09-May-2025 `__, + + +Abstract +======== + +This PEP proposes a new module for number-theoretical, combinatorial and other +functions defined for integer arguments, like +:external+py3.14:func:`math.gcd` or :external+py3.14:func:`math.isqrt`. + + +Motivation +========== + +The :external+py3.14:mod:`math` documentation says: "This module provides access +to the mathematical functions defined by the C standard." But, +over time the module was populated with functions that aren't related to +the C standard or floating-point arithmetics. Now it's much harder to describe +module scope, content and interfaces (returned values or accepted arguments). + +For example, the :external+py3.14:mod:`math` module documentation says: "Except +when explicitly noted otherwise, all return values are floats." This is no +longer true: *None* of the functions listed in the `Number-theoretic +functions `_ +subsection of the documentation return a float, but the +documentation doesn't say so. In the documentation for the proposed ``imath`` module the sentence "All +return values are integers." would be accurate. In a similar way we +can simplify the description of the accepted arguments for functions in both the +:external+py3.14:mod:`math` and the new module. + +Apparently, the :external+py3.14:mod:`math` module can't serve as a catch-all place +for mathematical functions since we also have the :external+py3.14:mod:`cmath` and +:external+py3.14:mod:`statistics` modules. Let's do the same for integer-related +functions. It provides shared context, which reduces verbosity in the +documentation and conceptual load. It also aids discoverability through +grouping related functions and makes IDE suggestions more helpful. + +Currently the :external+py3.14:mod:`math` module code in the CPython is around +4200LOC, from which the new module code is roughly 1/3 (1300LOC). This is +comparable with the :external+py3.14:mod:`cmath` (1340LOC), which is *not* a +simple wrapper to the ``libm``, as most functions in the +:external+py3.14:mod:`math` module. + + +Specification +============= + +The PEP proposes moving the following integer-related functions to a new +module, called ``imath``: + +* :external+py3.14:func:`~math.comb` +* :external+py3.14:func:`~math.factorial` +* :external+py3.14:func:`~math.gcd` +* :external+py3.14:func:`~math.isqrt` +* :external+py3.14:func:`~math.lcm` +* :external+py3.14:func:`~math.perm` + +Their aliases in :external+py3.14:mod:`math` will be :term:`soft deprecated`. + +Module functions will accept integers and objects that implement the +:external+py3.14:meth:`~object.__index__` method, which is used to convert the +object to an integer number. Suitable functions must be computed exactly, +given sufficient time and memory. + +Possible extensions for the new module and its scope are discussed in the +`Open Issues `_ section. New functions are not part of this +proposal. + + +Backwards Compatibility +======================= + +As aliases in :external+py3.14:mod:`math` will be kept for an indefinite time +(their use would be discouraged), there are no anticipated code breaks. + + +How to Teach This +================= + +The new module will be a place for functions, that 1) accept +:external+py3.14:class:`int`-like arguments and also return integers, and 2) are +also in the field of arbitrary-precision integer arithmetic, i.e. have no +dependency on the platform floating-point format or behaviour and/or on the +platform math library (``libm``). + +For users it would be natural first to look on the +:external+py3.14:class:`int`'s methods, which cover most basic use-cases (e.g. +:external+py3.14:meth:`int.bit_length` method), than to some dedicated place in +the stdlib. + + +Reference Implementation +======================== + +`python/cpython#133909 `_ + + +Open Issues +=========== + +Module name +----------- + +The chosen name seems consistent with one existing domain-specific mathematical module: +:external+py3.14:mod:`cmath` (for complex numbers). + +We note the `Imath +`_ C++ library includes +Python bindings with the same name. There is also an :pypi:`imath` project on +PyPI, but only with two releases, with the most recent one four years ago. Its +repository is no longer accessible. + +`Polling showed `_ ``intmath`` as another +popular name. The argument made was that the normal mathematical spelling of +the imaginary unit is ``i``, which makes ``imath`` ambiguous. It also has no conflict +with any PyPI module. On the other hand, ``intmath`` may be confused with +interval math or numerical integration. + +Other proposed names include ``ntheory`` (like SymPy's submodule), +``integermath`` and ``imaths``. + + +Module scope and possible extensions +------------------------------------ + +Unless we can just provide bindings to some well supported mathematical library +like the GMP, the module scope should be limited. For example, no primality +testing and factorization, as production-quality implementatons will require a +decent mathematical background from contributors and belongs rather to +specialized libraries. + +Some possible additions, among those proposed in the initial discussion thread +(see also issue +`python/cpython#81313 `_): + +* ``ceil_div()`` --- for integer ceiling divide, see + `relevant discussion thread `_. +* ``gcdext()`` --- to solve linear `Diophantine equation `_ in two variables (the + :external+py3.14:class:`int` implementation actually includes an extended + Euclidean algorithm) +* ``isqrt_rem()`` --- to return both an integer square root and a remainder (which is non-zero only if + the integer isn't a perfect square) +* ``ilog()`` --- integer logarithm, :external+py3.14:func:`math.log` + has special handling for integer arguments. It's unique (with respect to other module + functions) and not documented so far, see issue + `python/cpython#120950 `_. +* ``fibonacci()`` --- `Fibonacci sequence `_. + + +Rejected ideas +============== + +There was a brief discussion about exposing :external+py3.14:func:`math.isqrt` +as ``imath.sqrt`` in the same way that :external+py3.14:func:`cmath.sqrt` is +the complex version of :external+py3.14:func:`math.sqrt`. However, ``isqrt`` +is ultimately a different function: it is the floor of the square root. It +would be confusing to give it the same name (under a different module). + + +Acknowledgements +================ + +Thanks to Tim Peters for reviving the idea of splitting the :external+py3.14:mod:`math` +module. Thanks to Neil Girdhar for substantial improvements of +the initial draft. + + +Copyright +========= + +This document is placed in the public domain or under the +CC0-1.0-Universal license, whichever is more permissive.