我是Java编程课程的学生。我的问题涉及对蒙特卡洛模拟的解释。我应该找到从四分之三零美分的钱包中挑出四分之三或三便士的可能性。硬币一旦被捡拾就不会被替换。机率应为0.1XXXXXXX。我的答案一直是0或1。这是我到目前为止所拥有的。

public class CoinPurse {
    public static void main(String[] args) {
        System.out.print("Probability of Drawing 3 coins of the Same Type - ");
        System.out.println(coinPurseSimulation(100));
    }

    /**
     Runs numTrials trials of a Monte Carlo simulation of drawing
     3 coins out of a purse containing 3 pennies and 3 quarters.
     Coins are not replaced once drawn.
     @param numTrials - the number of times the method will attempt to draw 3 coins
     @returns a double - the fraction of times 3 coins of the same type were drawn.
     */

    public static double coinPurseSimulation(int numTrials) {
        final int P = 1;
        final int Q = 2;
        int [] purse = {Q, Q, Q, P, P, P};
        int [] drawCoins = new int[3];
        for (int draw = 0; draw < 3; draw ++) {
            int index = (int)(Math.random() * purse.length);
            drawCoins[draw] = purse[index];
            int [] newPurse = new int[purse.length-1];
            int j = 0;
            for (int i =0; i < purse.length; i++) {
                if (i == index) {
                    continue;
                }
                newPurse[j] = purse[i];
                j++;
            }
            purse = newPurse;
        }
        double number = 0.0;
        double result = 0.0;
        for (int i = 0; i < numTrials; i++) {
            result++;
            for (int j = 0; j < numTrials;j++) {
                if(drawCoins[0] == drawCoins [1] && drawCoins[1] == drawCoins[2]) {
                    number++;
                }
            }
        }
        return number/result;
    }
}

最佳答案

您只能得到01的原因是,您只能从钱包中提取(或挑选)一次硬币,但随后测试提取numTrials * numTrials次。您有两个循环(索引为ij)迭代numTrials时间-那里的逻辑有些混乱。

您可以将第一个循环(用于绘制硬币)放入第二个循环(用于运行试验),您的代码将起作用。我在下面做了一个最小的重构(尽可能紧密地使用您的代码),之后再加上两条注释,可能会对您有所帮助。

public class CoinPurse
{
    public static void main(String[] args)
    {
        System.out.print("Probability of Drawing 3 coins of the Same Type - ");
        System.out.println(coinPurseSimulation(100));
    }

    /**
     * Runs numTrials trials of a Monte Carlo simulation of drawing 3 coins out
     * of a purse containing 3 pennies and 3 quarters. Coins are not replaced
     * once drawn.
     *
     * @param numTrials
     *            - the number of times the method will attempt to draw 3 coins
     * @returns a double - the fraction of times 3 coins of the same type were
     *          drawn.
     */

    public static double coinPurseSimulation(int numTrials)
    {
        final int P = 1;
        final int Q = 2;

        double number = 0.0;
        double result = 0.0;

        // Changed your loop index to t to avoid conflict with i in your draw
        // loop
        for (int t = 0; t < numTrials; t++)
        {
            result++;

            // Moved your draw without replacement code here
            int[] purse =
            { Q, Q, Q, P, P, P };
            int[] drawCoins = new int[3];

            for (int draw = 0; draw < 3; draw++)
            {
                int index = (int) (Math.random() * purse.length);
                drawCoins[draw] = purse[index];
                int[] newPurse = new int[purse.length - 1];
                int j = 0;
                for (int i = 0; i < purse.length; i++)
                {
                    if (i == index)
                    {
                        continue;
                    }
                    newPurse[j] = purse[i];
                    j++;
                }
                purse = newPurse;
            }

            // Deleted the loop with index j - you don't need to test the same
            // combination numTrials times...
            if (drawCoins[0] == drawCoins[1] && drawCoins[1] == drawCoins[2])
            {
                number++;
            }
        }

        return number / result;
    }
}


领取硬币代码

我对您的投币路线有一些评论:


它正常工作
这很麻烦
如果您将这部分代码分解为单独的方法,则更容易发现问题。


我要说的是3,然后是2。

将绘图代码分解为一种方法

private static int[] pickCoins(int[] purse, int numPicks)
{
    //A little error check
    if (numPicks > purse.length)
    {
        System.err.println("Can't pick " + numPicks +
                           " coins from a purse with only " + purse.length + " coins!");
    }

    int[] samples = new int[numPicks];

    // Your sampling code here

    return samples;
}


您现在可以简单地从第二个循环中进行调用,即

drawCoins = pickCoins(purse, 3);


采样算法

@pjs's answer建议使用Collections.shuffle(),然后获取您收藏中的前3个硬币(例如ArrayList)。这是一个很好的建议,但我想您尚未被引入Collections,并且可能无法“允许”使用它们。如果您是-请使用它们。如果不是(按照我的假设),您可能需要考虑更好的方法来从r长度数组中随机绘制n个项目而不进行替换。

一种(公认的)方式是Fisher-Yates shuffle及其派生词。实际上,它涉及从数组的未选择子集中随机选择。

在Java中-一个有效的示例如下-通过将拾取的硬币移动到钱包的“末端”并仅从第一个maxInd未拾取的硬币中进行拾取来工作。

    private static int[] pickCoins(int[] purse, int numCoins)
    {
        int[] samples = new int[numCoins];
        int maxInd = purse.length - 1;

        for (int i = 0; i < numCoins; i++)
        {
            int index = (int) (Math.random() * maxInd);
            int draw = purse[index];
            samples[i] = draw;
            // swap the already drawn sample with the one at maxInd and decrement maxInd
            purse[index] = purse[maxInd];
            purse[maxInd] = draw;
            maxInd -= 1;
        }

        return samples;
    }


预期成绩

您说您的预期结果是0.1XXXXXXX。在学习蒙特卡洛模拟时-您可能需要多考虑一点。预期结果取决于您进行了多少次试验。

首先,在这个简单的示例中,您可以考虑分析(或某种意义上说是精确的)结果。考虑以下过程:


您抽出第一枚硬币-不管是哪一个
不管是哪一种硬币,袋子中都剩下2枚相同的硬币-选择其中一种硬币的概率为2 / 5
如果您在步骤2中选择了匹配的硬币之一,则袋子中现在剩下1个匹配的硬币。拣选的概率为1 / 4
因此,获得3个匹配硬币(两种面额)的概率为2 / 5 * 1 / 4 == 2 / 20 == 0.1


您的蒙特卡洛程序正在尝试估计该概率。给定足够的估算值(即numTrials足够高),您可能希望它收敛于0.1。它不会总是给出等于甚至以0.1开头的值。经过足够的试验,很可能会给出以0.090.1开头的内容。但是,如果numTrials == 1,它将给出01,因为它将绘制一次,并且绘制是否匹配。如果为numTrials == 2,则结果只能为00.51,依此类推。

进行蒙特卡洛模拟以估计概率的一课是获得足够高的样本数以获得良好的估计。反过来,这取决于您想要的精度-一旦运行,您就可以使用代码进行调查。

07-26 02:57