Rand7 from Rand5: Implement a method rand7()
given rand5()
. That is, given a method that generates a random number between 0 and 4 (inclusive), write a method that generates a random number between 0 and 6 (inclusive).
Hints: #505, #574, #637, #668, #697, #720
解法
rand5()
的范围是[0, 4]
,先看看那么两个rand5()
相加是否能够等价rand10()
即[0, 9]
。
结果 | 组合 | 概率 |
---|---|---|
0 | 0 + 0 | 0.04( 0.2 * 0.2) |
1 | 1 + 0, 0 + 1 | 2 * 0.04 = 0.08 |
2 | 1 + 1, 0 + 2, 2 + 0 | 3 * 0.04 = 0.12 |
3 | 1 + 2, 2 + 1, 0 + 3, 3 + 0 | 4 * 0.04 = 0.16 |
4 | 1 + 3, 3 + 1, 0 + 4, 4 + 0, 2 + 2 | 5 * 0.04 = 0.20 |
5 | 1 + 4, 4 + 1, 2 + 3, 3 + 2 | 4 * 0.04 = 0.16 |
6 | 3 + 3, 2 + 4, 4 + 2 | 3 * 0.04 = 0.12 |
7 | 3 + 4, 4 + 3 | 2 * 0.04 = 0.08 |
8 | 4 + 4 | 0.2 * 0.2 = 0.04 |
可以每个结果的概率并不相同,所以不能成立。其实同理,相乘也不能成立。
如果对结果取模,那么分布就变成了:
结果 | 组合 | 概率 |
---|---|---|
0,7 (7 % 7 = 0) | 0 + 0, 3 + 4, 4 + 3 | 3 * 0.04 = 0.12 |
1,8 (8 % 7 = 1) | 1 + 0, 0 + 1, 4 + 4 | 3 * 0.04 = 0.12 |
2 | 1 + 1, 0 + 2, 2 + 0 | 3 * 0.04 = 0.12 |
3 | 1 + 2, 2 + 1, 0 + 3, 3 + 0 | 4 * 0.04 = 0.16 |
4 | 1 + 3, 3 + 1, 0 + 4, 4 + 0, 2 + 2 | 5 * 0.04 = 0.20 |
5 | 1 + 4, 4 + 1, 2 + 3, 3 + 2 | 4 * 0.04 = 0.16 |
6 | 3 + 3, 2 + 4, 4 + 2 | 3 * 0.04 = 0.12 |
回发现概率分布还是不均匀。
得想一个办法将各种结果出现的概率弄成一致,如果这样 5 * rand5() + rand5()
:
因子1 | 因子2 | 结果 |
---|---|---|
0 | 0 | 0 |
0 | 5 | 5 |
0 | 10 | 10 |
0 | 15 | 15 |
0 | 20 | 20 |
1 | 0 | 1 |
1 | 5 | 6 |
1 | 10 | 11 |
1 | 15 | 16 |
1 | 20 | 21 |
2 | 0 | 2 |
2 | 5 | 7 |
2 | 10 | 12 |
2 | 15 | 17 |
2 | 20 | 22 |
3 | 0 | 3 |
3 | 5 | 8 |
3 | 10 | 13 |
3 | 15 | 18 |
3 | 20 | 23 |
4 | 0 | 4 |
4 | 5 | 9 |
4 | 10 | 14 |
4 | 15 | 19 |
4 | 20 | 24 |
可以发现,结果出现的次数都是一次,也就是概率相同。那么,我们可以抛弃掉[21, 24]这4个结果,在[0, 20]之间 % 7,代码:
|
|
为什么这样做概率是均匀的?我们可以把代码做一个转换,因为已知rand5(5) + rand(5)
能够得到一个均匀分布的[0, 24]的区间,那么就等价于rand25()
,然后我们把 % 7 这个操作去掉,把代码变成这样:
|
|
假设每次调用rand25()
的返回结果是0, 1, 2, 3, ..., 24, 0, 1, 2, ..., 24
,那么调用rand21()
的记录就是:
rand21()结果 | rand25()调用结果 |
---|---|
0 | 0 |
1 | 1 |
2 | 2 |
… | … |
20 | 20 |
0 | 21, 22, 23, 24, 0,结果取0 |
1 | 1 |
2 | 2 |
… |
可以看到rand21()
的结果的分布都是均匀的,所以解法提到的方法是可行的。
评论