将随机范围从1-5扩展到1-7

时间:2011-02-25 04:30:08

标签: algorithm random

Expand a random range from 1–5 to 1–7

int i;
do
{
  i = 5 * (rand5() - 1) + rand5();  // i is now uniformly random between 1 and 25
} while(i > 21);
// i is now uniformly random between 1 and 21
return i % 7 + 1;  // result is now uniformly random between 1 and 7

为什么我不能放

i = 6*(rand5()-1);

有?为什么我们需要“*”和“+”操作

3 个答案:

答案 0 :(得分:4)

(rand5() - 1)返回0到4之间的数字。如果将这些数字中的任何一个乘以6,您将只得到5个数字中的一个(0,6,12,18或24)。

以另一种方式执行此操作可确保输出中出现1到21之间的所有可能整数(概率均匀)。

修改

5 *(rand5() - 1)会给你一个(0,5,10,15,20)。然后我们在1到5之间添加另一个随机整数,从而填补空白。我们现在有一个1到25之间的随机整数,具有统一的概率。由于我们需要1到21的范围,我们拒绝超过21的任何内容并重试。

答案 1 :(得分:1)

关键是rand5()是 random ,原始表达式中的每个调用都会返回不同的答案。这就是rand5() + rand5()2*rand5()不同的原因。

同样:5 * (rand5() - 1) + rand5()5*rand5() + rand5() - 5,但与6*rand5() - 5不同,因为每次调用rand5()都会产生不同的结果。

答案 2 :(得分:0)

这是python中的一个例程,它具有统一性的经验测试。

首先是1:5范围内的随机生成器:

>>> def r5(): return randrange(5) + 1

>>> bins = dict((i, 0) for i in range(9))
>>> pp(bins)
{0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0}
>>> for i in range(999999): bins[r5()] += 1

>>> pp(bins)
{0: 0, 1: 199752, 2: 200378, 3: 200452, 4: 199580, 5: 199837, 6: 0, 7: 0, 8: 0}

注意值为1..5的bin计数。

使用的算法是,如果按顺序生成两个r5()数,那么它们是5 * 5 = 25种可能的排列,它们都具有相同的发生可能性。如果我们采用这些排列的任何常数21,我们可以看出我们生成的perm是否在21中,并将每三个值转换为七个整数中的一个返回。如果我们生成一个不在21中的排列,那么我们需要再获得两个r5()值并重复。

r7的代码取决于我为速度做全局的一些常量:

>>> list5 = [1,2,3,4,5]
>>> perm21 = [(x,y) for x in list5 for y in list5 ][:21]
>>> set21 = set(perm21)
>>> def r7():
    r = (6,6)
    while r not in set21:
        r = (r5(), r5())
    return (perm21.index(r) // 3) + 1

>>> bins = dict((i, 0) for i in range(9))
>>> for i in range(999999): bins[r7()] += 1

>>> pp(bins)
{0: 0,
 1: 142857,
 2: 143558,
 3: 143046,
 4: 142699,
 5: 142786,
 6: 142439,
 7: 142614,
 8: 0}
>>> 

让我们试着看看10次试验的传播:

>>> bins = dict((i, 0) for i in range(9))
>>> for i in range(9999999): bins[r7()] += 1

>>> pp(bins)
{0: 0,
 1: 1429821,
 2: 1429851,
 3: 1427350,
 4: 1428478,
 5: 1425243,
 6: 1429618,
 7: 1429638,
 8: 0}

对我来说没问题: - )