def monte_carlo_pi(num_dardos): """ Calcula o valor de pi pelo método de Monte Carlo. """ # define e inicializa acumulador conta_dardos_in = 0 for i in range(num_dardos): # gera posição dardo i x= random.random() y= random.random() # dentro ou fora? d = (x**2 + y**2)**0.5 if d <= 1: conta_dardos_in = conta_dardos_in + 1 res_pi = 4 * (conta_dardos_in/num_dardos) return res_piA ideia consiste em ter um quarto de círculo de raio um (cuja área é igual a pi/4) inscrito num quadrado de lado um. Simulamos de seguida o lançamento de dardos cuja posição de impacto é escolhida com base numa distribuição uniforme (todos os pontos são equi-prováveis). A percentagem de dardos que cai dentro do círculo, multiplicado por 4 dá-nos o valor pretendido.
Este método pode ser aplicado nas mais diversas situações e problemas. Por exemplo, determinar a probabilidade de um dardo lançado aleatoriamente cair dentro de uma certa zona. Procurámos resolver esta questão no caso das áreas 1 e 3 da figura abaixo. A ideia para a solução não é diferente da anterior: contar a percentagem dos dardos que caem dentro de uma das áreas pretendidas:
def monte_carlo_reg_2(num_dardos): """ Calcula o valor de uma área pelo método de Monte Carlo. """ # define e inicializa acumulador conta_dardos_in = 0 for i in range(num_dardos): # gera posição dardo i x= random.uniform(0,2) y= random.uniform(0,2) # dentro ou fora zona_1 = (x <= 1 and y >=1) zona_3 = (x >= 1 and y <= 1) or (x>= 1 and y <= x) if zona_1 or zona_3: conta_dardos_in = conta_dardos_in + 1 res = conta_dardos_in/num_dardos return resCom estes dois exemplos o leitor está preparado para dar o salto para uma generalização da abordagem. Imaginemos que queremos calcular um dado integral: Sabemos que o valor do integral é dado pela área debaixo de f(x), para x entre a e b. Então conhecido f(x) podemos encontrar uma figura geométrica de área conhecida e que envolva f(x). Feito isto só temos que calcular a percentagem de dados que ficam debaixo da curva e multiplicar pela área. E o programa que o faz é o seguinte:
def monte_carlo_int(funcao, min_x, max_x, min_y, max_y, num_dardos): """ Calcula o valor de um integral pelo método de Monte Carlo. """ # define e inicializa acumulador conta_dardos_in = 0 for i in range(num_dardos): # gera posição dardo i x= random.uniform(min_x,max_x) y= random.uniform(min_y,max_y) # dentro ou fora zona_limite = funcao(x) if y < zona_limite: conta_dardos_in = conta_dardos_in + 1 area = (max_x - min_x) * (max_y -min_y) res = area * (conta_dardos_in/num_dardos ) return resPodemos testar o programa para um caso concreto, o da função y = e^x. A imagem mostra o seu comportamento entre x= 0 e x = 1, e ainda alguns dardos que foram “lançados”: Como chamamos o programa? Fácil. Definimos a função, os respectivos valores máximos e mínimos para x e y e o número de dardos:
def my_exp(x): return pow(math.e, x) minx = 0 maxx = 1 miny = 0 maxy = math.e print(monte_carlo_int(my_exp, minx,maxx,miny,maxy,1000000))
Sem comentários:
Enviar um comentário