给定了一个能够生成1~n的随机函数,求一个生成1~m的随机函数。为了方便,假设n<m,m<n*n。
有一种比较通用,但不一定高效的方法是:
1、 z = n *( rand_n() - 1 )+rand_n();此时z的取值范值范围是[1,n*n],而且是等概率的取值。
2、 剩下的就是将[1,n*n]映射到[1,m]。因为m<n*n,所以只需要以m个数作为一个取值区间,从小到大进行映射,到最后的几个数不满m个,就舍弃,重新取值。
所以,首先确定最后舍弃的那几个数的个数,re = n*n%m,
3、最后,当z的值在(n*n - re, n*n]之间的时候,重新取值。在[1,n*n-re]时,对m取余,加一即可。
int rand_m()
{
int z;
int re = n*n%m;
do
{
z = n * ( rand_n() - 1 ) + rand_n();
} while(z > n*n - re)
return z%m + 1;
}
这种方法,采用舍弃一部分不符合要求的数值的方式,原则上舍弃的数值的比例越少越好,最差的情况是舍弃约50%的数值。比如z的范围是[1,10],m是[1,6],那么7,8,9,10都是要舍弃的。