该题目来源于Robert Sedgewick 的《算法》。
1.1.37 Dice simulation. The following code computes the exact probability distribution for the sum of two dice:
int SIDES = 6; double[] dist = new double[2*SIDES+1]; for (int i = 1; i <= SIDES; i++) { for(int j=1; j <= SIDES; j++){ dist[i+j] += 1.0; } } logger.info("dist:" + Arrays.toString(dist)); double sum = 0.0; for (double var : dist) { sum += var; } logger.info("dist sum: " + sum); for(int k=2; k <= 2*SIDES; k++){ dist[k] /= SIDES * SIDES; }
The vlaue dist[i] is the probability that the dice sum to i. Run experiments to validate this calculation simulating N dice throws, keeping track of the frequencies of occureence of each value when you compute the sum of two random integers between 1 and 6. How large does N have be before your empirical results match the exact results to three decimal places?
1.1.37 模拟掷筛子。下面的代码计算两个筛子点和的精确的可能性分布:
dist[i]的值为筛子和为i的可能性。模拟N次掷筛子去验证这个计算,当你计算两个随机在1到6之间的随机整数和的时候,保持跟踪每个值出现的频次。 在你的经验结果和准确结果匹配,精确到小数点后三位之前,N的值应该多大?
分析:
两个6面的筛子,同时掷两个筛子,可能出现的组合有6*6中情况。这6*6中情况中,和为i+j的情况有:dist[i+j] += 1 种。
详细的代码如下:
import java.util.Arrays;
import java.util.logging.Logger;
import utils.chapter1.StdRandom;
/**
*
*/
public class Exercise1135DiceSimulation {
private static final Logger logger = Logger.getLogger("basicprogrammingmodel.exercises");
private static final int SIDES = 6;
public static void main(String[] args) {
//diceExactProbabilityDistribution();
int N = findSufficientN(.001);
logger.info("N have to be " + N);
}
/**
* 精确值的概率分布
*/
public static double[] diceExactProbabilityDistribution(){
double[] dist = new double[2*SIDES+1];
for (int i = 1; i <= SIDES; i++) {
for(int j=1; j <= SIDES; j++){
dist[i+j] += 1.0;
}
}
logger.info("dist:" + Arrays.toString(dist));
double sum = 0.0;
for (double var : dist) {
sum += var;
}
logger.info("dist sum: " + sum);
for(int k=2; k <= 2*SIDES; k++){
dist[k] /= SIDES * SIDES;
}
logger.info("dist:" + Arrays.toString(dist));
return dist;
}
/**
* 掷筛子
* @return
*/
private static int diceThrow(){
return StdRandom.uniform(SIDES) + 1;
}
/**
* 掷N次筛子,两个筛子和的概率分布
* @param N
* @return
*/
private static double[] trackNDiceThrowsProbabilityResult(int N){
double[] dist = new double[SIDES*2+1];
for (int i = 0; i < N; i++) {
int dice1 = diceThrow();
int dice2 = diceThrow();
dist[dice1 + dice2] += 1.0;
}
for (int i = 2; i < dist.length; i++) {
dist[i] /= N;
}
return dist;
}
/**
* 最大的差距
* @param exactResults
* @param empiricalResults
* @return
*/
private static double maxDisparity(double[] exactResults, double[] empiricalResults){
double max_disp = Double.NEGATIVE_INFINITY;
int indexMax = Math.max(exactResults.length, empiricalResults.length);
for (int i = 2; i < indexMax; i++) {
double disp = Math.abs(exactResults[i] - empiricalResults[i]);
if (max_disp < disp) max_disp = disp;
}
return max_disp;
}
/**
* 查找足量的N
* @param disparity
* @return
*/
private static int findSufficientN(double disparity){
double[] theoretical_dist = diceExactProbabilityDistribution();
int N=35;
double[] experiment_dist;
do{
N += 1;
experiment_dist = trackNDiceThrowsProbabilityResult(N);
}while(maxDisparity(theoretical_dist,experiment_dist) > disparity);
return N;
}
}