随机数生成问题
给定随机生成整数1到5的函数,写出能随机生成整数1到7的函数
方法1:
rand5()*5+rand5(),得到[6,30]区间内25个数等概率分布
可以只用6~26之间的21个数,映射到1~7这7个数
27~30怎么办?抛弃掉
int rand7() { int i; while((i=rand5()*5+rand5())>26); return (i-3)/3; }
这样生成的1~7概率均匀,只是其和不等于1
方法2:
用rand5()生成一个5进制的数
假如有3位,那么每一位生成一个rand5(),这个数就是[0,444]上的均匀分布的整数
不过遗憾7不能整除5的幂次方,这样就无法均分7段
不过如果位数足够大,则遗漏的概率就会相当的小
类似问题
已知rand1()等概率返回0或者1,试写一个函数等概率返回[a,b]之间的整数
用二进制表示a与b,
得到a的位数,b的位数,
按位生成二进制数,如果超出了[a,b]范围则重新生成
(对于上一题,如果随机数生成器可以生成偶数范围的话,可以先构造rand1(),之后的问题即为本问题)
类似问题
已知rand7(),球rand10()
这可以转成第一个问题:先构造rand7()*7+rand7(),然后过滤,再平分
或者可以把rand7()先转成rand5()与rand2(),然后组合
int rand10() { int t1; int t2; do{ t1=rand7(); }while(t1>5); do{ t2=rand7(); }while(t2>2); return t1+5*(t2-1); }
推广:
已知randk(),求randn()
用k进制表示n,先求需要多少位,求解m:
k^m-1=n m=int(m)+1 int randn() { while(sum>n) { for(i=0;i<m;++i) bit i of sum=randk(); } }
理解这类题的关键知识:
每一位等概率分布 -> 这个数在整个域上也等概率分布
一个等概率分布[a,b]的子集合(例如[a+1,b-1])同样是等概率分布,只是子集合的概率和不为1,但不影响算法实现
ref:http://www.cnblogs.com/youxin/p/3351213.html