先占坑。以后再修改
昨天遇到一道题, Given int Rand(1) = 0或者 1- uniformly distributed, write a function to implement Rand(29) - uniformly distributed。
由于本科时概率没学好,挂了。回来网上一查资料发现有类似的题目 - Given Rand(5) = {1, 2, 3, 4, 5}, 求Rand(7)。
求Rand7的代码是
public static int random7() { int val = (random5() - 1) * 5 + (random5() - 1); return val < 21 ? val % 7 + 1 : random7();}
思路其实是把 1 - 5的数字映射到 1-7的范围,只要是uniformly distributed就行, 我们可以不在乎这 1 - 7的概率是 4%, 2 % , 还是 1%, 只要他们相等, 多余的部分我们再舍弃掉。比如计算范围是 1 - 10
- 我们可以取 1 ,2, 3 ,4 ,5 ,6 ,7, 舍弃 8 - 10 (舍弃的方法是再call一次random函数,程序有可能死循环,但从概率上来看死循环几率极小)
- 也可以取 4, 5, 6, 7, 8, 9, 10,舍弃 1 - 3, 但计算答案的时候 return val - 3
以上代码是一个解,我们还可以有其他的解。 比如以下,
public static int random7() { int val = (random5() - 1) + (random5() - 1) * 5 + (random5() - 1) * 25; return val < 119 ? val % 7 + 1 : random7();}
原理就是,只要把random5()得到的数字均匀映射到一串大于7的连续数字里。
所以回到这个题目,Given rand(1)实现 rand(29),其中 rand1() = 0 或者 1,每次只有两个数,所以我们可以使用以下代码来映射到0 - 31, 再舍弃30 和31就可以了:
public static int rand29() { int val = rand1() + rand1() * 2 + rand1() * 4 + rand1() * 8 + rand1() * 16; return val < 29 ? val: rand29();}
2/25/2016
今天又看到有一个公式,假如给定m 和 n以及一个rand(1),那么求一个在m到n中间的数,可以用 rand(1) * (n - m) + n。这里题目不要求uniform distribution的话好像也可以这么做。
Reference:
http://www.growingwiththeweb.com/2014/03/given-random5-implement-random7.html
http://www.careercup.com/question?id=12426697