Python 中的指数:x**y 与 math.pow(x, y)

2025-04-17 09:02:00
admin
原创
18
摘要:问题描述:math.pow使用或运算符哪一个效率更高**?我什么时候应该使用其中一个?到目前为止,我知道x**y可以返回一个int或一个,float如果你使用小数,函数pow将返回一个浮点数import math print( math.pow(10, 2) ) print( 10. ** 2 ) 解决方...

问题描述:

math.pow使用或运算符哪一个效率更高**?我什么时候应该使用其中一个?

到目前为止,我知道x**y可以返回一个int或一个,float如果你使用小数,函数pow将返回一个浮点数

import math

print( math.pow(10, 2) )

print( 10. ** 2 )

解决方案 1:

使用幂运算符**会更快,因为它不会产生函数调用的开销。如果你反汇编一下 Python 代码,你会看到这一点:

>>> dis.dis('7. ** i')
  1           0 LOAD_CONST               0 (7.0) 
              3 LOAD_NAME                0 (i) 
              6 BINARY_POWER         
              7 RETURN_VALUE         
>>> dis.dis('pow(7., i)')
  1           0 LOAD_NAME                0 (pow) 
              3 LOAD_CONST               0 (7.0) 
              6 LOAD_NAME                1 (i) 
              9 CALL_FUNCTION            2 (2 positional, 0 keyword pair) 
             12 RETURN_VALUE         
>>> dis.dis('math.pow(7, i)')
  1           0 LOAD_NAME                0 (math) 
              3 LOAD_ATTR                1 (pow) 
              6 LOAD_CONST               0 (7) 
              9 LOAD_NAME                2 (i) 
             12 CALL_FUNCTION            2 (2 positional, 0 keyword pair) 
             15 RETURN_VALUE         

请注意,我在这里使用变量i作为指数,因为像这样的常量表达式7. ** 5实际上是在编译时进行评估的。

现在,实际上,这种差异并不那么重要,正如您在计时时所看到的那样:

>>> from timeit import timeit
>>> timeit('7. ** i', setup='i = 5')
0.2894785532627111
>>> timeit('pow(7., i)', setup='i = 5')
0.41218495570683444
>>> timeit('math.pow(7, i)', setup='import math; i = 5')
0.5655053168791255

因此,虽然powmath.pow的速度大约是前者的两倍,但它们仍然足够快,因此无需过多关注。除非您能真正识别出指数运算是瓶颈,否则如果清晰度降低,就没有理由选择其中一种方法而不是另一种方法。pow例如,这尤其适用于提供集成模运算的情况。


Alfe 在上面的评论中提出了一个很好的问题:

timeit结果表明,这math.pow**所有情况都要慢。这math.pow()到底有什么好处呢?有人知道它有什么优势吗?

math.pow内置运算符pow和幂运算符的最大区别**在于,幂运算符始终使用浮点语义。因此,如果您出于某种原因希望确保返回浮点数,则math.pow需要确保此属性。

让我们举个例子:我们有两个数字,ij,并且不知道它们是浮点数还是整数。但我们想要得到浮点数的结果i^j。那么我们有什么选择呢?

  • 我们可以将至少一个参数转换为浮点数,然后执行i ** j

  • 我们可以执行i ** j并将结果转换为浮点数(当ij为浮点数时,会自动使用浮点指数,因此结果相同)。

  • 我们可以使用math.pow

那么,让我们测试一下:

>>> timeit('float(i) ** j', setup='i, j = 7, 5')
0.7610865891750791
>>> timeit('i ** float(j)', setup='i, j = 7, 5')
0.7930400942188385
>>> timeit('float(i ** j)', setup='i, j = 7, 5')
0.8946636625872202
>>> timeit('math.pow(i, j)', setup='import math; i, j = 7, 5')
0.5699394063529439

正如你所见,math.pow实际上更快了!而且如果你仔细想想,函数调用的开销现在也消失了,因为在所有其他替代方案中,我们只需要调用float()


此外,值得注意的是,可以通过为自定义类型实现特殊的(and ) 方法来覆盖**and的行为。所以,如果你不想这样做(无论出于何种原因),使用 using是不会实现这一点的。pow`__pow____rpow__math.pow`

解决方案 2:

pow() 函数允许您添加第三个参数作为模数。

例如:我最近在执行以下任务时遇到了内存错误:

2**23375247598357347582% 23375247598357347583

相反,我这样做了:

pow(2, 23375247598357347582, 23375247598357347583)

这仅需几毫秒即可返回结果,而不像普通指数那样需要耗费大量的时间和内存。因此,在处理大数和并行模数时,pow() 效率更高;然而,在处理不带模数的较小数时,** 效率更高。

解决方案 3:

仅针对协议:该运算符相当于内置函数**的双参数版本,如果前两个参数是整数,则该函数接受可选的第三个参数(模数)。pow`pow`

因此,如果您打算计算幂的余数,请使用内置函数。math.pow对于合理大小的参数,它将给出错误的结果:

import math

base = 13
exp = 100
mod = 2
print math.pow(base, exp) % mod
print pow(base, exp, mod)

当我运行这段代码时,我遇到0.0了第一种情况,这显然不可能成立,因为 13 是奇数(因此它的所有整数幂都是奇数)。该版本使用了IEEE-754双精度math.pow的有限精度(52 位尾数,略小于 16 位小数),这会导致此处出现错误。

为了公平起见,我们必须说,也math.pow 可以更快:

>>> import timeit
>>> min(timeit.repeat("pow(1.1, 9.9)", number=2000000, repeat=5))
0.3063715160001266
>>> min(timeit.repeat("math.pow(1.1, 9.9)", setup="import math", number=2000000, repeat=5))
0.2647279420000359

math.pow函数在工程应用中曾经(现在仍然)具有其优势,但对于数论应用,您应该使用内置pow函数。


一些在线示例


更新(不可避免的修正): 我删除了和

的时间比较,因为它会给出错误的结果,而例如和之间的比较本来是公平的(尽管这不符合-module 函数的实际用途)。我添加了一个更好的比较,并指出了导致 限制的细节。math.pow(2,100)`pow(2,100)math.powpow(2,50)math.pow(2,50)math`math.pow

解决方案 4:

**确实比 更快math.pow(),但如果您想要像示例中那样的简单二次函数,那么使用乘积会更快。

10.*10.

会更快

10.**2

对于一次操作(使用),差异并不大且不明显timeit,但是对于大量操作,差异可能会很大。

解决方案 5:

嗯,它们确实用于不同的任务。

当您需要整数运算时, 使用pow(相当于带有两个参数)。x ** y

math.pow如果任一参数都是浮点数,并且您想要浮点输出, 则使用。

pow有关和之间的差异的讨论math.pow,请参阅此问题。

解决方案 6:

运算符**(与相同pow())可用于计算非常大的整数。

>>> 2 ** 12345
164171010688258216356020741663906501410127235530735881272116103087925094171390144280159034536439457734870419127140401667195510331085657185332721089236401193044493457116299768844344303479235489462...

>>> math.pow(2, 12345)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: math range error
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2482  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1533  
  PLM(产品生命周期管理)项目对于企业优化产品研发流程、提升产品质量以及增强市场竞争力具有至关重要的意义。然而,在项目推进过程中,范围蔓延是一个常见且棘手的问题,它可能导致项目进度延迟、成本超支以及质量下降等一系列不良后果。因此,有效避免PLM项目范围蔓延成为项目成功的关键因素之一。以下将详细阐述三大管控策略,助力企业...
plm系统   0  
  PLM(产品生命周期管理)项目管理在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和产品复杂度的提升,PLM项目面临着诸多风险。准确量化风险优先级并采取有效措施应对,是确保项目成功的关键。五维评估矩阵作为一种有效的风险评估工具,能帮助项目管理者全面、系统地评估风险,为决策提供有力支持。五维评估矩阵概述...
免费plm软件   0  
  引言PLM(产品生命周期管理)开发流程对于企业产品的全生命周期管控至关重要。它涵盖了从产品概念设计到退役的各个阶段,直接影响着产品质量、开发周期以及企业的市场竞争力。在当今快速发展的科技环境下,客户对产品质量的要求日益提高,市场竞争也愈发激烈,这就使得优化PLM开发流程成为企业的必然选择。缺陷管理工具和六西格玛方法作为...
plm产品全生命周期管理   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用