【问题标题】:Is there any advantage using math.sqrt(num) over num**0.5 in Python在 Python 中使用 math.sqrt(num) 比 num**0.5 有什么优势吗
【发布时间】:2013-12-12 04:00:18
【问题描述】:

我看到人们通常使用math 库来计算平方根,我想知道与普通的**0.5 相比是否有优势(matissa 或计算效率)?

好吧也做了个快速测试,cpu时间趋于相等

import time 

start_time = time.clock()

i = 0
while i < 10000000: 
    i ** 0.5
    i += 1

elapsed_time = time.clock() - start_time
print ("Time elapsed: {} seconds".format(elapsed_time))

经过时间:7.27 秒

import time 
import math

start_time = time.clock()

i = 0
while i < 10000000: 
    math.sqrt(i)
    i += 1

elapsed_time = time.clock() - start_time
print ("Time elapsed: {} seconds".format(elapsed_time))

经过的时间:7.109999999999999 秒

【问题讨论】:

标签: python


【解决方案1】:

他们的行为有细微的差别。 x**n 首先尝试x.__pow__(n)。如果该调用返回 NotImplemented,则调用 n.__rpow__(x)

>>> (2).__pow__(0.5)
NotImplemented
>>> (0.5).__rpow__(2)
1.4142135623730951

math.sqrt(x) 将 x 转换为浮点数(幕后的 C 双精度),然后调用 C 数学库。

>>> class F(object):
...   def __init__(self, value):
...     self.value = value
...   def __float__(self):
...     print("hi!")
...     return float(self.value)
... 
>>> a=F(2)
>>> math.sqrt(a)
hi!
1.4142135623730951

这种差异对于 Python 中的普通数字类型通常并不重要,但其他数字类型的行为可能会有所不同。 gmpy2 实现了整数和浮点的任意精度算术。导致 math.sqrt() 溢出的值可以由 ** 处理。

>>> import gmpy2
>>> math.sqrt(gmpy2.mpz("1"*999))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: 'mpz' too large to convert to float
>>> gmpy2.mpz("1"*999)**0.5
mpfr('1.0540925533894598e+499')
>>> 

【讨论】:

    【解决方案2】:

    看起来函数调用更快了:

    In [102]: a = 2
    
    In [103]: timeit a**0.5
    1000000 loops, best of 3: 222 ns per loop
    
    In [104]: timeit sqrt(a)
    10000000 loops, best of 3: 120 ns per loop
    

    除了可读性之外,我想不出任何其他原因。哪个更具可读性取决于您询问的对象和上下文。

    【讨论】:

    • 这不是一个公平的比较——尝试a=2,然后是timeit a**0.5timeit sqrt(a)
    【解决方案3】:

    根据 math.pow(x,[b]) 的描述,我会冒险 math.sqrt(x) 会进行自动类型转换。一般来说,我的猜测是数学库是一个比使用 **0.5 更安全、更可靠的函数

    【讨论】:

      【解决方案4】:

      它们差不多:

      $ python -m timeit 'import math; [math.sqrt(n) for n in range(100)]'
      100000 loops, best of 3: 13.3 usec per loop
      $ python -m timeit 'import math; [n**0.5 for n in range(100)]'
      100000 loops, best of 3: 16.2 usec per loop
      

      【讨论】:

        【解决方案5】:

        在对 python 了解不多的情况下,我会说在你只做一次的情况下,运算符比调用库函数更好,因为使用运算符意味着你的解释器(或其他语言的编译器)不会必须遍历整个包含的库。

        【讨论】:

          猜你喜欢
          • 2012-06-05
          • 2012-01-10
          • 2014-01-02
          • 2019-11-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-20
          • 1970-01-01
          • 2011-10-02
          相关资源
          最近更新 更多