刚开始看题目没有很好的理解题目的意思,后来仔细阅读题目,才发现题目中最重要的两个字是均匀。
首先我们先考虑rand2()来完成rand4()。
首先大家可能都会想到用相加的方法进行处理,构造出符号条件的结果。
rand2()+rand2():这样是完不成题目所要求的, 构造rand2()-1+rand2()
1+1=2 1-1+1=1
1+2=3 1-1+2=2
2+1=3 2-1+1=2
2+2=4 2-1+2=3 此构造出了rand3(),但不均匀
(rand2()-1)*2+rand2()
(1-1)*2+1=1
(1-1)*2+2=2
(2-1)*2+1=3
(2-1)*2+2=4 构造出的结果完全满足要求,即为rand4(),每个值的概率也是均匀的。
经过多次举例,得到了下面这个公式,大家却不知下面这个公式对错与否,可先举例尝试。
(randX()-1)*Y+randY(); 可得到在区间[1,X*Y]区间内的一个均匀整数。
OK,说完举例是这样的后,现在进一步说明原因,
以(rand7()-1)*7+rand7()为例证,
rand7()={1,2,3,4,5,6,7}
rand7()-1={0,1,2,3,4,5,6}
(rand7()-1)*7={0,7,14,21,28,35,42}
X和Y是两个相互不相关的部分,按照概率论的说法,这两者是相互不独立的。
能得出[1,49]这个区间的所有数是符合均匀概率的。
从这引申到[1,X*Y]区间上必然每个数也是等概率的。
现在题目转换为:由rand49()怎么得出rand10()。
明显看出49不是10的倍数,不能够均匀缩小到一个长度为10的区间上,保证每个整数的概率相等。
因此这里涉及到拒绝采样。不懂的同学可以自己查资料看看。
我们构造了一个rand49(),那我们就可以取前40个概率相等的数字进行处理。
int num=(rand7()-1)*7+rand7();
while(num>40){
num=(rand7()-1)*7+rand7();
}
在这个过程中我们限制只取[1,40]区间的数,最后利用区间缩小办法,即1+(num-1)%10保证了区间的限制要求。
优化问题
由于存在[41,49]的未命中区间,因此就需要尽可能的缩小未命中的区间,以达到优化的目的。
这样就能回答题目中的附加问,怎么尽可能减少调用rand7()的次数。