给定一个等概率随机产生1~5的随机函数rand1To5如下:
public int rand1To5()
{
return (int) (Math.random() * 5) + 1;
}
1~5无法表示1~7,所以我们需要将1~5扩展,形成更大的长度以便容得下1~7
1.R() 函数可以产生 1~~5
2.R()-1 函数可以产生0~~4
3.( R()-1 )*5函数可以产生0、5、10、15、20
4.( R()-1 )*5+R()-1 函数便可以产生0~~24,其中0~4刚好插入到0~5的空中,所以以此类推
5. 得到了可以容纳1~7的表达式,然后对其进行模7,可以产生0~6的表达式
6.最后即对上述进行加1即可。
问题:
到0~~24这步我们产生的都是等概率的,如果模7,那么有三组0~6,多出来一组0~4,也就是21,22,23,24模7产生的数
解决方案是,当产生了这些数,我们让其进行重新获取,直到获取到的数是0~20以内的,那么就相当于把0~~4这部分多出来的概率平摊到了前面三组之上
public int rand1To7()
{
int temp;
do{
temp=(rand1To5()-1)*5+rand1To5()-1;
}while(temp>20);
return temp%7+1;
}
public int rand01p()
{
// you can change p as you like
double p = 0.83;
return Math.random() < p ? 0 : 1;
}
除此之外不能使用任何额外的随机机制,请用rand01p实现等概率随机产生1~6的随机函数rand1To6。
尽管产生0和产生1的概率不相等,但是产生 0 1和产生1 0 的概率是一致的,P*( 1-P ) 和 ( 1-P )*P
所以我们只需要让函数第一次产生的和第二次产生的数不一样即可,如果产生的数一样,那么返回重做即可。
这样我们就得到了等概率产生0~~1的函数
然后我们再利用类似的方法等概率产生0~3,然后再次产生1~~6,分步来产生,当然还有更好的方法,见题目3
public int rand01()
{
int num;
do{
num=rand01p();
}while(num==rand01p());
return num==0 ? 1 : 0;
}
/**
* 将等概率的01转化为等概率的0~3
* */
public int rand03()
{
return rand01()*2+rand01();
}
/**
* 将等概率0~3转化为等概率的1~6
* */
public int rand16()
{
int temp;
do{
temp = rand03()*4+rand03();
}while(temp>11);
return temp%6+1;
}
public int rand1ToM(int m) {
return (int) (Math.random() * m) + 1;
}
除此之外不能使用任何额外的随机机制。有两个输入参数分别为m和n,请用rand1ToM(m)实现等概率随机产生1~n的随机函数rand1ToN。
public int rand1ToN(int n,int m)
{
int k =getBitM(n,m);//获取可以容纳n的m进制位数
int result;
while(true)
{
int temp =k;
result =0;
while(temp>=0)
{
result+=(rand1ToM(m)-1)*Math.pow(2, --temp);
}
if(result=0)
{
sum*=m;
++k;
}
return k;
}