我是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;
}
}
答案 0 :(得分:4)
您获得0
或1
的原因是您只能从钱包中绘制(或选择)硬币一次,但然后你 test 绘制numTrials * numTrials
次。你有两个循环(索引i
和j
)迭代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
,而且可能不会被允许&#39;使用它们。如果你是 - 确实使用它们。如果不是(我假设),您可能想要考虑更好的方法从r长度数组中随机绘制n个项目而无需替换。
一种(被广泛接受的)方式是Fisher-Yates shuffle及其衍生物。实际上,它涉及从数组的 未打开的 子集中随机选取。
在Java中 - 一个工作示例可以如下 - 它通过将拾取的硬币移动到&#34; end&#34;钱包和只从第一个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 / 5
1 / 4
2 / 5 * 1 / 4 == 2 / 20 == 0.1
您的蒙特卡洛计划正在尝试估算该概率。给定足够的估计值(即numTrials
足够高),你会期望它<0.1>收敛。它不会总是给出与0.1
相等甚至开始的值。通过足够数量的试验,它可能会提供从0.09
或0.1
开始的内容。但是,如果numTrials == 1
,它会提供0
或1
,因为它会绘制一次,并且绘制将匹配与否。如果numTrials == 2
,结果只能是0
,0.5
或1
,依此类推。
进行蒙特卡罗模拟以估算概率的一个教训是获得足够高的样本数以获得良好的估计。这反过来取决于您想要的准确性 - 您可以使用您的代码在其工作后进行调查。
答案 1 :(得分:0)
您需要将生成的循环向下移动到numTrials
循环中。您编写它的方式是进行单次绘制,然后检查一个结果numTrials
次。
我没有仔细检查你的绘图的逻辑,但那是因为我推荐了一种不同的(更简单的)方法。在你的宿舍和便士上使用Collections.shuffle(),并在每次洗牌后检查前三个元素。
如果操作正确,答案应为2 * (3/6) * (2/5) * (1/4)
,即0.1。