1、给定一个等概率产生1-5的随机数rand1To5,要求不使用额外的随机函数实现等概率的产生1-7的随机函数rand1To7。
实现过程如下:
- rand1To5()等概率产生1,2,3,4,5
- rand1To5()-1 等概率产生 0,1,2,3,4
- (rand1To5()-1) * 5 等概率产生 0,5,10,15,20
- (rand1To5()-1) * 5 + rand1To5()-1 等概率产生 0,1,2,3,4,...,23,24 。这里是两次调用,不能化简。
- 如果步骤4产生的结果大于20,则重复步骤4,得到等概率的0,1,2...,20
- 对步骤5等概率的0,1,2...20 mod 7 得到等概率的 0,1,2,3,4,5,6
- 对步骤6得到的等概率 0,1,2,3,4,5,6 + 1 得到等概率的 1,2,3,4,5,6,7
public int rand1To7() {
int num = 0;
do {
num = (rand1To5() - 1) * 5 + rand1To5() - 1;
} while (num > 20);
return num % 7 + 1;
}
总结:其实我们可以利用这种思路产生任意的等概率随机数。比如,我们需要构建 1-50的等概率随机数,在步骤4中我们得到了0-24的等概率随机数,接下来我们执行 ((rand1To5()-1) * 5 + rand1To5()-1) * 25 + (rand1To5()-1) * 5 + rand1To5()-1 可以得到 0-624的等概率随机数,然后大于599的都不要,在对结果 mod 50 然后在加1,就得到1-50的等概率随机数了。
给定一个以p概率产生0,1-p概率产生1的随机函数rand01p(),实现等概率的0/1随机数函数
显然rand01p()生成01和10的概率均为p(1-p)
利用这个特性就可以实现01等概率的随机数了:
public int rand01() {
int num;
do {
num = rand01p();
} while (num == rand01p());
return num;
}
相关题目:
有两个随机数产生器,R1以0.7的概率产生1,以0.3的概率产生0,而R2以0.3的概率产生1,0.7的概率产生0.问如何组合这两种产生器,使新得到的随机数产生器以0.5的概率产生1,0.5的概率产生0。随机数产生器可复用。
R1 + R2
x | 0 | 1 | 2 |
p | 0.21 | 0.58 | 0.21 |
所以为0时输出0,为2时输出1,为1时继续迭代。
给定一个分类器p,它有0.5的概率输出1,0.5的概率输出0。Q1:如何生成一个分类器使该分类器输出1的概率为0.25,输出0的概率为0.75?Q2:如何生成一个分类器使该分类器输出1的概率为0.3,输出0的概率为0.7?
第一问,也即01概率之比为3:1,假设我们能生成一个0,1,2,3的等概率随机数,那么0,1,2时输出0;3时输出1。有01等概率生成0-3等概率可以参考前面的步骤实现,就是 rand01() * 2 + rand01()
第二问,01概率之比为7:3,同样我们生成一个0,1,2,3,4,5,6,7,8,9的等概率随机,然后0-6时输出0, 7-9时输出1。步骤和前面的一样,就不在赘述了。
现在有一个可以随机数1-9的均匀随机函数,要求推到出一个1-7的均匀随机函数。
分析:经历过上面的洗礼,我想这题应该很清晰了,就是丢掉8,9。
如果面试官接着问道,如果一直产生8,9怎么办?一直丢掉吗?
这里我给出一种我的想法,由1-9的等概率随机数,我们可以产生0-80的随机数,步骤和上面一样,那么我们 0-10输出1, 11-21生成2, ...,66-76输出7, 77-80丢弃,那么这样我们丢弃一个数的概率为 4/81比之前的2/9要小了。虽然这样丢弃一个数的概率变小了,但是每一个数至少要通过两次随机才可得到,不知是不是得不偿失。