给定一个函数,它产生的是1到5之间的随机整数,写一个函数,它产生的是1到7之间的随机整数。


当前回答

上面引用了一些优雅的算法,但这里有一种方法可以接近它,尽管它可能是迂回的。我假设的值是从0开始的。

R2 =给出小于2的随机数生成器(样本空间= {0,1}) R8 =给出小于8的随机数生成器(样本空间= {0,1,2,3,4,5,6,7})

为了从R2生成R8,您将运行R2三次,并将所有3次运行的组合结果作为3位二进制数使用。下面是R2运行三次时的值范围:

0, 0, 0 --> 0 . . 1, 1, 1 --> 7

现在要从R8生成R7,我们只需再次运行R7,如果它返回7:

int R7() {
  do {
    x = R8();
  } while (x > 6)
  return x;
}

迂回的解决方案是从R5生成R2(就像我们从R8生成R7一样),然后从R2生成R8,然后从R8生成R7。

其他回答

这里有很多解决方案没有产生均匀分布,许多评论指出了这一点,但这个问题并没有把它作为一个要求。最简单的解决方案是:

int rand_7() { return rand_5(); }

1 - 5范围内的随机整数显然在1 - 7范围内。从技术上讲,最简单的解决方法是返回一个常数,但那太琐碎了。

然而,我认为rand_5函数的存在是一个转移注意力的问题。假设问题是“生成一个均匀分布的伪随机数生成器,输出范围为1 - 7”。这是一个简单的问题(技术上不简单,但已经解决了,所以您可以查阅它)。

另一方面,如果问题被解释为你实际上有一个真正的随机数生成器,用于范围为1 - 5的整数(而不是伪随机),那么解决方案是:

1) examine the rand_5 function
2) understand how it works
3) profit

这相当于Adam Rosenfield的解决方案,但对一些读者来说可能更清楚一些。它假设rand5()是一个函数,返回1到5范围内的统计随机整数。

int rand7()
{
    int vals[5][5] = {
        { 1, 2, 3, 4, 5 },
        { 6, 7, 1, 2, 3 },
        { 4, 5, 6, 7, 1 },
        { 2, 3, 4, 5, 6 },
        { 7, 0, 0, 0, 0 }
    };

    int result = 0;
    while (result == 0)
    {
        int i = rand5();
        int j = rand5();
        result = vals[i-1][j-1];
    }
    return result;
}

How does it work? Think of it like this: imagine printing out this double-dimension array on paper, tacking it up to a dart board and randomly throwing darts at it. If you hit a non-zero value, it's a statistically random value between 1 and 7, since there are an equal number of non-zero values to choose from. If you hit a zero, just keep throwing the dart until you hit a non-zero. That's what this code is doing: the i and j indexes randomly select a location on the dart board, and if we don't get a good result, we keep throwing darts.

就像亚当说的,在最坏的情况下,它可以一直运行下去,但从统计上看,最坏的情况永远不会发生。:)

从一个扩大浮动范围的链接来到这里。这个更有趣。而不是我是如何得出结论的,我突然想到,对于一个给定的随机整数生成函数f,以“基数”b(在这种情况下是4,我会告诉为什么),它可以展开如下:

(b^0 * f() + b^1 * f() + b^2 * f() .... b^p * f()) / (b^(p+1) - 1) * (b-1)

这将把随机生成器转换为FLOAT生成器。我将在这里定义2个参数b和p。虽然这里的“基数”是4,但b实际上可以是任何东西,它也可以是无理数等p,我称之为精度是你想要的浮点生成器的良好粒度的程度。可以把这看作是对rand7的每次调用对rand5的调用数。

但我意识到,如果你把b设为底数+1(在这种情况下是4+1 = 5),这是一个最佳点,你会得到均匀的分布。首先摆脱这个1-5生成器,它实际上是rand4() + 1:

function rand4(){
    return Math.random() * 5 | 0;
}

为了达到这个目的,你可以用rand5()-1替换rand4

接下来是将rand4从整数生成器转换为浮点生成器

function toFloat(f,b,p){
    b = b || 2;
    p = p || 3;
    return (Array.apply(null,Array(p))
    .map(function(d,i){return f()})
    .map(function(d,i){return Math.pow(b,i)*d})
    .reduce(function(ac,d,i){return ac += d;}))
    /
    (
        (Math.pow(b,p) - 1)
        /(b-1)
    )
}

这将把我写的第一个函数应用到一个给定的rand函数。试一试:

toFloat(rand4) //1.4285714285714286 base = 2, precision = 3
toFloat(rand4,3,4) //0.75 base = 3, precision = 4
toFloat(rand4,4,5) //3.7507331378299122 base = 4, precision = 5
toFloat(rand4,5,6) //0.2012288786482335 base = 5, precision =6
...

现在,您可以将这个浮动范围(0-4 include)转换为任何其他浮动范围,然后将其降级为整数。这里我们的底是4,因为我们处理的是rand4,因此b=5的值会给你一个均匀分布。当b增长超过4时,你将开始在分布中引入周期性间隙。我测试了从2到8的b值,每个值都有3000分,并与原生数学进行了比较。随机的javascript,在我看来甚至比本机本身更好:

http://jsfiddle.net/ibowankenobi/r57v432t/

对于上面的链接,单击分布顶部的“bin”按钮以减小分箱大小。最后一个图表是原生数学。随机的,第四个d=5是均匀的。

在你得到浮动范围后,要么与7相乘并抛出小数部分,要么与7相乘,减去0.5并四舍五入:

((toFloat(rand4,5,6)/4 * 7) | 0) + 1   ---> occasionally you'll get 8 with 1/4^6 probability.
Math.round((toFloat(rand4,5,6)/4 * 7) - 0.5) + 1 --> between 1 and 7
int getOneToSeven(){
    int added = 0;
    for(int i = 1; i<=7; i++){
        added += getOneToFive();
    }
    return (added)%7+1;
}

你需要的函数是rand1_7(),我写了rand1_5(),这样你就可以测试它并绘制它。

import numpy
def rand1_5():
    return numpy.random.randint(5)+1

def rand1_7():
    q = 0
    for i in xrange(7):  q+= rand1_5()
    return q%7 + 1