【发布时间】:2010-06-15 16:19:01
【问题描述】:
我想在不使用数学模块的情况下找到数字的平方根,因为我需要调用该函数大约 20k 次,并且不想通过每次调用函数时链接到数学模块来减慢执行速度
有没有更快更简单的求平方根的方法?
【问题讨论】:
-
sqrt() 很慢。您真的需要找到 20k 个不同的根,还是可以使用查找表或缓存结果?
标签: python
我想在不使用数学模块的情况下找到数字的平方根,因为我需要调用该函数大约 20k 次,并且不想通过每次调用函数时链接到数学模块来减慢执行速度
有没有更快更简单的求平方根的方法?
【问题讨论】:
标签: python
导入数学模块只发生一次,您可能不会比数学模块快多少。还有一个关于 Which is faster in Python: x**.5 or math.sqrt(x)? 的旧 Stackoverflow 问题。目前尚不清楚哪种方法更快。
【讨论】:
sqrt() 实际上更快(见我的回答)。这两种方法实际上是不同的,哪一种更快取决于实现细节。
正如 Fabian 所说,很难比math.sqrt 更快。原因是它从C库中调用了对应的函数,用CPython。
但是,您可以通过消除属性查找的开销来加快速度:
from math import sqrt
随后对 sqrt 的每次调用不必在数学模块中查找它,这样可以节省执行时间:
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
你在哪里看到常量 float sqrt(2) = 1.414…
如果您操作数字数组,NumPy 的 sqrt 是要走的路,正如另一个答案中提到的那样。
【讨论】:
python -m timeit -s 'import math; x= 10000000000; math.sqrt(x)'
我认为数学库可能与您自己编写的任何东西一样快。但如果你想自己写,这里有一种算法。我不懂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
【讨论】:
你应该在 Jupyter Notebook 中输入这一行:
25**(1/2)
【讨论】:
在某些特殊情况下,您可以用程序大小来换取极快的速度。创建一个大数组并存储每个平方根运算的预计算结果(使用输入值作为索引)。它非常有限,但你不会得到更快的东西。
(地震就是这样弄的)
【讨论】:
使用幂运算符,将您的数字提高到 1/2 次方:
>>> 2**0.5
1.4142135623730951
至于是否更快:
>>> timeit.timeit(stmt='sqrt(x)', setup='from math import sqrt; x = 2')
0.7182440785071833
>>> timeit.timeit(stmt='x**0.5', setup='from math import sqrt; x = 2')
0.87514279049432275
【讨论】:
math.sqrt慢。原因是2**0.5是一个预先计算好的数值常数。
0.42521**0.5 大约比 sqrt(0.42521) 快 7 倍)。我没有得出任何结论,但测试对我来说似乎是有效的。
0.42521**0.5 是由 Python 预编译的(任何 0.5 次幂的常数也是如此):当您运行代码时,no 数学执行操作;相反,Python 只加载一个常数(请参阅我的答案中的反汇编代码)。如果计算时间很重要,那么只有在计算 变量 的平方根时(不是常数);因此,实际的测试应该包括取一个变量的平方根。
您可以实现 Newton 的方法,但是虽然它非常快,但它不太可能比我假设在数学模块中实现的 C 版本更快。见http://en.wikipedia.org/wiki/Methods_of_computing_square_roots。
【讨论】:
平方根函数
def sqrt(number):
if number ** 0.5 == int(number ** 0.5):
return True
else:
return False
【讨论】:
有点晚了,但无论如何我想提一下这些简单的算术:
25**(1/2)
或
pow(25, 0,5)
将返回 5. 享受。
【讨论】:
用于计算平方的 Python 代码 sn-p。它首先进行初始猜测,如果猜测不够好,它会迭代,直到我们有一个好的猜测
def gen_square_root_v1(number, epsilon):
#boundary condition check
if number == '1':
return 1
elif number <= 0:
print('this computes square root for positive numbers only' )
else:
pass
prev_estimate = number/2
while True:
#each itearation, calculate a new estimate
new_estimate = (prev_estimate + number/prev_estimate)/2
#Alternatively can use if abs(new_estimate - prev_estimate) < epsilon:
#check the difference between square of new_estimate and number
if abs(new_estimate * new_estimate - number) < epsilon:
return prev_estimate
#if guess is not good enough, use it to make the next guess
prev_estimate = new_estimate
#call the function
print(gen_square_root_v1(16,1e-5))
【讨论】:
下面的代码是在不使用python的内置方法的情况下找到数字的平方根。代码很容易理解,因为我使用数学简单解决方案编写了代码。
x=float(input())
min1=0
max1=x
for i in range(10):
mid=(min1+max1)/2 #middle value
res=mid**2 #finding the square of middle value
if res==x: #if the middle value is square root program break here
break
elif res>x: #if the square value of the middle value is more than x then we need to take max value as middle
max1=mid
else: #if the square value of the middle value is less than x then we need to take min value as middle
min1=mid
print(mid)
【讨论】: