0

I am trying to process a Monte Carlo Algorithm to calculate the value of pi. When I try to give a large input as mentioned in the program below. I get a memory error. What should i do to rectify it? The code is a s follows:

def PiCalc():
    N_ok=0  
    n=1000000000000 

    for i in range(n):  
        x=random()  
        y=random() 

        if sqrt(x**2 + y**2) <= 1:  
            N_ok+=1  
    pi= 4.0 * N_ok / n 

    print "No. of points inside the circle: ", N_ok
    print "Pi: ", pi
    return pi 
Andrea Corbellini
  • 17,339
  • 3
  • 53
  • 69
Sandy.Arv
  • 607
  • 10
  • 34
  • Can you post the output you're seeing? True memory errors in python are rare. – alexgolec Sep 22 '15 at 15:26
  • 6
    Does it help if you use `xrange` instead of `range`? – bereal Sep 22 '15 at 15:27
  • You're not actually using `i`. – Peter Wood Sep 22 '15 at 15:30
  • Even apart from the memory issue, it would take forever to loop 10^12 times, and your code doesn't print any partial results. – DSM Sep 22 '15 at 15:32
  • 1
    Why do you need the `sqrt`? – Peter Wood Sep 22 '15 at 15:34
  • thanks everyone. xrange helped. but ya as @DSM says it is taking forever to to loop. but, I am in need to compare the speed of different languages with the same function. so I have no choice. – Sandy.Arv Sep 22 '15 at 15:41
  • 1
    @Sandy.Arv consider picking and accepting the answer – Amir Sep 22 '15 at 15:42
  • "I am in need to compare the speed of different languages with the same function". How convenient, this has already been done for you: [N-body Benchmark](http://benchmarksgame.alioth.debian.org/u32/performance.php?test=nbody) – Kevin Sep 22 '15 at 15:43

4 Answers4

5

In Python 2.7 range(n) will create a list with 1000000000000 elements in it, which causes MemoryError

using xrange(n) you can generate items as you go

according to documentation:

xrange(start, stop[, step]) This function is very similar to range(), but returns an xrange object instead of a list. This is an opaque sequence type which yields the same values as the corresponding list, without actually storing them all simultaneously. The advantage of xrange() over range() is minimal (since xrange() still has to create the values when asked for them)

akalikin
  • 1,071
  • 12
  • 35
  • 1
    One of the differences between pythons 2 and 3. In python 3 there's no problem with range(1000000000000) because it does not create a list but a range expression, and it won't run you out of memory. Might take quite a while to iterate 10^12 times, though! – nigel222 Sep 22 '15 at 15:45
5

Given that nobody mentioned this...

You can also use itertools.repeat(None, n). This will be much faster than both range and xrange, because it won't create one trilion new int instances.

With repeat(), your for-loop becomes this:

for _ in itertools.repeat(None, n):
    x=random()
    y=random()
    if x**2 + y**2 <= 1:
        N_ok += 1
Andrea Corbellini
  • 17,339
  • 3
  • 53
  • 69
2

I assume that you are using Python 2.x because of the way you use print. In Python 2.x, range returns a list. So you are trying to build in memory a list of 1000000000000 integers. The memory error is normal here.

You should try instead:

for i in xrange(n):  

because xrange returns a xrange object (*) and does not build the list in memory.

(*) it allows iterating over the values, but it is not really an iterator (thanks to DSM for the precision)

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • Pedantic: `xrange` does not return an iterator. Try `next(xrange(10))` to confirm. – DSM Sep 22 '15 at 15:36
1

I'd create a function:

def random_pairs(n):
    for _ in itertools.repeat(None, n):
        yield random(), random()

N = sum(1 for (x, y) in random_pairs(n)
        if x**2 + y**2 <= 1.)
Peter Wood
  • 23,859
  • 5
  • 60
  • 99