The bottleneck here is your for loop. Python for loops are relatively slow, so if you need to iterate over a million items, you can get more speed by avoiding them at all. In this case, it is quite easy. Instead of this:
for item in range(n): if ((s1[item])**2 + (s2[item])**2) < 1: ii = ii + 1
do the following:
ii = ((s1 ** 2 + s2 ** 2) < 1).sum()
This works because numpy has built-in support for optimized array operations. The loop happens in c instead of python, so it is much faster. I did a quick test so you can see the difference:
>>> 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
Here are some examples of possible operations, so you have a sense of how this works.
Array squaring:
>>> a = numpy.arange(5) >>> a ** 2 array([ 0, 1, 4, 9, 16])
Adding Arrays:
>>> a + a array([0, 2, 4, 6, 8])
Comparison of arrays:
>>> a > 2 array([False, False, False, True, True], dtype=bool)
Summing Boolean Values:
>>> (a > 2).sum() 2
As you probably understand, there are faster ways to evaluate Pi, but I admit that I have always admired the simplicity and effectiveness of this method.