【问题标题】:How do you generate a random number in between 1 and 7 by using a function which generates 1 to 5 [duplicate]如何使用生成 1 到 5 的函数生成 1 到 7 之间的随机数 [重复]
【发布时间】:2011-08-06 13:56:04
【问题描述】:

可能重复:
Expand a random range from 1-5 to 1-7

我理解了使用拒绝抽样的解决方案,即

public static int rand7() {
    while (true) {
       int num = 5 * (rand5() - 1) + (rand5() - 1);
       if (num < 21) return (num % 7 + 1);
    }
}

但我正在考虑另一种解决方案,即 rand5() 被调用 7 次,结果除以 5,但我不确定这是否正确。请让我知道是否存在。

public static int rand7() {    
    int num = rand5()+rand5()+rand5()+rand5()+rand5()+rand5()+rand5();
    return num/5;
}

编辑:看起来生成 1 的概率是 (1/5)^7,但生成 2 的概率是 7*(1/5)^7。它不均匀,因此无法正常工作。

【问题讨论】:

  • 在我看来这应该可以工作,因为应该调用rand5() 任何大于或等于 7 的次数(在sum 中累积结果),然后将(sum % 7) + 1 作为结果。
  • @aroth,这行不通。假设你做了两次。您会在 (1, 10) 范围内获得一个随机值。那么 1、2 和 3 的概率将高于 4、5、6、7。
  • @Paul R:不是完全重复的。这个问题是关于您引用的问题中未提供的解决方案的准确性。
  • @aroth 如果没有指定分布,通常暗示它是统一的。 return 4 只是非均匀分布的一个极端情况。
  • 1 到 5 之间的每个数字已经 1 到 7 之间的数字。​trollface.jpg

标签: algorithm math random


【解决方案1】:

它不会是均匀分布(看起来很正常)。正如保罗所说,证据来自Central Limit Theorem

【讨论】:

  • 证明见中心极限定理:en.wikipedia.org/wiki/Central_limit_theorem
  • @Hareendra:没问题。另外,如果您认为答案很好,请点赞。我还注意到您还没有接受任何答案。如果您的特定答案最能回答您的问题,请单击它旁边的勾号。欲了解更多信息,请阅读FAQ
【解决方案2】:

不,这是不正确的(至少如果要求是均匀分布,这是通过拒绝抽样提供的)。

如果您再添加两个+ rand5() 项,您将计算一个rand5 函数的平均值近似值。就目前而言,您基本上是在计算 rand5 函数的 7/5 × 平均值 的近似值。 (应该是 4.2 左右。)

如果你想要一个介于 1 和 25 之间的数字,你可以这样做

int[][] lut = { {  1,  2,  3,  4,  5},
                {  6,  7,  8,  9, 10},
                ...,
                { 21, 22, 23, 24, 25 } }

return lut[rand5()][rand()]

这不能对 7 进行,因为 5 和 7 是互质数。拒绝抽样是解决这个问题的最好方法。

【讨论】:

  • 不,这不是平均水平。要获得平均值,他必须调用rand5() 7 次,然后除以 7。他调用 7 次并除以 5。据我所知,这个问题没有对结果如何做出任何规定的rand7() 需要分发。我认为任何可能产生介于 1 和 7(含)之间的任何值的解决方案都将被视为有效。
  • 通过这种方式得到近似正态分布,而不是矩形分布 - 请参阅中心极限定理。
  • @aroth,更新了关于平均值的答案。关于“分布”,我认为我们可以放心地假设它是 OP 所追求的均匀分布。
  • @aroth,抱歉没有提供细节,我想要一个统一的分布。
【解决方案3】:

不可能在统一 rand5() 函数的基础上创建统一 rand7() 函数。但是,可以根据需要尽可能接近。

例如,如果你能够在 rand7() 中调用 rand5() 10 次,你可以得到相当好的准统一 rand7()。如果您可以称其为 100,那么 rand7() 可以几乎是完美的,但绝不是完全一致的。这可以在数学上证明。

【讨论】:

    【解决方案4】:

    一个简单的解决方案是在八位字节的位上使用 rand5(),通过将 0 分配给派生值 1 或 2,在 3 上再次生成,或者为值 4 或 5 分配 1。如果最终结果为零,然后重做。这是一些代码:

    public static int rand7() {
        int returnValue = 0;
        while (returnValue == 0) {
            for (int i = 1; i <= 3; i++) {
                returnValue = (returnValue << 1) + rand5_output_2();
            }
        }
        return returnValue;
    }
    
    private static int rand5_output_2() {
        while (true) {
            int flip = rand5();
    
            if (flip < 3) {
                return 0;
            }
            else if (flip > 3) {
                return 1;
            }
        }
    }
    

    【讨论】:

    • 他并没有把事情复杂化。您的解决方案将不起作用,因为函数 rand5() 显然返回整数。这样你只能得到数字 1 2 4 5 7。
    • @Tomas,好吧,希望他指定了。这是我为整数找到的最佳解决方案。
    【解决方案5】:

    虽然其他解决方案会生成 1..7 范围内的随机数,但它会以不均匀的概率分布来生成,即数字 3 比数字 1 更有可能。

    相比之下,拒绝抽样方法将以相等的概率返回 1..7 范围内的所有数字。

    【讨论】:

    • 请注意,第二个解决方案导致正态分布(高斯曲线)。第一个解决方案就OK了。
    猜你喜欢
    • 2013-01-02
    • 2013-12-21
    • 1970-01-01
    • 2014-04-11
    • 1970-01-01
    • 1970-01-01
    • 2016-09-25
    • 2011-08-19
    相关资源
    最近更新 更多