[算法]Java实现 模拟掷骰子
来源:互联网 发布:mac是哪个国家的品牌 编辑:程序博客网 时间:2024/04/29 09:19
[算法]Java实现 模拟掷骰子
代码说明
1.计算掷两枚骰子所得点数之和的准确概率;
2.计算模拟掷N次所得两枚骰子点数之和的经验概率;
3.当经验概率与准确概率吻合到小数点后三位时输出数据。
完整源码
public class Crap2{ // 计算掷两枚骰子所得点数之和的准确概率 public static double[] Prob() { 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; for(int k=2;k<=2*SIDES;k++) { dist[k] /= 36.0; } return dist; } //计算模拟掷N次所得两枚骰子点数之和的经验概率 public static double[] testPro(double N){ int SIDES = 6; double[] b = new double[2*SIDES+1]; double t = N; while(N>0){ int m = 1+(int)(Math.random()*6); int n = 1+(int)(Math.random()*6); b[m+n] += 1.0; N--; } for(int i=2;i<=SIDES*2;i++){ b[i] /= t; } return b; } public static void main(String args[]) { int SIDES =6; double N = 64; double[] a = Prob(); double[] b = new double[SIDES*2+1]; int p =0; while(p==0){ b = testPro(N); p = 1; for(int i=2;i<=2*SIDES;i++){ // 反复对比,直到全部情况数据吻合度达到小数点后三位 if(Math.abs(a[i]-b[i])>.0001){ p = 0; break; } } N*=2; } //当经验概率与准确概率吻合到小数点后三位时输出数据 System.out.println("Test Times "+N); for(int i=0;i<=SIDES*2;i++){ System.out.println(i+" "+a[i]+" "+b[i]); } }}
输出结果(模拟)
Compiling Crap2.java....... -----------OUTPUT----------- Test Times 6.7108864E70 0.0 0.01 0.0 0.02 0.027777777777777776 0.0278392136096954353 0.05555555555555555 0.055485188961029054 0.08333333333333333 0.083392083644866945 0.1111111111111111 0.111125588417053226 0.1388888888888889 0.13884845376014717 0.16666666666666666 0.16670277714729318 0.1388888888888889 0.138930976390838629 0.1111111111111111 0.1111281514167785610 0.08333333333333333 0.0832940042018890411 0.05555555555555555 0.055494755506515512 0.027777777777777776 0.027758806943893433[Finished in 4.3s]
代码解释
- 关于存放概率的数组长度
int SIDES = 6; double[] dist = new double[2*SIDES+1];
,骰子有六面,掷两枚可以依次掷出总和为{2,3,4,5,6,7,8,9,10,11,12}
等一共11种结果,数组下标从0 开始标记,所以数组的长度在声明时需要声明成11+2 = 6*2+1 =
一共13的长度;
SIDES*2+1 - 换个更简单的思路可以这么想,物理情况下总和最低是
1+1=2
,最高是6+6=12
,存放12本质上是数据的第13个数据,因此声明长度为13的数组;
不用考虑具体的某一种情况的总和,因为i+j
总和可以出现的情况是有穷的
for(int i=1;i<=SIDES;i++) for(int j=1;j<=SIDES;j++) dist[i+j] += 1.0;
- 既然和的情况是有穷的,那么移植到模拟实验的部分,每次随机出来的两个数字m n,也就可以使用
m+n
将得到的和次数填充到double[] b = new double[2*SIDES+1]; b[m+n] += 1.0;
数组里; - 然后是测试部分,N控制着生成一个经验概率数组b[]所要进行地从[1,6]中随机取单个整数的次数,起始值设定为64(2^6),没什么特殊意义想要一个大于36的2的倍数而已;
- 反复对比,
N*=2
直到全部情况数据经验概率与准确概率吻合到小数点后三位时输出,其中p是用来控制循环的变量,当两种概率的吻合度并没有达到小数点后三位时,p始终置为0保证循环继续使N增大,N增大物理意义上就使得模拟掷骰子的次数上升了;直到全部情况的吻合度达到要求,p置1跳出循环;
int p =0; while(p==0){ b = testPro(N); p = 1; for(int i=2;i<=2*SIDES;i++){ // 反复对比,直到全部情况数据吻合度达到小数点后三位 if(Math.abs(a[i]-b[i])>.0001){ p = 0; break; } } N*=2; }
- 吻合度达到小数点后三位的判断使用
if(Math.abs(a[i]-b[i])>.0001){}
,计算两个数值差的绝对值,当这个绝对值小于.0001即表示吻合;
代码心得
- 数组长度那里一开始我以为2*SIDES就足够了,一开始没有想到0和1是不会出现的,下标即和这种思路赋予了数组下标丰富的物理意义,很巧妙以后也要多利用,用白话说起来就是数组下标是9的位置存着的值就是9这个数字出现的次数;
- 同时,模拟测试部分,不断增加N的大小使用P来控制循环也是经典套路了,真是很好用啊!我觉得按照这种思路比较容易把握p的变化时刻以及循环内外的赋值,也就是最好从里往外写;
- 参考下面的代码,最里面的if是循环结束的控制条件,加了break表示的是这种情况只要发生一次我就不需要继续我的外层for循环了,这里的for循环是为了将全部的数据进行吻合度的匹配,如果已经出现了不符合条件的就不需要遍历剩余的元素了;因此,既然直到目前为止还没有出现符合全部吻合度的N,那么外层的while循环就必须继续….
int p =0; while(p==0){ p = 1; for(){ if(){ p = 0; break; } } }
0 0
- [算法]Java实现 模拟掷骰子
- 编程算法之模拟法-掷骰子
- 模拟掷骰子
- python模拟掷骰子
- Java实现-骰子求和
- 【NOIP2012模拟10.31】掷骰子
- 【NOIP2012模拟10.31】掷骰子
- 模拟骰子
- 模拟骰子
- java界面实现骰子比赛
- JAVA实现一个掷骰子,及三个数取最小
- des算法java模拟实现
- 【程序12】模拟掷骰子游戏
- JZOJ3072. 【NOIP2012模拟10.31】掷骰子
- 【NOIP 模拟题】掷骰子(dp)
- JZOJ【3072】【NOIP2012模拟10.31】掷骰子
- java界面实现骰子比赛改进
- 模拟投骰子
- Aisan demand of film faced plywood will be climbing
- python + opencv 环境搭建
- android studio使用baidu map
- P122 .6 大小写转换
- 涉足计算机视觉领域要知道的~ (part1)
- [算法]Java实现 模拟掷骰子
- 浅析GLib
- UVA11538俩皇后可以相互攻击的方法,使用平方和公式将时间复杂度降到o(1)
- C++ STL中stack/queue的使用
- 类与对象
- Ubuntu系统日志配置 /var/log/messages
- 要开始写博客了呵呵哒
- Dell m4800 装Ubuntu 14.04 无线网卡驱动的问题
- IText实现Html转PDF itextpdf-5.5.5.jar