gh-81313: Add the math.integer module (PEP-791) (GH-133909)

This commit is contained in:
Serhiy Storchaka
2025-10-31 16:13:43 +02:00
committed by GitHub
parent 680a5d070f
commit dcf3cc5796
22 changed files with 2091 additions and 1748 deletions

View File

@@ -0,0 +1,85 @@
:mod:`math.integer` --- integer-specific mathematics functions
==============================================================
.. module:: math.integer
:synopsis: Integer-specific mathematics functions.
.. versionadded:: next
--------------
This module provides access to the mathematical functions defined for integer arguments.
These functions accept integers and objects that implement the
:meth:`~object.__index__` method which is used to convert the object to an integer
number.
The following functions are provided by this module. All return values are
computed exactly and are integers.
.. function:: comb(n, k, /)
Return the number of ways to choose *k* items from *n* items without repetition
and without order.
Evaluates to ``n! / (k! * (n - k)!)`` when ``k <= n`` and evaluates
to zero when ``k > n``.
Also called the binomial coefficient because it is equivalent
to the coefficient of k-th term in polynomial expansion of
``(1 + x)ⁿ``.
Raises :exc:`ValueError` if either of the arguments are negative.
.. function:: factorial(n, /)
Return factorial of the nonnegative integer *n*.
.. function:: gcd(*integers)
Return the greatest common divisor of the specified integer arguments.
If any of the arguments is nonzero, then the returned value is the largest
positive integer that is a divisor of all arguments. If all arguments
are zero, then the returned value is ``0``. ``gcd()`` without arguments
returns ``0``.
.. function:: isqrt(n, /)
Return the integer square root of the nonnegative integer *n*. This is the
floor of the exact square root of *n*, or equivalently the greatest integer
*a* such that *a*\ ² |nbsp| ≤ |nbsp| *n*.
For some applications, it may be more convenient to have the least integer
*a* such that *n* |nbsp| ≤ |nbsp| *a*\ ², or in other words the ceiling of
the exact square root of *n*. For positive *n*, this can be computed using
``a = 1 + isqrt(n - 1)``.
.. |nbsp| unicode:: 0xA0
:trim:
.. function:: lcm(*integers)
Return the least common multiple of the specified integer arguments.
If all arguments are nonzero, then the returned value is the smallest
positive integer that is a multiple of all arguments. If any of the arguments
is zero, then the returned value is ``0``. ``lcm()`` without arguments
returns ``1``.
.. function:: perm(n, k=None, /)
Return the number of ways to choose *k* items from *n* items
without repetition and with order.
Evaluates to ``n! / (n - k)!`` when ``k <= n`` and evaluates
to zero when ``k > n``.
If *k* is not specified or is ``None``, then *k* defaults to *n*
and the function returns ``n!``.
Raises :exc:`ValueError` if either of the arguments are negative.

View File

@@ -27,15 +27,6 @@ noted otherwise, all return values are floats.
==================================================== ============================================
**Number-theoretic functions**
--------------------------------------------------------------------------------------------------
:func:`comb(n, k) <comb>` Number of ways to choose *k* items from *n* items without repetition and without order
:func:`factorial(n) <factorial>` *n* factorial
:func:`gcd(*integers) <gcd>` Greatest common divisor of the integer arguments
:func:`isqrt(n) <isqrt>` Integer square root of a nonnegative integer *n*
:func:`lcm(*integers) <lcm>` Least common multiple of the integer arguments
:func:`perm(n, k) <perm>` Number of ways to choose *k* items from *n* items without repetition and with order
**Floating point arithmetic**
--------------------------------------------------------------------------------------------------
:func:`ceil(x) <ceil>` Ceiling of *x*, the smallest integer greater than or equal to *x*
@@ -126,92 +117,6 @@ noted otherwise, all return values are floats.
==================================================== ============================================
Number-theoretic functions
--------------------------
.. function:: comb(n, k)
Return the number of ways to choose *k* items from *n* items without repetition
and without order.
Evaluates to ``n! / (k! * (n - k)!)`` when ``k <= n`` and evaluates
to zero when ``k > n``.
Also called the binomial coefficient because it is equivalent
to the coefficient of k-th term in polynomial expansion of
``(1 + x)ⁿ``.
Raises :exc:`TypeError` if either of the arguments are not integers.
Raises :exc:`ValueError` if either of the arguments are negative.
.. versionadded:: 3.8
.. function:: factorial(n)
Return factorial of the nonnegative integer *n*.
.. versionchanged:: 3.10
Floats with integral values (like ``5.0``) are no longer accepted.
.. function:: gcd(*integers)
Return the greatest common divisor of the specified integer arguments.
If any of the arguments is nonzero, then the returned value is the largest
positive integer that is a divisor of all arguments. If all arguments
are zero, then the returned value is ``0``. ``gcd()`` without arguments
returns ``0``.
.. versionadded:: 3.5
.. versionchanged:: 3.9
Added support for an arbitrary number of arguments. Formerly, only two
arguments were supported.
.. function:: isqrt(n)
Return the integer square root of the nonnegative integer *n*. This is the
floor of the exact square root of *n*, or equivalently the greatest integer
*a* such that *a*\ ² |nbsp| ≤ |nbsp| *n*.
For some applications, it may be more convenient to have the least integer
*a* such that *n* |nbsp| ≤ |nbsp| *a*\ ², or in other words the ceiling of
the exact square root of *n*. For positive *n*, this can be computed using
``a = 1 + isqrt(n - 1)``.
.. versionadded:: 3.8
.. function:: lcm(*integers)
Return the least common multiple of the specified integer arguments.
If all arguments are nonzero, then the returned value is the smallest
positive integer that is a multiple of all arguments. If any of the arguments
is zero, then the returned value is ``0``. ``lcm()`` without arguments
returns ``1``.
.. versionadded:: 3.9
.. function:: perm(n, k=None)
Return the number of ways to choose *k* items from *n* items
without repetition and with order.
Evaluates to ``n! / (n - k)!`` when ``k <= n`` and evaluates
to zero when ``k > n``.
If *k* is not specified or is ``None``, then *k* defaults to *n*
and the function returns ``n!``.
Raises :exc:`TypeError` if either of the arguments are not integers.
Raises :exc:`ValueError` if either of the arguments are negative.
.. versionadded:: 3.8
Floating point arithmetic
-------------------------
@@ -812,6 +717,75 @@ Special functions
.. versionadded:: 3.2
Number-theoretic functions
--------------------------
For backward compatibility, the :mod:`math` module provides also aliases of
the following functions from the :mod:`math.integer` module:
.. list-table::
* - .. function:: comb(n, k)
:no-typesetting:
:func:`comb(n, k) <math.integer.comb>`
- Number of ways to choose *k* items from *n* items without repetition
and without order
* - .. function:: factorial(n)
:no-typesetting:
:func:`factorial(n) <math.integer.factorial>`
- *n* factorial
* - .. function:: gcd(*integers)
:no-typesetting:
:func:`gcd(*integers) <math.integer.gcd>`
- Greatest common divisor of the integer arguments
* - .. function:: isqrt(n)
:no-typesetting:
:func:`isqrt(n) <math.integer.isqrt>`
- Integer square root of a nonnegative integer *n*
* - .. function:: lcm(*integers)
:no-typesetting:
:func:`lcm(*integers) <math.integer.lcm>`
- Least common multiple of the integer arguments
* - .. function:: perm(n, k)
:no-typesetting:
:func:`perm(n, k) <math.integer.perm>`
- Number of ways to choose *k* items from *n* items without repetition
and with order
.. versionadded:: 3.5
The :func:`gcd` function.
.. versionadded:: 3.8
The :func:`comb`, :func:`perm` and :func:`isqrt` functions.
.. versionadded:: 3.9
The :func:`lcm` function.
.. versionchanged:: 3.9
Added support for an arbitrary number of arguments in the :func:`gcd`
function.
Formerly, only two arguments were supported.
.. versionchanged:: 3.10
Floats with integral values (like ``5.0``) are no longer accepted in the
:func:`factorial` function.
.. deprecated:: next
These aliases are :term:`soft deprecated` in favor of the
:mod:`math.integer` functions.
Constants
---------
@@ -894,5 +868,5 @@ Constants
Module :mod:`cmath`
Complex number versions of many of these functions.
.. |nbsp| unicode:: 0xA0
:trim:
Module :mod:`math.integer`
Integer-specific mathematics functions.

View File

@@ -19,6 +19,7 @@ The following modules are documented in this chapter:
numbers.rst
math.rst
math.integer.rst
cmath.rst
decimal.rst
fractions.rst

View File

@@ -311,7 +311,12 @@ Other language changes
New modules
===========
* None yet.
math.integer
------------
This module provides access to the mathematical functions for integer
arguments (:pep:`791`).
(Contributed by Serhiy Storchaka in :gh:`81313`.)
Improved modules

View File

@@ -17,7 +17,8 @@ extern int _PyImport_IsInitialized(PyInterpreterState *);
// Export for 'pyexpat' shared extension
PyAPI_FUNC(int) _PyImport_SetModule(PyObject *name, PyObject *module);
extern int _PyImport_SetModuleString(const char *name, PyObject* module);
// Export for 'math' shared extension
PyAPI_FUNC(int) _PyImport_SetModuleString(const char *name, PyObject* module);
extern void _PyImport_AcquireLock(PyInterpreterState *interp);
extern void _PyImport_ReleaseLock(PyInterpreterState *interp);

View File

@@ -307,7 +307,7 @@ class CAPITest(unittest.TestCase):
CURRENT_THREAD_REGEX +
r' File .*, line 6 in <module>\n'
r'\n'
r'Extension modules: _testcapi \(total: 1\)\n')
r'Extension modules: ')
else:
# Python built with NDEBUG macro defined:
# test _Py_CheckFunctionResult() instead.

View File

@@ -55,56 +55,6 @@ def to_ulps(x):
return n
# Here's a pure Python version of the math.factorial algorithm, for
# documentation and comparison purposes.
#
# Formula:
#
# factorial(n) = factorial_odd_part(n) << (n - count_set_bits(n))
#
# where
#
# factorial_odd_part(n) = product_{i >= 0} product_{0 < j <= n >> i; j odd} j
#
# The outer product above is an infinite product, but once i >= n.bit_length,
# (n >> i) < 1 and the corresponding term of the product is empty. So only the
# finitely many terms for 0 <= i < n.bit_length() contribute anything.
#
# We iterate downwards from i == n.bit_length() - 1 to i == 0. The inner
# product in the formula above starts at 1 for i == n.bit_length(); for each i
# < n.bit_length() we get the inner product for i from that for i + 1 by
# multiplying by all j in {n >> i+1 < j <= n >> i; j odd}. In Python terms,
# this set is range((n >> i+1) + 1 | 1, (n >> i) + 1 | 1, 2).
def count_set_bits(n):
"""Number of '1' bits in binary expansion of a nonnnegative integer."""
return 1 + count_set_bits(n & n - 1) if n else 0
def partial_product(start, stop):
"""Product of integers in range(start, stop, 2), computed recursively.
start and stop should both be odd, with start <= stop.
"""
numfactors = (stop - start) >> 1
if not numfactors:
return 1
elif numfactors == 1:
return start
else:
mid = (start + numfactors) | 1
return partial_product(start, mid) * partial_product(mid, stop)
def py_factorial(n):
"""Factorial of nonnegative integer n, via "Binary Split Factorial Formula"
described at http://www.luschny.de/math/factorial/binarysplitfact.html
"""
inner = outer = 1
for i in reversed(range(n.bit_length())):
inner *= partial_product((n >> i + 1) + 1 | 1, (n >> i) + 1 | 1)
outer *= inner
return outer << (n - count_set_bits(n))
def ulp_abs_check(expected, got, ulp_tol, abs_tol):
"""Given finite floats `expected` and `got`, check that they're
approximately equal to within the given number of ulps or the
@@ -547,33 +497,6 @@ class MathTests(unittest.TestCase):
self.ftest('fabs(0)', math.fabs(0), 0)
self.ftest('fabs(1)', math.fabs(1), 1)
def testFactorial(self):
self.assertEqual(math.factorial(0), 1)
total = 1
for i in range(1, 1000):
total *= i
self.assertEqual(math.factorial(i), total)
self.assertEqual(math.factorial(i), py_factorial(i))
self.assertRaises(ValueError, math.factorial, -1)
self.assertRaises(ValueError, math.factorial, -10**100)
def testFactorialNonIntegers(self):
self.assertRaises(TypeError, math.factorial, 5.0)
self.assertRaises(TypeError, math.factorial, 5.2)
self.assertRaises(TypeError, math.factorial, -1.0)
self.assertRaises(TypeError, math.factorial, -1e100)
self.assertRaises(TypeError, math.factorial, decimal.Decimal('5'))
self.assertRaises(TypeError, math.factorial, decimal.Decimal('5.2'))
self.assertRaises(TypeError, math.factorial, "5")
# Other implementations may place different upper bounds.
@support.cpython_only
def testFactorialHugeInputs(self):
# Currently raises OverflowError for inputs that are too large
# to fit into a C long.
self.assertRaises(OverflowError, math.factorial, 10**100)
self.assertRaises(TypeError, math.factorial, 1e100)
def testFloor(self):
self.assertRaises(TypeError, math.floor)
self.assertEqual(int, type(math.floor(0.5)))
@@ -1175,68 +1098,6 @@ class MathTests(unittest.TestCase):
with self.assertRaises(ValueError):
math.dist([1, 2], [3, 4, 5])
def testIsqrt(self):
# Test a variety of inputs, large and small.
test_values = (
list(range(1000))
+ list(range(10**6 - 1000, 10**6 + 1000))
+ [2**e + i for e in range(60, 200) for i in range(-40, 40)]
+ [3**9999, 10**5001]
)
for value in test_values:
with self.subTest(value=value):
s = math.isqrt(value)
self.assertIs(type(s), int)
self.assertLessEqual(s*s, value)
self.assertLess(value, (s+1)*(s+1))
# Negative values
with self.assertRaises(ValueError):
math.isqrt(-1)
# Integer-like things
s = math.isqrt(True)
self.assertIs(type(s), int)
self.assertEqual(s, 1)
s = math.isqrt(False)
self.assertIs(type(s), int)
self.assertEqual(s, 0)
class IntegerLike(object):
def __init__(self, value):
self.value = value
def __index__(self):
return self.value
s = math.isqrt(IntegerLike(1729))
self.assertIs(type(s), int)
self.assertEqual(s, 41)
with self.assertRaises(ValueError):
math.isqrt(IntegerLike(-3))
# Non-integer-like things
bad_values = [
3.5, "a string", decimal.Decimal("3.5"), 3.5j,
100.0, -4.0,
]
for value in bad_values:
with self.subTest(value=value):
with self.assertRaises(TypeError):
math.isqrt(value)
@support.bigmemtest(2**32, memuse=0.85)
def test_isqrt_huge(self, size):
if size & 1:
size += 1
v = 1 << size
w = math.isqrt(v)
self.assertEqual(w.bit_length(), size // 2 + 1)
self.assertEqual(w.bit_count(), 1)
def test_lcm(self):
lcm = math.lcm
self.assertEqual(lcm(0, 0), 0)
@@ -2392,140 +2253,6 @@ class MathTests(unittest.TestCase):
self.assertEqual(type(prod([1, decimal.Decimal(2.0), 3, 4, 5, 6])),
decimal.Decimal)
def testPerm(self):
perm = math.perm
factorial = math.factorial
# Test if factorial definition is satisfied
for n in range(500):
for k in (range(n + 1) if n < 100 else range(30) if n < 200 else range(10)):
self.assertEqual(perm(n, k),
factorial(n) // factorial(n - k))
# Test for Pascal's identity
for n in range(1, 100):
for k in range(1, n):
self.assertEqual(perm(n, k), perm(n - 1, k - 1) * k + perm(n - 1, k))
# Test corner cases
for n in range(1, 100):
self.assertEqual(perm(n, 0), 1)
self.assertEqual(perm(n, 1), n)
self.assertEqual(perm(n, n), factorial(n))
# Test one argument form
for n in range(20):
self.assertEqual(perm(n), factorial(n))
self.assertEqual(perm(n, None), factorial(n))
# Raises TypeError if any argument is non-integer or argument count is
# not 1 or 2
self.assertRaises(TypeError, perm, 10, 1.0)
self.assertRaises(TypeError, perm, 10, decimal.Decimal(1.0))
self.assertRaises(TypeError, perm, 10, "1")
self.assertRaises(TypeError, perm, 10.0, 1)
self.assertRaises(TypeError, perm, decimal.Decimal(10.0), 1)
self.assertRaises(TypeError, perm, "10", 1)
self.assertRaises(TypeError, perm)
self.assertRaises(TypeError, perm, 10, 1, 3)
self.assertRaises(TypeError, perm)
# Raises Value error if not k or n are negative numbers
self.assertRaises(ValueError, perm, -1, 1)
self.assertRaises(ValueError, perm, -2**1000, 1)
self.assertRaises(ValueError, perm, 1, -1)
self.assertRaises(ValueError, perm, 1, -2**1000)
# Returns zero if k is greater than n
self.assertEqual(perm(1, 2), 0)
self.assertEqual(perm(1, 2**1000), 0)
n = 2**1000
self.assertEqual(perm(n, 0), 1)
self.assertEqual(perm(n, 1), n)
self.assertEqual(perm(n, 2), n * (n-1))
if support.check_impl_detail(cpython=True):
self.assertRaises(OverflowError, perm, n, n)
for n, k in (True, True), (True, False), (False, False):
self.assertEqual(perm(n, k), 1)
self.assertIs(type(perm(n, k)), int)
self.assertEqual(perm(IntSubclass(5), IntSubclass(2)), 20)
self.assertEqual(perm(MyIndexable(5), MyIndexable(2)), 20)
for k in range(3):
self.assertIs(type(perm(IntSubclass(5), IntSubclass(k))), int)
self.assertIs(type(perm(MyIndexable(5), MyIndexable(k))), int)
def testComb(self):
comb = math.comb
factorial = math.factorial
# Test if factorial definition is satisfied
for n in range(500):
for k in (range(n + 1) if n < 100 else range(30) if n < 200 else range(10)):
self.assertEqual(comb(n, k), factorial(n)
// (factorial(k) * factorial(n - k)))
# Test for Pascal's identity
for n in range(1, 100):
for k in range(1, n):
self.assertEqual(comb(n, k), comb(n - 1, k - 1) + comb(n - 1, k))
# Test corner cases
for n in range(100):
self.assertEqual(comb(n, 0), 1)
self.assertEqual(comb(n, n), 1)
for n in range(1, 100):
self.assertEqual(comb(n, 1), n)
self.assertEqual(comb(n, n - 1), n)
# Test Symmetry
for n in range(100):
for k in range(n // 2):
self.assertEqual(comb(n, k), comb(n, n - k))
# Raises TypeError if any argument is non-integer or argument count is
# not 2
self.assertRaises(TypeError, comb, 10, 1.0)
self.assertRaises(TypeError, comb, 10, decimal.Decimal(1.0))
self.assertRaises(TypeError, comb, 10, "1")
self.assertRaises(TypeError, comb, 10.0, 1)
self.assertRaises(TypeError, comb, decimal.Decimal(10.0), 1)
self.assertRaises(TypeError, comb, "10", 1)
self.assertRaises(TypeError, comb, 10)
self.assertRaises(TypeError, comb, 10, 1, 3)
self.assertRaises(TypeError, comb)
# Raises Value error if not k or n are negative numbers
self.assertRaises(ValueError, comb, -1, 1)
self.assertRaises(ValueError, comb, -2**1000, 1)
self.assertRaises(ValueError, comb, 1, -1)
self.assertRaises(ValueError, comb, 1, -2**1000)
# Returns zero if k is greater than n
self.assertEqual(comb(1, 2), 0)
self.assertEqual(comb(1, 2**1000), 0)
n = 2**1000
self.assertEqual(comb(n, 0), 1)
self.assertEqual(comb(n, 1), n)
self.assertEqual(comb(n, 2), n * (n-1) // 2)
self.assertEqual(comb(n, n), 1)
self.assertEqual(comb(n, n-1), n)
self.assertEqual(comb(n, n-2), n * (n-1) // 2)
if support.check_impl_detail(cpython=True):
self.assertRaises(OverflowError, comb, n, n//2)
for n, k in (True, True), (True, False), (False, False):
self.assertEqual(comb(n, k), 1)
self.assertIs(type(comb(n, k)), int)
self.assertEqual(comb(IntSubclass(5), IntSubclass(2)), 10)
self.assertEqual(comb(MyIndexable(5), MyIndexable(2)), 10)
for k in range(3):
self.assertIs(type(comb(IntSubclass(5), IntSubclass(k))), int)
self.assertIs(type(comb(MyIndexable(5), MyIndexable(k))), int)
@requires_IEEE_754
def test_nextafter(self):
# around 2^52 and 2^63

View File

@@ -0,0 +1,403 @@
from decimal import Decimal
from fractions import Fraction
import unittest
from test import support
class IntSubclass(int):
pass
# Class providing an __index__ method.
class MyIndexable(object):
def __init__(self, value):
self.value = value
def __index__(self):
return self.value
# Here's a pure Python version of the math.integer.factorial algorithm, for
# documentation and comparison purposes.
#
# Formula:
#
# factorial(n) = factorial_odd_part(n) << (n - count_set_bits(n))
#
# where
#
# factorial_odd_part(n) = product_{i >= 0} product_{0 < j <= n >> i; j odd} j
#
# The outer product above is an infinite product, but once i >= n.bit_length,
# (n >> i) < 1 and the corresponding term of the product is empty. So only the
# finitely many terms for 0 <= i < n.bit_length() contribute anything.
#
# We iterate downwards from i == n.bit_length() - 1 to i == 0. The inner
# product in the formula above starts at 1 for i == n.bit_length(); for each i
# < n.bit_length() we get the inner product for i from that for i + 1 by
# multiplying by all j in {n >> i+1 < j <= n >> i; j odd}. In Python terms,
# this set is range((n >> i+1) + 1 | 1, (n >> i) + 1 | 1, 2).
def count_set_bits(n):
"""Number of '1' bits in binary expansion of a nonnnegative integer."""
return 1 + count_set_bits(n & n - 1) if n else 0
def partial_product(start, stop):
"""Product of integers in range(start, stop, 2), computed recursively.
start and stop should both be odd, with start <= stop.
"""
numfactors = (stop - start) >> 1
if not numfactors:
return 1
elif numfactors == 1:
return start
else:
mid = (start + numfactors) | 1
return partial_product(start, mid) * partial_product(mid, stop)
def py_factorial(n):
"""Factorial of nonnegative integer n, via "Binary Split Factorial Formula"
described at http://www.luschny.de/math/factorial/binarysplitfact.html
"""
inner = outer = 1
for i in reversed(range(n.bit_length())):
inner *= partial_product((n >> i + 1) + 1 | 1, (n >> i) + 1 | 1)
outer *= inner
return outer << (n - count_set_bits(n))
class IntMathTests(unittest.TestCase):
import math.integer as module
def assertIntEqual(self, actual, expected):
self.assertEqual(actual, expected)
self.assertIs(type(actual), int)
def test_factorial(self):
factorial = self.module.factorial
self.assertEqual(factorial(0), 1)
total = 1
for i in range(1, 1000):
total *= i
self.assertEqual(factorial(i), total)
self.assertEqual(factorial(i), py_factorial(i))
self.assertIntEqual(factorial(False), 1)
self.assertIntEqual(factorial(True), 1)
for i in range(3):
expected = factorial(i)
self.assertIntEqual(factorial(IntSubclass(i)), expected)
self.assertIntEqual(factorial(MyIndexable(i)), expected)
self.assertRaises(ValueError, factorial, -1)
self.assertRaises(ValueError, factorial, -10**1000)
def test_factorial_non_integers(self):
factorial = self.module.factorial
self.assertRaises(TypeError, factorial, 5.0)
self.assertRaises(TypeError, factorial, 5.2)
self.assertRaises(TypeError, factorial, -1.0)
self.assertRaises(TypeError, factorial, -1e100)
self.assertRaises(TypeError, factorial, Decimal('5'))
self.assertRaises(TypeError, factorial, Decimal('5.2'))
self.assertRaises(TypeError, factorial, Fraction(5, 1))
self.assertRaises(TypeError, factorial, "5")
# Other implementations may place different upper bounds.
@support.cpython_only
def test_factorial_huge_inputs(self):
factorial = self.module.factorial
# Currently raises OverflowError for inputs that are too large
# to fit into a C long.
self.assertRaises(OverflowError, factorial, 10**100)
self.assertRaises(TypeError, factorial, 1e100)
def test_gcd(self):
gcd = self.module.gcd
self.assertEqual(gcd(0, 0), 0)
self.assertEqual(gcd(1, 0), 1)
self.assertEqual(gcd(-1, 0), 1)
self.assertEqual(gcd(0, 1), 1)
self.assertEqual(gcd(0, -1), 1)
self.assertEqual(gcd(7, 1), 1)
self.assertEqual(gcd(7, -1), 1)
self.assertEqual(gcd(-23, 15), 1)
self.assertEqual(gcd(120, 84), 12)
self.assertEqual(gcd(84, -120), 12)
self.assertEqual(gcd(1216342683557601535506311712,
436522681849110124616458784), 32)
c = 652560
x = 434610456570399902378880679233098819019853229470286994367836600566
y = 1064502245825115327754847244914921553977
a = x * c
b = y * c
self.assertEqual(gcd(a, b), c)
self.assertEqual(gcd(b, a), c)
self.assertEqual(gcd(-a, b), c)
self.assertEqual(gcd(b, -a), c)
self.assertEqual(gcd(a, -b), c)
self.assertEqual(gcd(-b, a), c)
self.assertEqual(gcd(-a, -b), c)
self.assertEqual(gcd(-b, -a), c)
c = 576559230871654959816130551884856912003141446781646602790216406874
a = x * c
b = y * c
self.assertEqual(gcd(a, b), c)
self.assertEqual(gcd(b, a), c)
self.assertEqual(gcd(-a, b), c)
self.assertEqual(gcd(b, -a), c)
self.assertEqual(gcd(a, -b), c)
self.assertEqual(gcd(-b, a), c)
self.assertEqual(gcd(-a, -b), c)
self.assertEqual(gcd(-b, -a), c)
self.assertRaises(TypeError, gcd, 120.0, 84)
self.assertRaises(TypeError, gcd, 120, 84.0)
self.assertIntEqual(gcd(IntSubclass(120), IntSubclass(84)), 12)
self.assertIntEqual(gcd(MyIndexable(120), MyIndexable(84)), 12)
def test_lcm(self):
lcm = self.module.lcm
self.assertEqual(lcm(0, 0), 0)
self.assertEqual(lcm(1, 0), 0)
self.assertEqual(lcm(-1, 0), 0)
self.assertEqual(lcm(0, 1), 0)
self.assertEqual(lcm(0, -1), 0)
self.assertEqual(lcm(7, 1), 7)
self.assertEqual(lcm(7, -1), 7)
self.assertEqual(lcm(-23, 15), 345)
self.assertEqual(lcm(120, 84), 840)
self.assertEqual(lcm(84, -120), 840)
self.assertEqual(lcm(1216342683557601535506311712,
436522681849110124616458784),
16592536571065866494401400422922201534178938447014944)
x = 43461045657039990237
y = 10645022458251153277
for c in (652560,
57655923087165495981):
a = x * c
b = y * c
d = x * y * c
self.assertEqual(lcm(a, b), d)
self.assertEqual(lcm(b, a), d)
self.assertEqual(lcm(-a, b), d)
self.assertEqual(lcm(b, -a), d)
self.assertEqual(lcm(a, -b), d)
self.assertEqual(lcm(-b, a), d)
self.assertEqual(lcm(-a, -b), d)
self.assertEqual(lcm(-b, -a), d)
self.assertEqual(lcm(), 1)
self.assertEqual(lcm(120), 120)
self.assertEqual(lcm(-120), 120)
self.assertEqual(lcm(120, 84, 102), 14280)
self.assertEqual(lcm(120, 0, 84), 0)
self.assertRaises(TypeError, lcm, 120.0)
self.assertRaises(TypeError, lcm, 120.0, 84)
self.assertRaises(TypeError, lcm, 120, 84.0)
self.assertRaises(TypeError, lcm, 120, 0, 84.0)
self.assertEqual(lcm(MyIndexable(120), MyIndexable(84)), 840)
def test_isqrt(self):
isqrt = self.module.isqrt
# Test a variety of inputs, large and small.
test_values = (
list(range(1000))
+ list(range(10**6 - 1000, 10**6 + 1000))
+ [2**e + i for e in range(60, 200) for i in range(-40, 40)]
+ [3**9999, 10**5001]
)
for value in test_values:
with self.subTest(value=value):
s = isqrt(value)
self.assertIs(type(s), int)
self.assertLessEqual(s*s, value)
self.assertLess(value, (s+1)*(s+1))
# Negative values
with self.assertRaises(ValueError):
isqrt(-1)
# Integer-like things
self.assertIntEqual(isqrt(True), 1)
self.assertIntEqual(isqrt(False), 0)
self.assertIntEqual(isqrt(MyIndexable(1729)), 41)
with self.assertRaises(ValueError):
isqrt(MyIndexable(-3))
# Non-integer-like things
bad_values = [
3.5, "a string", Decimal("3.5"), 3.5j,
100.0, -4.0,
]
for value in bad_values:
with self.subTest(value=value):
with self.assertRaises(TypeError):
isqrt(value)
@support.bigmemtest(2**32, memuse=0.85)
def test_isqrt_huge(self, size):
isqrt = self.module.isqrt
if size & 1:
size += 1
v = 1 << size
w = isqrt(v)
self.assertEqual(w.bit_length(), size // 2 + 1)
self.assertEqual(w.bit_count(), 1)
def test_perm(self):
perm = self.module.perm
factorial = self.module.factorial
# Test if factorial definition is satisfied
for n in range(500):
for k in (range(n + 1) if n < 100 else range(30) if n < 200 else range(10)):
self.assertEqual(perm(n, k),
factorial(n) // factorial(n - k))
# Test for Pascal's identity
for n in range(1, 100):
for k in range(1, n):
self.assertEqual(perm(n, k), perm(n - 1, k - 1) * k + perm(n - 1, k))
# Test corner cases
for n in range(1, 100):
self.assertEqual(perm(n, 0), 1)
self.assertEqual(perm(n, 1), n)
self.assertEqual(perm(n, n), factorial(n))
# Test one argument form
for n in range(20):
self.assertEqual(perm(n), factorial(n))
self.assertEqual(perm(n, None), factorial(n))
# Raises TypeError if any argument is non-integer or argument count is
# not 1 or 2
self.assertRaises(TypeError, perm, 10, 1.0)
self.assertRaises(TypeError, perm, 10, Decimal(1.0))
self.assertRaises(TypeError, perm, 10, Fraction(1, 1))
self.assertRaises(TypeError, perm, 10, "1")
self.assertRaises(TypeError, perm, 10.0, 1)
self.assertRaises(TypeError, perm, Decimal(10.0), 1)
self.assertRaises(TypeError, perm, Fraction(10, 1), 1)
self.assertRaises(TypeError, perm, "10", 1)
self.assertRaises(TypeError, perm)
self.assertRaises(TypeError, perm, 10, 1, 3)
self.assertRaises(TypeError, perm)
# Raises Value error if not k or n are negative numbers
self.assertRaises(ValueError, perm, -1, 1)
self.assertRaises(ValueError, perm, -2**1000, 1)
self.assertRaises(ValueError, perm, 1, -1)
self.assertRaises(ValueError, perm, 1, -2**1000)
# Returns zero if k is greater than n
self.assertEqual(perm(1, 2), 0)
self.assertEqual(perm(1, 2**1000), 0)
n = 2**1000
self.assertEqual(perm(n, 0), 1)
self.assertEqual(perm(n, 1), n)
self.assertEqual(perm(n, 2), n * (n-1))
if support.check_impl_detail(cpython=True):
self.assertRaises(OverflowError, perm, n, n)
for n, k in (True, True), (True, False), (False, False):
self.assertIntEqual(perm(n, k), 1)
self.assertEqual(perm(IntSubclass(5), IntSubclass(2)), 20)
self.assertEqual(perm(MyIndexable(5), MyIndexable(2)), 20)
for k in range(3):
self.assertIs(type(perm(IntSubclass(5), IntSubclass(k))), int)
self.assertIs(type(perm(MyIndexable(5), MyIndexable(k))), int)
def test_comb(self):
comb = self.module.comb
factorial = self.module.factorial
# Test if factorial definition is satisfied
for n in range(500):
for k in (range(n + 1) if n < 100 else range(30) if n < 200 else range(10)):
self.assertEqual(comb(n, k), factorial(n)
// (factorial(k) * factorial(n - k)))
# Test for Pascal's identity
for n in range(1, 100):
for k in range(1, n):
self.assertEqual(comb(n, k), comb(n - 1, k - 1) + comb(n - 1, k))
# Test corner cases
for n in range(100):
self.assertEqual(comb(n, 0), 1)
self.assertEqual(comb(n, n), 1)
for n in range(1, 100):
self.assertEqual(comb(n, 1), n)
self.assertEqual(comb(n, n - 1), n)
# Test Symmetry
for n in range(100):
for k in range(n // 2):
self.assertEqual(comb(n, k), comb(n, n - k))
# Raises TypeError if any argument is non-integer or argument count is
# not 2
self.assertRaises(TypeError, comb, 10, 1.0)
self.assertRaises(TypeError, comb, 10, Decimal(1.0))
self.assertRaises(TypeError, comb, 10, "1")
self.assertRaises(TypeError, comb, 10.0, 1)
self.assertRaises(TypeError, comb, Decimal(10.0), 1)
self.assertRaises(TypeError, comb, "10", 1)
self.assertRaises(TypeError, comb, 10)
self.assertRaises(TypeError, comb, 10, 1, 3)
self.assertRaises(TypeError, comb)
# Raises Value error if not k or n are negative numbers
self.assertRaises(ValueError, comb, -1, 1)
self.assertRaises(ValueError, comb, -2**1000, 1)
self.assertRaises(ValueError, comb, 1, -1)
self.assertRaises(ValueError, comb, 1, -2**1000)
# Returns zero if k is greater than n
self.assertEqual(comb(1, 2), 0)
self.assertEqual(comb(1, 2**1000), 0)
n = 2**1000
self.assertEqual(comb(n, 0), 1)
self.assertEqual(comb(n, 1), n)
self.assertEqual(comb(n, 2), n * (n-1) // 2)
self.assertEqual(comb(n, n), 1)
self.assertEqual(comb(n, n-1), n)
self.assertEqual(comb(n, n-2), n * (n-1) // 2)
if support.check_impl_detail(cpython=True):
self.assertRaises(OverflowError, comb, n, n//2)
for n, k in (True, True), (True, False), (False, False):
self.assertIntEqual(comb(n, k), 1)
self.assertEqual(comb(IntSubclass(5), IntSubclass(2)), 10)
self.assertEqual(comb(MyIndexable(5), MyIndexable(2)), 10)
for k in range(3):
self.assertIs(type(comb(IntSubclass(5), IntSubclass(k))), int)
self.assertIs(type(comb(MyIndexable(5), MyIndexable(k))), int)
class MathTests(IntMathTests):
import math as module
class MiscTests(unittest.TestCase):
def test_module_name(self):
import math.integer
self.assertEqual(math.integer.__name__, 'math.integer')
for name in dir(math.integer):
if not name.startswith('_'):
obj = getattr(math.integer, name)
self.assertEqual(obj.__module__, 'math.integer')
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1 @@
Add the :mod:`math.integer` module (:pep:`791`).

View File

@@ -156,6 +156,7 @@ PYTHONPATH=$(COREPYTHONPATH)
#binascii binascii.c
#cmath cmathmodule.c
#math mathmodule.c
#_math_integer mathintegermodule.c
#mmap mmapmodule.c
#select selectmodule.c
#_sysconfig _sysconfig.c

View File

@@ -37,6 +37,7 @@
@MODULE__HEAPQ_TRUE@_heapq _heapqmodule.c
@MODULE__JSON_TRUE@_json _json.c
@MODULE__LSPROF_TRUE@_lsprof _lsprof.c rotatingtree.c
@MODULE__MATH_INTEGER_TRUE@_math_integer mathintegermodule.c
@MODULE__PICKLE_TRUE@_pickle _pickle.c
@MODULE__QUEUE_TRUE@_queue _queuemodule.c
@MODULE__RANDOM_TRUE@_random _randommodule.c

159
Modules/clinic/mathintegermodule.c.h generated Normal file
View File

@@ -0,0 +1,159 @@
/*[clinic input]
preserve
[clinic start generated code]*/
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
PyDoc_STRVAR(math_integer_gcd__doc__,
"gcd($module, /, *integers)\n"
"--\n"
"\n"
"Greatest Common Divisor.");
#define MATH_INTEGER_GCD_METHODDEF \
{"gcd", _PyCFunction_CAST(math_integer_gcd), METH_FASTCALL, math_integer_gcd__doc__},
static PyObject *
math_integer_gcd_impl(PyObject *module, PyObject * const *args,
Py_ssize_t args_length);
static PyObject *
math_integer_gcd(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject * const *__clinic_args;
Py_ssize_t args_length;
__clinic_args = args;
args_length = nargs;
return_value = math_integer_gcd_impl(module, __clinic_args, args_length);
return return_value;
}
PyDoc_STRVAR(math_integer_lcm__doc__,
"lcm($module, /, *integers)\n"
"--\n"
"\n"
"Least Common Multiple.");
#define MATH_INTEGER_LCM_METHODDEF \
{"lcm", _PyCFunction_CAST(math_integer_lcm), METH_FASTCALL, math_integer_lcm__doc__},
static PyObject *
math_integer_lcm_impl(PyObject *module, PyObject * const *args,
Py_ssize_t args_length);
static PyObject *
math_integer_lcm(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject * const *__clinic_args;
Py_ssize_t args_length;
__clinic_args = args;
args_length = nargs;
return_value = math_integer_lcm_impl(module, __clinic_args, args_length);
return return_value;
}
PyDoc_STRVAR(math_integer_isqrt__doc__,
"isqrt($module, n, /)\n"
"--\n"
"\n"
"Return the integer part of the square root of the input.");
#define MATH_INTEGER_ISQRT_METHODDEF \
{"isqrt", (PyCFunction)math_integer_isqrt, METH_O, math_integer_isqrt__doc__},
PyDoc_STRVAR(math_integer_factorial__doc__,
"factorial($module, n, /)\n"
"--\n"
"\n"
"Find n!.");
#define MATH_INTEGER_FACTORIAL_METHODDEF \
{"factorial", (PyCFunction)math_integer_factorial, METH_O, math_integer_factorial__doc__},
PyDoc_STRVAR(math_integer_perm__doc__,
"perm($module, n, k=None, /)\n"
"--\n"
"\n"
"Number of ways to choose k items from n items without repetition and with order.\n"
"\n"
"Evaluates to n! / (n - k)! when k <= n and evaluates\n"
"to zero when k > n.\n"
"\n"
"If k is not specified or is None, then k defaults to n\n"
"and the function returns n!.\n"
"\n"
"Raises ValueError if either of the arguments are negative.");
#define MATH_INTEGER_PERM_METHODDEF \
{"perm", _PyCFunction_CAST(math_integer_perm), METH_FASTCALL, math_integer_perm__doc__},
static PyObject *
math_integer_perm_impl(PyObject *module, PyObject *n, PyObject *k);
static PyObject *
math_integer_perm(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *n;
PyObject *k = Py_None;
if (!_PyArg_CheckPositional("perm", nargs, 1, 2)) {
goto exit;
}
n = args[0];
if (nargs < 2) {
goto skip_optional;
}
k = args[1];
skip_optional:
return_value = math_integer_perm_impl(module, n, k);
exit:
return return_value;
}
PyDoc_STRVAR(math_integer_comb__doc__,
"comb($module, n, k, /)\n"
"--\n"
"\n"
"Number of ways to choose k items from n items without repetition and without order.\n"
"\n"
"Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates\n"
"to zero when k > n.\n"
"\n"
"Also called the binomial coefficient because it is equivalent\n"
"to the coefficient of k-th term in polynomial expansion of the\n"
"expression (1 + x)**n.\n"
"\n"
"Raises ValueError if either of the arguments are negative.");
#define MATH_INTEGER_COMB_METHODDEF \
{"comb", _PyCFunction_CAST(math_integer_comb), METH_FASTCALL, math_integer_comb__doc__},
static PyObject *
math_integer_comb_impl(PyObject *module, PyObject *n, PyObject *k);
static PyObject *
math_integer_comb(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *n;
PyObject *k;
if (!_PyArg_CheckPositional("comb", nargs, 2, 2)) {
goto exit;
}
n = args[0];
k = args[1];
return_value = math_integer_comb_impl(module, n, k);
exit:
return return_value;
}
/*[clinic end generated code: output=34697570c923a3af input=a9049054013a1b77]*/

View File

@@ -8,60 +8,6 @@ preserve
#endif
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
PyDoc_STRVAR(math_gcd__doc__,
"gcd($module, /, *integers)\n"
"--\n"
"\n"
"Greatest Common Divisor.");
#define MATH_GCD_METHODDEF \
{"gcd", _PyCFunction_CAST(math_gcd), METH_FASTCALL, math_gcd__doc__},
static PyObject *
math_gcd_impl(PyObject *module, PyObject * const *args,
Py_ssize_t args_length);
static PyObject *
math_gcd(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject * const *__clinic_args;
Py_ssize_t args_length;
__clinic_args = args;
args_length = nargs;
return_value = math_gcd_impl(module, __clinic_args, args_length);
return return_value;
}
PyDoc_STRVAR(math_lcm__doc__,
"lcm($module, /, *integers)\n"
"--\n"
"\n"
"Least Common Multiple.");
#define MATH_LCM_METHODDEF \
{"lcm", _PyCFunction_CAST(math_lcm), METH_FASTCALL, math_lcm__doc__},
static PyObject *
math_lcm_impl(PyObject *module, PyObject * const *args,
Py_ssize_t args_length);
static PyObject *
math_lcm(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject * const *__clinic_args;
Py_ssize_t args_length;
__clinic_args = args;
args_length = nargs;
return_value = math_lcm_impl(module, __clinic_args, args_length);
return return_value;
}
PyDoc_STRVAR(math_ceil__doc__,
"ceil($module, x, /)\n"
"--\n"
@@ -235,24 +181,6 @@ PyDoc_STRVAR(math_fsum__doc__,
#define MATH_FSUM_METHODDEF \
{"fsum", (PyCFunction)math_fsum, METH_O, math_fsum__doc__},
PyDoc_STRVAR(math_isqrt__doc__,
"isqrt($module, n, /)\n"
"--\n"
"\n"
"Return the integer part of the square root of the input.");
#define MATH_ISQRT_METHODDEF \
{"isqrt", (PyCFunction)math_isqrt, METH_O, math_isqrt__doc__},
PyDoc_STRVAR(math_factorial__doc__,
"factorial($module, n, /)\n"
"--\n"
"\n"
"Find n!.");
#define MATH_FACTORIAL_METHODDEF \
{"factorial", (PyCFunction)math_factorial, METH_O, math_factorial__doc__},
PyDoc_STRVAR(math_trunc__doc__,
"trunc($module, x, /)\n"
"--\n"
@@ -1107,89 +1035,6 @@ exit:
return return_value;
}
PyDoc_STRVAR(math_perm__doc__,
"perm($module, n, k=None, /)\n"
"--\n"
"\n"
"Number of ways to choose k items from n items without repetition and with order.\n"
"\n"
"Evaluates to n! / (n - k)! when k <= n and evaluates\n"
"to zero when k > n.\n"
"\n"
"If k is not specified or is None, then k defaults to n\n"
"and the function returns n!.\n"
"\n"
"Raises TypeError if either of the arguments are not integers.\n"
"Raises ValueError if either of the arguments are negative.");
#define MATH_PERM_METHODDEF \
{"perm", _PyCFunction_CAST(math_perm), METH_FASTCALL, math_perm__doc__},
static PyObject *
math_perm_impl(PyObject *module, PyObject *n, PyObject *k);
static PyObject *
math_perm(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *n;
PyObject *k = Py_None;
if (!_PyArg_CheckPositional("perm", nargs, 1, 2)) {
goto exit;
}
n = args[0];
if (nargs < 2) {
goto skip_optional;
}
k = args[1];
skip_optional:
return_value = math_perm_impl(module, n, k);
exit:
return return_value;
}
PyDoc_STRVAR(math_comb__doc__,
"comb($module, n, k, /)\n"
"--\n"
"\n"
"Number of ways to choose k items from n items without repetition and without order.\n"
"\n"
"Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates\n"
"to zero when k > n.\n"
"\n"
"Also called the binomial coefficient because it is equivalent\n"
"to the coefficient of k-th term in polynomial expansion of the\n"
"expression (1 + x)**n.\n"
"\n"
"Raises TypeError if either of the arguments are not integers.\n"
"Raises ValueError if either of the arguments are negative.");
#define MATH_COMB_METHODDEF \
{"comb", _PyCFunction_CAST(math_comb), METH_FASTCALL, math_comb__doc__},
static PyObject *
math_comb_impl(PyObject *module, PyObject *n, PyObject *k);
static PyObject *
math_comb(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *n;
PyObject *k;
if (!_PyArg_CheckPositional("comb", nargs, 2, 2)) {
goto exit;
}
n = args[0];
k = args[1];
return_value = math_comb_impl(module, n, k);
exit:
return return_value;
}
PyDoc_STRVAR(math_nextafter__doc__,
"nextafter($module, x, y, /, *, steps=None)\n"
"--\n"
@@ -1318,4 +1163,4 @@ math_ulp(PyObject *module, PyObject *arg)
exit:
return return_value;
}
/*[clinic end generated code: output=4fb180d4c25ff8fa input=a9049054013a1b77]*/
/*[clinic end generated code: output=23b2453ba77453e5 input=a9049054013a1b77]*/

1293
Modules/mathintegermodule.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,7 @@ extern PyObject* PyInit_errno(void);
extern PyObject* PyInit_faulthandler(void);
extern PyObject* PyInit__tracemalloc(void);
extern PyObject* PyInit_gc(void);
extern PyObject* PyInit__math_integer(void);
extern PyObject* PyInit_math(void);
extern PyObject* PyInit_nt(void);
extern PyObject* PyInit__operator(void);
@@ -100,6 +101,7 @@ struct _inittab _PyImport_Inittab[] = {
{"errno", PyInit_errno},
{"faulthandler", PyInit_faulthandler},
{"gc", PyInit_gc},
{"_math_integer", PyInit__math_integer},
{"math", PyInit_math},
{"nt", PyInit_nt}, /* Use the NT os functions, not posix */
{"_operator", PyInit__operator},

View File

@@ -479,6 +479,7 @@
<ClCompile Include="..\Modules\hmacmodule.c" />
<ClCompile Include="..\Modules\itertoolsmodule.c" />
<ClCompile Include="..\Modules\main.c" />
<ClCompile Include="..\Modules\mathintegermodule.c" />
<ClCompile Include="..\Modules\mathmodule.c" />
<ClCompile Include="..\Modules\md5module.c" />
<ClCompile Include="..\Modules\mmapmodule.c" />

View File

@@ -1070,6 +1070,9 @@
<ClCompile Include="..\Modules\main.c">
<Filter>Modules</Filter>
</ClCompile>
<ClCompile Include="..\Modules\mathintegermodule.c">
<Filter>Modules</Filter>
</ClCompile>
<ClCompile Include="..\Modules\mathmodule.c">
<Filter>Modules</Filter>
</ClCompile>

View File

@@ -51,6 +51,7 @@ static const char* _Py_stdlib_module_names[] = {
"_lsprof",
"_lzma",
"_markupbase",
"_math_integer",
"_md5",
"_multibytecodec",
"_multiprocessing",

View File

@@ -255,14 +255,14 @@ impl_definition block
cls: Class | None = None
for idx, field in enumerate(fields):
fullname = ".".join(fields[:idx + 1])
if not isinstance(parent, Class):
if field in parent.modules:
parent = module = parent.modules[field]
if fullname in parent.modules:
parent = module = parent.modules[fullname]
continue
if field in parent.classes:
parent = cls = parent.classes[field]
else:
fullname = ".".join(fields[idx:])
fail(f"Parent class or module {fullname!r} does not exist.")
return module, cls

28
configure generated vendored
View File

@@ -814,6 +814,8 @@ MODULE__BISECT_FALSE
MODULE__BISECT_TRUE
MODULE__ASYNCIO_FALSE
MODULE__ASYNCIO_TRUE
MODULE__MATH_INTEGER_FALSE
MODULE__MATH_INTEGER_TRUE
MODULE_ARRAY_FALSE
MODULE_ARRAY_TRUE
MODULE_TIME_FALSE
@@ -31334,6 +31336,28 @@ then :
fi
if test "$py_cv_module__math_integer" != "n/a"
then :
py_cv_module__math_integer=yes
fi
if test "$py_cv_module__math_integer" = yes; then
MODULE__MATH_INTEGER_TRUE=
MODULE__MATH_INTEGER_FALSE='#'
else
MODULE__MATH_INTEGER_TRUE='#'
MODULE__MATH_INTEGER_FALSE=
fi
as_fn_append MODULE_BLOCK "MODULE__MATH_INTEGER_STATE=$py_cv_module__math_integer$as_nl"
if test "x$py_cv_module__math_integer" = xyes
then :
fi
@@ -34447,6 +34471,10 @@ if test -z "${MODULE_ARRAY_TRUE}" && test -z "${MODULE_ARRAY_FALSE}"; then
as_fn_error $? "conditional \"MODULE_ARRAY\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${MODULE__MATH_INTEGER_TRUE}" && test -z "${MODULE__MATH_INTEGER_FALSE}"; then
as_fn_error $? "conditional \"MODULE__MATH_INTEGER\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${MODULE__ASYNCIO_TRUE}" && test -z "${MODULE__ASYNCIO_FALSE}"; then
as_fn_error $? "conditional \"MODULE__ASYNCIO\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5

View File

@@ -7881,6 +7881,7 @@ PY_STDLIB_MOD_SIMPLE([time], [], [$TIMEMODULE_LIB])
dnl always enabled extension modules
PY_STDLIB_MOD_SIMPLE([array])
PY_STDLIB_MOD_SIMPLE([_math_integer])
PY_STDLIB_MOD_SIMPLE([_asyncio])
PY_STDLIB_MOD_SIMPLE([_bisect])
PY_STDLIB_MOD_SIMPLE([_csv])