Search code examples
pythonmontecarlo

How to define an exact number of samples in the Monte Carlo method


I am developing a simulation of the integration of montecarlo (dx) and I find myself wondering which is the best way to determine the exact number of samples (N) in the Monte Carlo method to approximate the solution to a definite integral.

This is a simple code of implementation:

import math
import random

class Montecarlo:

    def __init__ (self):
        print ("Inicializa..")

    def fy(self, ri, a, b):
        res = math.pow((b-a)*ri+a, 2.0)+math.sqrt((b-a)*ri+a)        
        return res

    def integral (self, a, b, N):
        suma = 0.0
        ri = 0.0
        for i in range (N):
            ri = random.random()
            suma+=self.fy(ri,a,b)

        res=((b-a)/N)*suma
        return res
    if __name__ == "__main__":
        monte = Montecarlo()
        res = monte.integral(10.0,27.0,N)
        print("Res: ", res)
  • Where N must be a value that allows to approximate the real result of the integral

Solution

  • Win Monte Carlo, you could compute statistical error (stddev) of the simulation. It goes down as 1/sqrt(N). You could set your goal - say, make error below 2% - and easily compute now many samples (N) you need.

    I modified your code and added calculation of second momentum, sigma and simulation error

    import math
    import random
    
    class Montecarlo:
    
        def __init__(self):
            print ("Inicializa..")
    
        def fy(self, ri, a, b):
            res = math.pow((b-a)*ri+a, 2.0) + math.sqrt((b-a)*ri+a)
            return res
    
        def integral (self, a, b, N):
            sum = 0.0
            var = 0.0
            for i in range(N):
                ri = random.random()
                v  = self.fy(ri, a, b)
                sum += v
                var += v*v
    
            sum /= float(N)
            var /= float(N)
    
            sigma = ( var - sum*sum ) * float(N)/float(N-1)
            error = sigma / math.sqrt(N)
    
            return ((b-a) * sum, (b-a)*error)
    
    if __name__ == "__main__":
        N = 100000
        monte = Montecarlo()
        res, err = monte.integral(10.0, 27.0, N)
        print("Res: {0}, Err: {1}".format(res, err))