Причина, по которой вы получаете только 0
или 1
, заключается в том, что вы только берете (или забираете) монеты из кошелька только один раз, но затем вы проверяете, что нарисовать 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 рекомендует использовать Collections.shuffle()
, а затем взять первые 3 монеты в вашей коллекции (например, ArrayList). Это хорошее предложение, но я предполагаю, что вы еще не знакомы с Collections
, и, возможно, вам не разрешено их использовать. Если да - воспользуйтесь ими. Если нет (как я предполагаю), вы можете подумать о лучших способах случайного извлечения n элементов из массива длины r без замены.
Один (хорошо принятый) способ - это перемешивание Фишера-Йейтса и его производные. По сути, он включает случайный выбор из неотобранного подмножества массива.
В 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
.
Ваша программа Монте-Карло пытается оценить эту вероятность. Можно ожидать, что он сходится на 0,1 при достаточных оценках (то есть при достаточно высоком numTrials
). Он не всегда дает значение, равное или даже начинающееся с 0.1
. При достаточном количестве испытаний это может дать что-то начиная с 0.09
или 0.1
. Однако, если numTrials == 1
, он выдаст либо 0
, либо 1
, потому что он будет рисовать один раз, и ничья либо совпадет, либо нет. Если numTrials == 2
, результаты могут быть только 0
, 0.5
или 1
и так далее.
Один из уроков моделирования методом Монте-Карло для оценки вероятностей - иметь достаточно большое количество выборок, чтобы получить хорошую оценку. Это, в свою очередь, зависит от требуемой точности - вы можете использовать свой код, чтобы исследовать это, когда он заработает.
person
J Richard Snape
schedule
13.04.2015