简体   繁体   English

在 Python 中使用 Monte Carlo 方法估算球体的体积时无法计算小于 1 的数字

[英]Cant count up numbers < 1 while estimating the volume of a sphere using the Monte Carlo method in Python

For an assignment, I need to write a program that can estimate the volume of an n-dimensional sphere using the Monte-Carlo method.对于一项作业,我需要编写一个程序,该程序可以使用蒙特卡洛方法估算 n 维球体的体积。 I think I'm very close to having it done, but there is one problem.我认为我非常接近完成它,但是有一个问题。

I feel like everything works fine, except the part where I need to count the number of sum_x s that are <1.我觉得一切正常,除了我需要计算 <1 的sum_x数量的部分。 It simply doesn't seem to add all of them together.它似乎并没有将它们全部加在一起。 How can I make it count all the sum_x s that are <1?我怎样才能让它计算所有 <1 的sum_x

What can I do to fix this problem and make it count up all sum_x s < 1?我该怎么做才能解决这个问题并让它计算所有sum_x s < 1?

import random

def vol_sphere(n,s): #n is amount of dimensions, and s is the amount of points taken

    #grabbing random points
    for j in range(s):
        sum_x = 0
        count = 0
        for i in range(n):
            i = random.randrange(0,101)/100 #this might seem weird but I'm doing it so I can get decimals   
            x = i**2
            sum_x += x
        print("The sum of the x^2's is:", sum_x)
        if sum_x <= 1:
            count += 1
    v = count/s
    volume = (2**n)*v
    print(volume)
    
vol_sphere(3,1000000)

You are resetting count to zero every iteration through the loop.您正在通过循环的每次迭代将count重置为零。 Move the line count = 0 before the loop.在循环之前移动count = 0行。

Also, why not use random.uniform(-1,1) to generate coordinates uniformly between -1 and 1?另外,为什么不使用random.uniform(-1,1)在 -1 和 1 之间统一生成坐标? Your current method is only generating positive coordinates, but the 2**n in your volume calculation implies you are thinking of the cube each of whose sides goes from -1 to 1.您当前的方法仅生成正坐标,但体积计算中的2**n意味着您正在考虑每个边从 -1 到 1 的立方体。

In addition to Nick's answer (you reset count in the loop, when you should reset it just once; and you should use random.ramdom() to get a float uniform value from [0,1), instead of that random.randrange(0,101)/100 which introduce a rough discretization, and cost CPU — Nick's said random.uniform(-1,1), which is exactly the same here, since we don't really care for the sign, but cost 60% to 100% more CPU than random.random), you should also consider relying on numpy batch computation, to avoid using for loop yourself.除了尼克的回答(你在循环中重置计数,当你应该只重置一次时;你应该使用 random.ramdom() 从 [0,1 获取浮点统一值),而不是 random.randrange( 0,101)/100 引入了粗略的离散化,并消耗 CPU — Nick 说的是 random.uniform(-1,1),这里完全一样,因为我们并不真正关心符号,但消耗 60% 到 100 % more CPU than random.random),你还应该考虑依赖 numpy 批计算,以避免自己使用 for 循环。

import random
import sys
import numpy as np

def vol_sphere(n,s): #n is amount of dimensions and s is amount of points taken

    #grabbing random points
    count = 0
    for j in range(s):
        sum_x = 0
        for i in range(n):
            # I renamed your random variable ii, because I'm not very
            # comfortable with reusing the iteration variable. Even tho 
            # you can do it, as long as you don't really need i's value
            ii = random.random() #this might seem weird but I'm doing it so I can get decimals   
            x = ii**2
            sum_x += x
# Commented print (those printing cost all the CPU)
#        print("The sum of the x^2's is:", sum_x)
        if sum_x <= 1:
            count += 1
    v = count/s
    volume = (2**n)*v
    print(volume)

def vol_sphere2(n,s):
    # Same, but does computation by batches of 10000 (acceptable tradeoff
    # between CPU and memory)
    count=0
    reals=0
    for j in range(0, s, 10000):
        X2=np.random.random((10000, n))**2 # Generate 10000×n random number, squared at once
        # X2.sum(axis=1) is the column of 10000 sums of n columns of X2
        # X2.sum(axis=1)<=1 is a column of 10000 True/False saying which are<=1
        # (X2.sum(axis=1)<=1).sum() is the number of True
        count += (X2.sum(axis=1)<=1).sum()
        reals+=10000 # if s is not a factor of 10000, then we will do slightly more than s points.
    print(count/reals*2**n)

vol_sphere2(n,s)

On my computer version 2 is 20 times faster than version 1.在我的电脑上,版本 2 比版本 1 快 20 倍。

Edit: just for fun, I add a one-liner answer编辑:只是为了好玩,我添加了一个单行答案

((np.random.random((s,n))**2).sum(axis=1)<=1).sum()/s*2**n

Which use some memory, but not much code lines.其中使用了一些 memory,但代码行不多。

For example, an estimation of pi is例如,pi 的估计是

((np.random.random((100000,2))**2).sum(axis=1)<=1).sum()/100000*2**2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM