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


当前回答

如果我们考虑尝试给出最有效答案的附加约束,即给定一个长度为m(1-5)的均匀分布整数的输入流I,输出一个长度为m(1-7)的均匀分布整数的流O,长度为L(m)。

最简单的分析方法是将流I和O分别视为5元数和7元数。这是通过主答案的思想来实现的,即取流a1, a2, a3,…- > a1 + a2 + 5 * 5 ^ 2 * a3 + . .流O也是如此。

然后如果我们取长度为m的输入流的一段,选n s.t, 5^m-7^n=c,其中c>0,且尽可能小。然后有一个从长度为m的输入流到1到5^m的整数的统一映射,还有一个从1到7^n的整数到长度为n的输出流的统一映射,当映射的整数超过7^n时,我们可能不得不从输入流中丢失一些情况。

这就给出了L(m)的值约为m (log5/log7)也就是。82米。

上述分析的难点是方程5^m-7^n=c,它不容易精确求解,而在1到5^m的均匀值超过7^n的情况下,我们失去了效率。

问题是如何接近m (log5/log7)的最佳可能值。例如,当这个数字接近一个整数时,我们能否找到一种方法来实现这个精确的整数值输出?

如果5^m-7^n=c,那么从输入流中,我们有效地生成了一个从0到(5^m)-1的均匀随机数,并且不使用任何高于7^n的值。但是,这些值可以被保存并再次使用。它们有效地生成了从1到5^m-7^n的统一数字序列。所以我们可以尝试使用这些,并将它们转换成7位数,这样我们就可以创建更多的输出值。

如果我们让T7(X)是由大小为X的均匀输入导出的随机(1-7)整数的输出序列的平均长度,并假设5^m=7^n0+7^n1+7^n2+…+ 7 ^ nr + s, s < 7。

那么T7(5^m)=n0x7^n0/5^m + ((5^m-7^n0)/5^m) T7(5^m-7^n0)因为我们有一个无长度序列,概率为7^n0/5^m,残差长度为5^m-7^n0,概率为(5^m-7^n0)/5^m)。

如果我们一直代入,我们得到:

T7(5^m) = n0x7^n0/5^m + n1x7^n1/5^m + ... + nrx7^nr/5^m  = (n0x7^n0 + n1x7^n1 + ... + nrx7^nr)/5^m

因此

L(m)=T7(5^m)=(n0x7^n0 + n1x7^n1 + ... + nrx7^nr)/(7^n0+7^n1+7^n2+...+7^nr+s)

另一种说法是:

If 5^m has 7-ary representation `a0+a1*7 + a2*7^2 + a3*7^3+...+ar*7^r
Then L(m) = (a1*7 + 2a2*7^2 + 3a3*7^3+...+rar*7^r)/(a0+a1*7 + a2*7^2 + a3*7^3+...+ar*7^r)

最好的情况是上面的原始情况,即5^m=7^n+s,其中s<7。

然后机械师》(5 ^ m) = nx (7 ^ n) / (7 ^ n + s) = o (n + 1) = m (Log5 / Log7) + o(1)美国之前。

最坏的情况是我们只能找到k和s.t 5^m = kx7+s。

Then T7(5^m) = 1x(k.7)/(k.7+s) = 1+o(1)

其他情况介于两者之间。看看对于很大的m,我们能做得多好,也就是说,我们能多好地得到误差项,这将是很有趣的:

T7(5^m) = m (Log5/Log7)+e(m)

一般来说,似乎不可能实现e(m)=o(1)但希望我们可以证明e(m)=o(m)。

整个问题取决于5^m的7位数字对不同m值的分布。

我相信有很多理论涵盖了这一点,我可能会在某个时候看一看并报告。

其他回答

假设rand(n)在这里表示“从0到n-1均匀分布的随机整数”,下面是使用Python的randint的代码示例,它具有这种效果。它只使用randint(5)和常量来产生randint(7)的效果。其实有点傻

from random import randint
sum = 7
while sum >= 7:
    first = randint(0,5)   
    toadd = 9999
    while toadd>1:
        toadd = randint(0,5)
    if toadd:
        sum = first+5
    else:
        sum = first

assert 7>sum>=0 
print sum

以下是我的回答:

static struct rand_buffer {
  unsigned v, count;
} buf2, buf3;

void push (struct rand_buffer *buf, unsigned n, unsigned v)
{
  buf->v = buf->v * n + v;
  ++buf->count;
}

#define PUSH(n, v)  push (&buf##n, n, v)

int rand16 (void)
{
  int v = buf2.v & 0xf;
  buf2.v >>= 4;
  buf2.count -= 4;
  return v;
}

int rand9 (void)
{
  int v = buf3.v % 9;
  buf3.v /= 9;
  buf3.count -= 2;
  return v;
}

int rand7 (void)
{
  if (buf3.count >= 2) {
    int v = rand9 ();

    if (v < 7)
      return v % 7 + 1;

    PUSH (2, v - 7);
  }

  for (;;) {
    if (buf2.count >= 4) {
      int v = rand16 ();

      if (v < 14) {
        PUSH (2, v / 7);
        return v % 7 + 1;
      }

      PUSH (2, v - 14);
    }

    // Get a number between 0 & 25
    int v = 5 * (rand5 () - 1) + rand5 () - 1;

    if (v < 21) {
      PUSH (3, v / 7);
      return v % 7 + 1;
    }

    v -= 21;
    PUSH (2, v & 1);
    PUSH (2, v >> 1);
  }
}

它比其他的稍微复杂一点,但我相信它最小化了对rand5的调用。与其他解决方案一样,它有小概率会循环很长时间。

上面引用了一些优雅的算法,但这里有一种方法可以接近它,尽管它可能是迂回的。我假设的值是从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。

算法:

7可以用3位的序列表示

使用rand(5)随机地用0或1填充每一位。 例如:调用rand(5)和

如果结果是1或2,则用0填充位 如果结果是4或5,则用1填充位 如果结果是3,则忽略并重新执行(拒绝)

这样,我们可以用0/1随机填充3位,从而得到1-7中的数字。

编辑:这似乎是最简单和最有效的答案,所以这里有一些代码:

public static int random_7() {
    int returnValue = 0;
    while (returnValue == 0) {
        for (int i = 1; i <= 3; i++) {
            returnValue = (returnValue << 1) + random_5_output_2();
        }
    }
    return returnValue;
}

private static int random_5_output_2() {
    while (true) {
        int flip = random_5();

        if (flip < 3) {
            return 0;
        }
        else if (flip > 3) {
            return 1;
        }
    }
}
int randbit( void )
{
    while( 1 )
    {
        int r = rand5();
        if( r <= 4 ) return(r & 1);
    }
}

int randint( int nbits )
{
    int result = 0;
    while( nbits-- )
    {
        result = (result<<1) | randbit();
    }
    return( result );
}

int rand7( void )
{
    while( 1 )
    {
        int r = randint( 3 ) + 1;
        if( r <= 7 ) return( r );
    }
}