一. 给定一个a~b区间随机数,更改为c~d区间随机数
思路是先将a~b区间的数 转变 为0/1等概率生成器,利用能够包含c~d得到最小二进制位 重新生成 0~e ( 0 < c < d < e)的区间随机数,进而完成从 a~b随机 到 c~d随机 的转变。
例如:将1~5随机 变为 1~7随机
-
首先,调用random方法创建一个f1函数,用于生成区间1~5的随机整数。
public static int f1() {
return (int)(Math.random()*5)+1;//随机生成区间1~5的整数
}
-
第二步,将f1转化为0/1等概率随机生成器(即把a~b等分位两部分),当调用f2函数时,随机生成0或1。
public static int f2() {
int ans ;
do {
ans = f1();
} while (ans == 3) ;//0~2对应0, 4~5对应1, ans==3 则再次调用f1
return ans < 3 ? 0 : 1;
}
-
第三步,每一个f2所返回的值充当一个二进制位。(在这里,用3位二进制以表示生成0~7的等概率随机整数)
public static int f3() {
return (f2()<<2) + (f2()<<1) + (f2()<<0);//生成0~7随机数
}
-
最后一步,循环调用f3直至返回一个位于区间1~7的整数
public static int f4() {
int ans ;
do {
ans = f3();
} while (ans == 0); //若ans==0,则再次调用f3直至ans不为0
return ans;
}
-
简单的验证一下1000000次调用,1~7出现的概率分布。
public static void main(String[] args) throws IOException {
//给定一个f(a,b)等概率随机数,映射返回一个g(c,d)等概率随机数
int times = 1000000;
int[] count = new int[8];
for (int i = 0; i < times; i++) {
int index = f4();
count[index]++;
}
for (int i = 0; i < 8; i++) {
System.out.println("随机数"+i+"生成了:"+count[i]+"次");
}
}
-
输出结果:
随机数0生成了:0次
随机数1生成了:143132次
随机数2生成了:143031次
随机数3生成了:142630次
随机数4生成了:142429次
随机数5生成了:142740次
随机数6生成了:143160次
随机数7生成了:142878次
可以看出,1~7生成概率近乎相等。
二. 不等概率随机 到 0/1等概率随机
-
假定现有一个x会以如下概率固定返回0/1,不关注x的内容。
0 | 1 |
---|---|
P=0.83 | 1-P=0.19 |
public static int x() {
return Math.random() < 0.84 ? 0 : 1;
}
-
如何得到一个等概率返回0/1的y
0 | 1 |
---|---|
P=0.5 | 1-P=0.5 |
-
这里用到的依旧是二进制转换的思想:
11 | 10 | 01 | 00 |
---|---|---|---|
(1-P)² | P(1-P) | P(1-P) | P² |
-
不难看出,在这里只需要保留10和01(每当随机到11或00时,重新随机),即可得到两个等概率的数(10和01 其中 一个视做1 一个视做0)
public static int y() {
int ans;
do {
ans = x();
} while (ans == x()); //若两次x()相等,即出现00或11,重新随机
//ans = 01 或 ans = 10
return ans < 0.84 ? 0 : 1;
}
-
由此即可将一个固定概率的0/1转变为等概率0/1。