文章目录
- 约定条件说明
- 解决方案
- 构造 0 1 发生器函数 f2()
- 计算需要几个二进制位
- 验证 2-10 等概率返回某个整数
- 总结
约定条件说明
- 假定 f() 是一个函数,保证 [1, 5] 范围内等概率返回一个整数
- 实现 2-10 等概率随机不能使用
Math.random()
函数,只能使用函数 f()。
解决方案
- 首先这个函数 f() 是给定的条件,正常直接调用就好,但是为了后面能够验证,所以这里还是实现一下。如下:
// 假定 f() 是一个函数,保证 [1, 5] 范围内等概率返回一个整数
private int f(){
return (int)(Math.random() * 5) + 1;
}
构造 0 1 发生器函数 f2()
- 这里可以由函数 f() 构造一个 0 1 发生器,保证等概率返回 0 和 1。
// 由函数 f() 得到 0 1 发生器函数 f2()(等概率返回 0 和 1)
private int f2(){
int ran = 0;
do {
ran = f();
}while (ran == 3);
// 1 or 2 -> 0
// 4 or 5 -> 1
return (ran < 3 ? 0 : 1);
}
将返回 3 的概率均分到返回 1 2 4 5 上即可。这里也不做验证了,同学们可以自己验证下,验证可以参考 【算法学习系列】02。
计算需要几个二进制位
- 2-10 等概率随机可以转化为
0-8 等概率随机再加上2
。 - 0-8 一共有 9 个数,故需要 4 个二进制位。因为 3 个二进制位的最大值是 111(十进制的 7),无法取到 8 这个整数,
故需要 4 个二进制位
。 - 使用 0 1 发生器等概率随机生成某个 4 位二进制数,并将二进制数大于 8 的概率均分到 0-8 上即可。
代码如下:
// 实现函数g():[2, 10]等概率返回一个整数的功能
private int g(){
// 二进制:0000-1111 十进制:0-15
int ran = (f2() << 3) + (f2() << 2) + (f2() << 1) + f2();
// 将大于 8 的数的概率均分到 0-8 上
while (ran > 8){
ran = (f2() << 3) + (f2() << 2) + (f2() << 1) + f2();
}
// 0-8 -> 2-10
return (ran + 2);
}
验证 2-10 等概率返回某个整数
做十万次样本测试,声明一个长度为11的数组,依次保存每个整数出现的次数。如下:
// 验证 2-10 等概率随机
private void random2To10(){
int count = 0, testCount = 100000;
int[] ranCount = new int[11];
for (int i = 0;i < testCount;i++){
// g() 返回 2-10 中某个数
int ran = g();
ranCount[ran]++;
}
// 打印某个数出现的次数
for (int i = 0;i < ranCount.length;i++){
System.out.println(":> " + i + " 出现的次数为:" + ranCount[i]);
}
}
验证结果如下:
可以看到 0 和 1 出现的次数为 0,2-10 中每个数出现的次数都基本认为是一致的,故验证成功。
总结
所以根据上面的验证,由此可以进一步推导出存在:[a, b]等概率随机,实现:[c, d]等概率随机
的解决方案。
技术永不眠!下期有缘再见!