题目描述
假如有一个函数 rand5( ) 能等概率生成1-5之间的整数,如何利用 rand5( ) 来实现rand7( )?
rand7函数的要求是能够等概率生成1-7之间的整数。
题目分析
这是今天的一道笔试题,当时考虑一定是和概率相关的,如生成rand5( ) 那么每个数的概率是1/5, 而 rand7( ) 每个数出现概率为 1/7. 所以一次使用随机数 rand5( ) 是怎么也做不到题目要求的。 那我们就考虑两次及以上产生随机数并做一定运算产生新数,从而映射到1-7.
那么问题来了,两次使用rand5( ), 如何计算产生 等概率 的新数?我认为这是这道题的关键之处,举个栗子:
两次生成rand5(),并且相加,即:rand5()+rand5(),会得到2-10的数,这是很显而易见的,然而这十个数字是等概率产生的吗? 显然不是,因为1,2,3,4,5 和1,2,3,4,5想加,结果2-10,但是 2+3 和 1+4 都是5 ,所以产生的新数不是等概率的。那如何产生等概率数?
算法1
一种常见算法是这样的:
两次使用rand5( ),可以生成1-25的所有数。5 * (rand5( ) - 1) 可以生成 0 5 10 15 20,而 (rand5( ) - 1) 则可以生成0 1 2 3 4。则:5 * (rand5( ) - 1) + (rand5( ) - 1) 可生成均匀的0 1 2 3 4 5…23 24,用数学表达的话就是 [0, 24]。
代码如下
function rand7()
{
while (true)
{
//得出[0,24]的平均分布
int i = 5 * (rand5() - 1) + (rand5() - 1);
//只取前21个, 前21个也是平均分布,然后mod 7
if( i < 21 )
return i % 7 + 1;
}
}
算法2
同样的思路,另一种算法:先用2个rand5产生rand10(注意,不是相加),然后从rand10产生rand7。
// 产生0 1 随机数
int rand01( )
{
int i = rand5( );
while (i > 4)
i = rand5( );
return i % 2;
}
// 产生 0, 1, 2, 3, 4, 5, 6, 7 等概率数
int rand07( )
{
return rand01( ) * 2 + rand01( ) * 1 + rand01( );
}
// 产生 1, 2, 3, 4, 5, 6, 7 等概率数
int rand7( )
{
int i = rand07();
while (i == 0)
i = rand07();
return i;
}
算法3
还有一种方法,可以直接把概率问题转化到矩阵中解决。(该方法来自网络)具体代码查看:
http://www.nowamagic.net/librarys/veda/detail/2172