gpt4 book ai didi

python - Python负指数与除法

转载 作者:太空宇宙 更新时间:2023-11-04 01:13:28 25 4
gpt4 key购买 nike

在Python中,我应该使用负指数还是除法?例:

>>> num = 2.0**-1


要么

>>> num = 1/2.0


我进行了一些测试,看来区别在于BINARY_POWER与BINARY_DIVIDE:

import dis

def exp_test(x):
return x**-1

def div_test(x):
return 1/x

print "Exp Test:"
dis.dis(exp_test)
print "Div Test:"
dis.dis(div_test)


输出:

Exp Test:
2 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (-1)
6 BINARY_POWER
7 RETURN_VALUE
Div Test:
2 0 LOAD_CONST 1 (1)
3 LOAD_FAST 0 (x)
6 BINARY_DIVIDE
7 RETURN_VALUE


我在这里只考虑浮点值。我想我只需要担心浮点运算中通常会出现的差异。

最佳答案

如果您正在计算Python float x的倒数,我想不出任何理由更喜欢x**-1.0而不是1.0/x。从主观上讲,我认为后者更容易阅读。客观地讲,它可能会更快(因为它包装了一条简单的CPU指令,而不是对C库的pow函数的调用),并且更加准确(出于几乎相同的原因)。

请注意,我在两个表达式中都故意使用了1.0而不是1,这都是因为这样可以避免在x为浮点数的情况下进行额外的从int到float的转换,并且这将保证我在x恰好是一个int的情况下,在Python 2.7上获得一个适当的浮点除法而不是一个地板除法。

为了支持“更快”的主张,这是我的机器上的一些时间安排,包括同时具有11.0的变体。这是在Python 2.7下实现的,但结果在Python 3.4下却类似。

>>> import timeit
>>> timeit.timeit('x**-1', 'x=12.34')
0.08957314491271973
>>> timeit.timeit('x**-1.0', 'x=12.34')
0.08102011680603027
>>> timeit.timeit('1/x', 'x=12.34')
0.06166410446166992
>>> timeit.timeit('1.0/x', 'x=12.34')
0.04489898681640625


此处的除法形式具有相当明显的优势,并且使用 1.0代替 1可以明显提高速度。您的结果可能会有所不同。

注意:不要直接陷入诸如 2**-11.0/2.0这样的定时表达式的陷阱。可以通过Python的窥孔优化器将这些表达式优化为编译时的常量,因此最终需要花费的时间就是检索常量 0.5的时间。您可以使用标准库中的 dis模块查看此内容:

>>> def half_via_pow(): return 2.0**-1.0
...
>>> def half_via_div(): return 1.0/2.0
...
>>> import dis
>>> dis.dis(half_via_pow)
1 0 LOAD_CONST 3 (0.5)
3 RETURN_VALUE
>>> dis.dis(half_via_div)
1 0 LOAD_CONST 1 (1.0)
3 LOAD_CONST 2 (2.0)
6 BINARY_DIVIDE
7 RETURN_VALUE


上面显示了在Python 2.7上,计算 2.0**-1.0被优化为一个常数,而除法 1.0/2.0不是。在Python 3.4中,两者都被优化为一个常数。我怀疑Python 2.7窥孔优化器会避免优化除法,以便不必担心需要提高 ZeroDivisionError的情况。无论哪种方式,对 2.0**-1.0计时 1.0/2.0都不能准确反映 1.0/xx**-1.0的速度。将 1.0/xx**-1.0相对应,并在设置步骤中为 x提供一个值。

对于“更准确的”声明: 1.0/x将解析为一条机器指令,几乎可以肯定的是,它将为您提供四舍五入的结果。相反, pow的库实现非常糟糕,并且经常会给出未正确舍入的结果。即使在最好的情况下,数学库的 pow操作正确舍入,它仍然不会比除法结果更准确。

作为测试,我尝试了以下循环,比较 1.0 / xx ** -1.0的随机 x值:

>>> import random
>>> while True:
... x = random.random()
... print(repr(x))
... assert 1.0/x == x**-1.0


果然,经过大约200次迭代,我得到了:

<around 200 lines of output omitted>
0.16606458447273365
0.6466363135038045
0.8650060330740814
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
AssertionError


看一下最后一个 x值,我得到:

>>> x = 0.8650060330740814
>>> 1.0 / x
1.1560613010364489
>>> x ** -1.0
1.1560613010364487


粗略地检查一下 1.0 / x的结果是否在此正确舍入,我们可以将浮点数转换为 Fraction(进行精确转换),将倒数作为 Fraction,然后转换回 floatFraction的转换已正确舍入,并且不使用浮点算术来计算结果,因此在此检查中我们不依赖于浮点除法的精度。

>>> from fractions import Fraction
>>> float(1 / Fraction(x))
1.1560613010364489


float的精确倒数,计算为25个有效数字,是 x。我们从 1.156061301036448774438694取回的值,以相同的精度计算,是 1.0 / x,而 1.156061301036448885071195的值是< cc>,因此 x ** -1.0仅比 1.156061301036448663026590更接近真实值,但更接近。)

最后,对我而言,最重要的是, 1.0 / x易于阅读,并且不需要花费很多心思即可解析。

总而言之,没有什么理由偏爱 x ** -1.0形式。

关于python - Python负指数与除法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26185205/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com