Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 791 – math.integer — 整数专属数学函数子模块

作者:
Sergey B Kirpichev <skirpichev at gmail.com>
发起人:
Victor Stinner <vstinner at python.org>
讨论至:
Discourse 帖子
状态:
草案
类型:
标准跟踪
创建日期:
2025年5月12日
Python 版本:
3.15
发布历史:
2018年7月12日, 2025年5月9日, 2025年5月19日

目录

摘要

本PEP提议为数论、组合学和其他定义为整数参数的函数(如 math.gcd()math.isqrt())创建一个新的子模块。

动机

math 文档中写道:“此模块提供对C标准定义的数学函数的访问。”但是,随着时间的推移,该模块被填充了与C标准或浮点算术无关的函数。现在,要描述模块的范围、内容和接口(返回值或接受的参数)变得更加困难。

例如,文档中的以下声明:“除非另有明确说明,所有返回值都是浮点数。”这已不再正确:文档的数论函数部分中列出的函数都没有返回浮点数,但文档没有说明。在提议的 math.integer 子模块的文档中,“所有返回值都是整数”这句话将是准确的。以类似的方式,我们可以简化新子模块和 math 中函数的接受参数的描述。

现在,满足人们对模块内容的期望变得更加困难。例如,他们是否应该期望 math.factorial(100) 返回一个精确的结果?许多语言、Python包(如 scipy)或袖珍计算器都有相同或相似名称的函数,它们返回一个浮点值,在这个例子中只是一个近似值。

显然,math 模块不能作为数学函数的万能库,因为我们还有 cmathstatistics 模块。让我们为整数相关函数也这样做。它提供共享上下文,减少文档的冗长性和概念负担。它还通过分组相关函数来帮助发现性,并使IDE(例如新的CPython的REPL)建议更有用。

目前,CPython中 math 模块的代码约为4200行,其中新模块的代码大约占1/3(1300行)。这与 cmath (1340行)相当,而 cmath 不是 libm 的简单包装器,就像 math 模块中的大多数函数一样。

而且这种情况有恶化的趋势。当模块拆分首次被提出时,只有两个整数相关函数: factorial() (也接受 float,像模块中的其他函数一样)和 gcd() (从 fractions 模块移出)。随后添加了 isqrt()comb()perm(),并第二次提议添加新模块,以便所有新函数都直接进入其中,而不会污染 math 命名空间。现在有六个函数,而且 factorial() 不再接受 float

在最初的讨论串和问题 python/cpython#81313 中提出的一些可能的添加包括:

  • c_div()n_div() — 用于整数除法,分别向上(向正无穷大)取整和向最近整数取整,参见相关讨论帖。这在标准库中多次被重新发明,例如在 datetimefractions 中。而且正如讨论帖所演示的,这很容易出错。
  • gcdext() — 解决两个变量的线性丢番图方程int 实现实际上包含扩展欧几里得算法)
  • isqrt_rem() — 返回整数平方根和余数(仅当整数不是完全平方数时余数才非零)
  • ilog() — 整数对数,math.log() 对整数参数有特殊处理。它(相对于其他模块函数)是独特的,并且迄今为止没有文档说明,参见问题 python/cpython#120950
  • fibonacci()斐波那契数列

独立的命名空间消除了与现有 math 模块函数可能存在的名称冲突。例如,用于整数向上取整除法的可能名称 ceil_div()ceildiv() 将与 ceil() (用于 float有时碰巧对整数除法做出了正确的事情——但通常不会)发生冲突。

基本原理

这都是关于文档的问题吗?为什么不直接修复它呢?不,不是。当然,我们可以在模块前言中更模糊一些(例如,大致说“math 模块包含一些数学函数”),我们可以准确描述每个函数的输入/输出及其行为(例如,factorial() 的输出是否精确,如 scipy.special.factorial,默认情况下)。

但主要问题是当前模块混合了不同、几乎不交织的应用领域。添加更多文档只会突出这一点,并使最终用户的问题更糟(需要阅读/跳过更多文本)。而且它不会解决可发现性问题(要知道在哪里找到函数,以及是否能找到,你需要查看模块中的所有函数),也不会解决Tab键自动完成问题。

规范

本PEP提议将以下整数相关函数移到一个新的子模块,命名为 math.integer

它们在 math 中的别名将被软弃用。本PEP不会引入向后不兼容的更改。

模块函数将接受整数和实现 __index__() 方法的对象,该方法用于将对象转换为整数。在有足够的时间和内存的情况下,合适的函数必须精确计算。

intmath 包将为旧版本的Python提供新的子模块内容。

可能的扩展

新函数(如动机部分所述)不属于此提案。

不过,我们应该提到,除非我们能直接绑定到一些受良好支持的数学库(如 GMP),否则子模块的范围应该受到限制。例如,不包括素数测试和因式分解,因为生产质量的实现需要贡献者具备良好的数学背景,并且更属于专业库。

当提议的函数已存在于 gmpy2 中时,我们应优先为标准库提供兼容的接口。

向后兼容性

由于 math 中的别名将无限期保留(不鼓励使用),因此预计不会有代码中断。

如何教授此内容

新子模块将是以下函数的存放之处:1) 接受类似 int 的参数并返回整数的函数,以及 2) 属于任意精度整数算术领域的函数,即不依赖于平台浮点格式或行为和/或平台数学库 (libm) 的函数。

对于用户来说,首先查看 int 的方法是很自然的,这些方法涵盖了大多数基本用例(例如 int.bit_length() 方法),然后才是标准库中专门的模块。

参考实现

python/cpython#133909

被拒绝的想法

isqrt() 重命名

曾有短暂的讨论,关于将 math.isqrt() 公开为 imath.sqrt,就像 cmath.sqrt()math.sqrt() 的复数版本一样。然而,isqrt 最终是一个不同的函数:它是平方根的下限。给它相同的名称(在不同的模块下)会造成混淆。

模块名称

投票结果显示 intmath 是最受欢迎的候选名称,imath 紧随其后。

其他提议的名称包括 ntheory (如 SymPy 的子模块), integermath, zmath, dmathimaths

但是指导委员会(SC)倾向于子模块而不是新的顶级模块。math 的子模块最受欢迎的变体是:integerdiscretentheory(作者偏好)。

致谢

感谢 Tim Peters 重新提出拆分 math 模块的建议。感谢 Neil Girdhar 对初稿的重大改进。


来源:https://github.com/python/peps/blob/main/peps/pep-0791.rst

最后修改:2025-10-14 09:50:08 GMT