问题
从1~5随机到1~7随机:即给定一个方法f,该方法能够等概率的返回1~5之间的整数(包括a和b),要求不用其他随机方法只能用f方法,使得等概率返回1~7之间的整数(包括c和d)。
解答
基本思路
第一步:利用f方法实现等概率返回0和1。由于f方法能够等概率返回1~5之间的整数,这个时候我们可以写一个新的方法f2,内部去调用f方法,拿到f方法的返回结果x,由于1~5之间有5个数,所以我们可以这样处理:如果x的值是1或者2,则f2方法返回0;如果x的值是4或者5,则f2方法返回1;如果x的值是3,则重新调用f方法并将返回值重新赋值给x,直到x的值不为3。这样经过改造后,相当于f方法返回的1、2、4、5是等概率的,也就做到了0和1等概率。
第二步:由于7用二进制表示为111,有三位,所以这个时候可以写一个新的方法f3,内部我们只需要调用三次f2方法,然后再利用二进制位运算中左移的方式将这三次调用的结果加起来,就得到了0~7的值。
第三步:由于题干要求1~7随机,所以这个时候我们可以再写一个新的方法f4,内部去调用f3方法,拿到返回结果后进行判断,如果返回值是0,则重新调用f3,直到返回结果不为0为止,这样就做到了1~7随机。
代码示例
public class RandomFromAbToCd {
public static int f() {
return (int) (Math.random() * 5) + 1;
}
public static int f2() {
int num = f();
while (num == 3) {
num = f();
}
return num <= 2 ? 0 : 1;
}
public static int f3() {
// 利用位运算中的左移将三次结果加起来,其中f2() << 0可以简写为f2(),这里只是为了格式对称
return (f2() << 2) + (f2() << 1) + (f2() << 0);
}
public static int f4() {
int num = f3();
while (num == 0) {
num = f3();
}
return num;
}
public static void main(String[] args) {
int maxTimes = 10000000;
int[] arr = new int[8];
for (int i = 0; i < maxTimes; i++) {
int num = f4();
arr[num]++;
}
for (int i = 0; i < arr.length; i++) {
System.out.println(i + "出现了" + arr[i] + "次");
}
}
}
运行结果为:
0出现了0次
1出现了1428801次
2出现了1427610次
3出现了1428738次
4出现了1429379次
5出现了1429315次
6出现了1428680次
7出现了1427477次
思考
从1~5随机到1~7随机只是这一类题型的具体代表,可以概括为从a~b随机到c~d随机,其中a、b、c、d都是整数,这种题型都可以用上面的算法去解决。