关键是 Uniform. 如果2 * Rand7()
变为[2, 14]
再减1变为[1, 13]
,生成的各个数字的概率不是相等的;e.g. rand2()
等概率生成1,2, 但是对于 (rand2()-1) + rand2()
:1
2
3
4
5
6rand2() - 1 + rand()2 = ?
{0, 1} [1, 2]
0 1 1
0 2 2
1 1 2
1 2 3
不是等概率的;
但是如果 (rand2()-1)*2 + rand2()
:1
2
3
4
5
6(rand2() - 1)*2 + rand()2 = ?
{0, 2} [1, 2]
0 1 1
0 2 2
2 1 3
2 2 4
rand2()
生成rand4()
.
为什么 上面乘2 之后就可以了? 对于rand3()
: {1, 2, 3}
, 如果按照相同的操作: (rand3() - 1) * 3 + rand3()
:1
2
3
4
5
6
7
8
9
10
11
12(rand3() - 1)*3 + rand()3 = ?
{0,1,2} * 3 {1, 2, 3}
{0, 3, 6}
0 1 1
2 2
3 3
3 1 4
2 5
3 6
6 1 7
2 8
3 9
(rand3() - 1) * 3 + rand3()
刚好可以等概率生成 {0, ..., 9}
.
可以看出, (randN() - 1) * N
对于原randN()
来说,刚好上升一个维度并且接壤上,得到的结果就是等概率的。
回到前面的rand2()
生成rand4()
,那么反过来用rand4()
重新回到rand2()
: rand4() % 2 + 1
:
1
2
3
4
5rand4() % 2 + 1 = ?
1 2
2 1
3 2
4 1
同理,也可以用rand6()
生成rand2()
:1
2
3
4
5
6
7rand6() % 2 + 1 = ?
1 2
2 1
3 2
4 1
5 2
6 1
i.e. rand2N()
都可以通过rand2N() % 2 + 1
得到rand2()
。 所以,回到这道题,我们可以先凑出rand10N()
,然后再通过 rand10N() % 10 + 1
来获得 rand10()
.
rand7()
直接变为(rand7()-1) * 7 + rand7()
, [0, 6]*7 + [1, 7]
得到[1, 49], 明显超过了
10; 随机得到一个
[1, 10N]的范围内的数之后就可以
%10操作往
[1,10]`上靠.
[1, 49]
: 首先要得到[1,10N]
, 如果要操作次数最少,当然是最容易得到的最好:[1,40]
范围最大;[1, 40]
的%10
操作 => 等概率的[0, 9]
;[0, 9] + 1
=>[1, 10]
, i.e.rand10()