如何不使用math模块计算平方根?

17 投票
11 回答
73183 浏览
提问于 2025-04-16 00:00

我想要找到一个数字的平方根,但不想使用数学模块,因为我需要调用这个函数大约2万次,不想每次调用时都链接数学模块,这样会让执行速度变慢。

有没有更快更简单的方法来计算平方根呢?

11 个回答

12

我觉得数学库的速度应该和你自己写的代码差不多快。不过,如果你想自己写一个算法,这里有一个例子。我不太懂Python,所以我就写了一些伪代码。

function sqrt(x)
  lastGuess=x/2
  loop
    guess=(lastGuess+x/lastGuess)/2
    if abs(guess-lastGuess)<.000001 // or whatever threshold you want
      exit loop
    lastGuess=guess
  return guess

然后把这个伪代码转成Python代码:

def sqrt(x):
    last_guess= x/2.0
    while True:
        guess= (last_guess + x/last_guess)/2
        if abs(guess - last_guess) < .000001: # example threshold
            return guess
        last_guess= guess
12

正如Fabian所说,想要比math.sqrt更快是很难的。原因是它调用了C语言库中的相应函数,这在CPython中是这样实现的。

不过,你可以通过去掉查找属性的开销来加快速度:

from math import sqrt

每次后续调用sqrt时,就不需要再去math模块中查找,这样可以节省执行时间:

print sqrt(2)

这里有一些时间测试的数据,从最快到最慢(Python 2.6.5,Mac OS X 10.6.3):sqrt**0.5要快:

lebigot@weinberg ~ % python -m timeit -s 'from math import sqrt; x = 2' 'sqrt(x)'
1000000 loops, best of 3: 0.207 usec per loop
lebigot@weinberg ~ % python -m timeit -s 'x = 2' 'x**0.5'
1000000 loops, best of 3: 0.226 usec per loop
lebigot@weinberg ~ % python -m timeit -s 'import math; x = 2' 'math.sqrt(x)'
1000000 loops, best of 3: 0.268 usec per loop

注意,时间测试是计算一个变量的平方根。它们并不是计算像2**0.5这样的常量,因为2**0.5在CPython中是预先计算好的:

import dis

def f():
    return 2**0.5

print dis.dis(f)

打印结果

2           0 LOAD_CONST               3 (1.4142135623730951)
            3 RETURN_VALUE        

你会看到常量浮点数sqrt(2) = 1.414…

如果你在处理数字数组,使用NumPy的sqrt会更合适,正如另一个回答中提到的那样。

33

导入数学模块只需要做一次,而且你可能找不到比数学模块更快的方式了。还有一个旧的Stackoverflow问题讨论了在Python中,x**.5和math.sqrt(x)哪个更快?,但目前还不清楚哪种方法更快。

也许可以看看NumPySciPy,虽然不一定是为了开平方,但如果你在做一些复杂的计算,它们可能会很有用。

撰写回答