蒙特卡罗方法,飞镖在两个圆圈的重叠区域

时间:2013-09-24 03:51:54

标签: python

我正在尝试使用蒙特卡罗模拟来估计pi的值。我需要使用两个与原点相距用户输入距离的单位圆。我理解这个问题如何适用于单个圆圈,我只是不明白我是如何使用两个圆圈的。这是我到目前为止所得到的(这是我用于前一个问题的修改代码,使用了一个半径为2的圆。

import random
import math
import sys

def main():
    numDarts=int(sys.argv[1])
    distance=float(sys.argv[2])
    print(montePi(numDarts,distance))

def montePi(numDarts,distance):
    if distance>=1:
        return(0)
    inCircle=0
    for I in range(numDarts):
        x=(2*(random.random()))-2
        y=random.random()
        d=math.sqrt(x**2+y**2) 
        if d<=2 and d>=-2:
            inCircle=inCircle+1
    pi=inCircle/numDarts*4
    return pi

main()

我需要更改此代码才能使用2个单位圆,但我不明白如何使用三角函数来做这个,或者我是否在思考这个问题?无论哪种方式帮助将被欣赏,因为我继续试图解决这个问题。    我所知道的是我需要改变X坐标,以及确定“d”的等式(d = math.sqrt(x * 2 + y * 2)),我只是不确定如何。

这些是我的指示 -

编写一个名为mcintersection.py的程序,该程序使用蒙特卡罗方法 估计这个形状的面积(并打印结果)。你的程序应该采取 两个命令行参数:distance和numDarts。距离参数 指定圆与x轴上的原点相距多远。所以,如果距离 为0,则两个圆都以原点为中心,并完全重叠。如果 距离为0.5,则一个圆心((-0.5,0)为中心,另一个圆为(0.5,0)。如果 距离是1或更大,那么圆圈根本不重叠!在最后一种情况下,你的 程序可以简单地输出0. numDarts参数应该指定数字 随机点在蒙特卡罗过程中选择。

在这种情况下,矩形应该是2个单位高(顶部在y = 1和 底部在y = -1)。您也可以安全地将矩形设为2个单位宽,但这样 通常比必要的要大得多。相反,你应该弄清楚 根据距离参数确定形状的宽度。那样你就可以 尽可能使用像瘦的矩形。

1 个答案:

答案 0 :(得分:1)

如果我正确理解了问题,您有两个以(distance, 0)(-distance, 0)为中心的单位圆(也就是说,一个位于原点右侧,一个位于左侧)。您正在尝试确定给定点(x, y)是否在两个圈内。

最简单的方法可能是简单地计算每个圆的点和中心之间的距离。您已经在之前的代码中完成了此操作,只需重复计算两次,一次偏移偏移距离,然后使用and查看您的点是否在两个圆圈中。

但更优雅的解决方案是注意你的两个圆圈如何在y - 轴上完全相交。在轴的右侧,左侧圆圈完全包含在右侧。在y - 轴的左侧,右侧圆圈完全位于左侧圆圈内。由于形状是对称的,两半的大小完全相同。

这意味着你可以限制你的飞镖只能击中轴的一侧,然后通过一次距离测试就可以逃脱:

def circle_intersection_area(num_darts, distance):
    if distance >= 1:
        return 0

    in_circle = 0
    width = 1-distance   # this is enough to cover half of the target

    for i in range(num_darts):
        x = random.random()*width    # random value from 0 to 1-distance
        y = random.random()*2 - 1    # random value from -1 to 1
        d = math.sqrt((x+distance)**2 + y**2)  # distance from (-distance, 0)
        if d <= 1:
            in_circle += 1

    sample_area = width * 2
    target_area = sample_area * (in_circle / num_darts)

    return target_area * 2 # double, since we were only testing half the target