如何提高在Python中估计`Pi`的性能

时间:2015-06-12 15:37:25

标签: python performance pi

我在Python中编写了以下代码,以便估算Pi的值。它被称为Monte Carlo方法。显然,通过增加样本数量,代码变得更慢,我认为代码中最慢的部分是在采样部分。 我怎样才能让它更快?

from __future__ import division
import numpy as np

a = 1
n = 1000000

s1 = np.random.uniform(0,a,n)
s2 = np.random.uniform(0,a,n)

ii=0
jj=0

for item in range(n):
    if ((s1[item])**2 + (s2[item])**2) < 1:
        ii = ii + 1

print float(ii*4/(n))

您是否建议其他(可能更快)代码?

3 个答案:

答案 0 :(得分:8)

这里的瓶颈实际上是你的for循环。 Python for item in range(n): if ((s1[item])**2 + (s2[item])**2) < 1: ii = ii + 1 循环相对较慢,因此如果需要迭代超过一百万个项目,则可以通过完全避免它们来获得大量速度。在这种情况下,它很容易。而不是:

ii = ((s1 ** 2 + s2 ** 2) < 1).sum()

这样做:

numpy

这是有效的,因为c内置了对优化数组操作的支持。循环发生在>>> def estimate_pi_loop(x, y): ... total = 0 ... for i in xrange(len(x)): ... if x[i] ** 2 + y[i] ** 2 < 1: ... total += 1 ... return total * 4.0 / len(x) ... >>> def estimate_pi_numpy(x, y): ... return ((x ** 2 + y ** 2) < 1).sum() ... >>> %timeit estimate_pi_loop(x, y) 1 loops, best of 3: 3.33 s per loop >>> %timeit estimate_pi_numpy(x, y) 100 loops, best of 3: 10.4 ms per loop 而不是python中,所以它的速度要快得多。我做了一个快速测试,所以你可以看到差异:

>>> a = numpy.arange(5)
>>> a ** 2
array([ 0,  1,  4,  9, 16])

以下是一些可能的操作示例,以便您了解其工作原理。

平方阵列:

>>> a + a
array([0, 2, 4, 6, 8])

添加数组:

>>> a > 2
array([False, False, False,  True,  True], dtype=bool)

比较数组:

>>> (a > 2).sum()
2

求和布尔值:

var object = { "eid": "12345666c85f0beaad3c52947bb2dd88" };
$.cookie("blah", JSON.serialize(object));
$.parseJSON($.cookie("blah"))

正如您可能已经意识到的,有更快的方法来估计Pi,但我承认我总是钦佩这种方法的简单性和有效性。

答案 1 :(得分:2)

您已经分配了numpy数组,因此您应该使用这些数据。

for item in range(n):
    if ((s1[item])**2 + (s2[item])**2) < 1:
        ii = ii + 1

变为

s1sqr = s1*s1
s2sqr = s2*s2
s_sum = s1sqr + s2sqr
s_sum_bool = s_sum < 1
ii = s_sum_bool.sum()
print float(ii*4/(n))

你正在对数组进行平方,对它们求和,检查总和是否小于1,然后将布尔值(false = 0,true = 1)相加,得到满足条件的总数。

答案 2 :(得分:1)

我赞成senderle的答案,但如果您不想更改代码:

numba是为此目的而设计的图书馆。

只需将算法定义为函数,然后添加@jit装饰器:

 from __future__ import division
 import numpy as np
 from numba import jit

 a = 1
 n = 1000000

 s1 = np.random.uniform(0,a,n)
 s2 = np.random.uniform(0,a,n)

 @jit
 def estimate_pi(s1, s2):
     ii = 0
     for item in range(n):
         if ((s1[item])**2 + (s2[item])**2) < 1:
             ii = ii + 1
     return float(ii*4/(n))

 print estimate_pi(s1, s2)

在我的笔记本电脑上,n = 100000000的加速比增加了约20倍,n = 1000000的加速比增加了3倍。