【问题标题】:Why does this program that generates random numbers keep generating numbers in the hundreds?为什么这个生成随机数的程序不断生成数百个数字?
【发布时间】:2023-03-30 20:58:01
【问题描述】:

我有一个关于数组的非常简单的问题。我一直在看一些教程,但不明白为什么下面的代码将频率输出作为 1** 的随机组合。它从不给出 5、67、541 等数字,它总是给出 150、175、183 等数字。我希望我说清楚了。非常感谢!

代码:

    Random rand = new Random();
    int freq[] = new int[7];

    for(int roll=1; roll<=1000; roll++){

        ++freq[1+rand.nextInt(6)];
    }

    System.out.println("Face\tFrequency");

    for(int face=1; face<freq.length; face++){
            System.out.println(face + "\t" + freq[face]);
    }

样本输出:

Face       Frequency

1        176

2        171

3        157

4        159

5        164

6        173

【问题讨论】:

  • 这不是一个数组问题,而是一个概率问题。它可能给出很小的数字,但可能性很小。
  • 它与 0 到 5 (1-6) 之间的整数的随机分布有关。从统计上讲,如果随机发生器是真正随机的,它们都同样可能发生,这就是为什么你看到的数字看起来可能是“奇数”。例如,看到 6 的“67”表示 6 在 1000 次中仅掷出 67 次,这不太可能。例如,加权骰子可能会产生看起来不呈正态分布的数字,因为滚动给定数字的概率与其他数字不同。

标签: java arrays math random


【解决方案1】:

这实际上更像是一道数学题而不是编程题!

掷骰子有六种可能的结果,你掷骰子 1000 次。这意味着,如果您想查看不是“100 X”形式的数字,您需要查看一个数字的 200 个或更多,或者一个数字的 99 个或更少。您将看到每个数字的预期次数是 1000 / 6 = 166.7,因此要看到 200 或更多的数字,您需要偏离真实值 +33.3 或 -66.7。这可能发生;这并不常见。

我编写了一个程序来模拟这样的掷骰子,直到你得到其中一种类型的掷骰并计算你需要掷骰子的次数。在这样做了 1000 次之后,我发现平均而言,你需要掷骰子 53 次才能看到一个不在 100 以内的数字。代码如下:

import java.util.*;

public class DiceRolls {
    /* The number of trials to run. */
    private static final int NUM_TRIALS = 1000;

    public static void main(String[] args) {
        Random rand = new Random();

        int totalRuns = 0;
        for (int i = 0; i < NUM_TRIALS; i++) {
            totalRuns += runsUntilEvent(rand);
        }
        System.out.println(totalRuns / (double)NUM_TRIALS);
    }

    private static int runsUntilEvent(Random rand) {
        /* Track how many tries we needed. */
        int numTries = 0;
        while (true) {
            numTries++;

            /* Rather than indexing from 1 to 6, I'm indexing from 0 to 5. */
            int freq[] = new int[6];            
            for(int roll = 0; roll < 1000; roll++){
                ++freq[rand.nextInt(6)];
            }

            /* See if this isn't in the hundreds. */
            for(int face = 0; face < freq.length; face++){                
                if (freq[face] >= 200 || freq[face] <= 99) {
                    return numTries;
                }
            }
        }
    }
}

因此,您的问题的答案是“您可能会看到它,但不太可能,您必须运行该程序 很多 才能看到它。”

希望这会有所帮助!

【讨论】:

  • 哦,我知道了。所以它基本上给了我“1000卷中某个脸出现的次数”的输出。就像第 1 面出现了 176 次,第 2 面出现了 171 次等等。我认为程序做了其他事情。从这个角度考虑,就像你说的那样,某张脸有可能出现在 150 以下和 200 以上,但不太可能出现 5 次左右。哇,我太笨了:)谢谢你的帮助!
【解决方案2】:

这是正常的。频率为 5 是非常不寻常的,因为这意味着该数字在 1000 次中仅滚动了 5 次。您得到的数字大约是 1000 次滚动总数的 1/6,因此六个数字中的每一个都滚动了大约 1第六次。

【讨论】:

  • 非常感谢您的简单解释,真的很有帮助!
【解决方案3】:

由于你循环了 1000 次,所以偏差很小。

如果只循环 10 次,但在循环中将数字增加 100,则会得到更高的偏差。

【讨论】:

    【解决方案4】:

    输出是在每个“掷骰子”中找到数字的次数。就您使用伪随机数生成而言,数字生成被认为是“公平的”,因此您有一个“公平的骰子掷骰”,这意味着平均而言,每个数字在每次掷骰时出现的机会均等。

    因此,每个数字平均应该出现几乎 1/6 次总投掷,这就是你现在得到的结果。

    如果增加总卷数,每个数字之间1/6的偏差会更大,并且随着卷数的增加而增加。

    【讨论】:

      【解决方案5】:

      我猜你最初的问题是为什么你没有得到低于 100(小于 10%)或大于 500(大于 50%)的低值。

      简短的回答,你不够幸运。因为您创建随机生成器的方式,您必须多次运行程序才能观察这些值。

      如果您只运行一次程序,让我们计算任何结果(频率)在超过 50% 的情况下发生的概率: 如果我们成对滚动,这可以很容易地估算出来(例如,1000 次滚动是 500 对)

      对于每一对,某些特定边的概率(例如 6)是合格结果的数量除以结果的总数:

      合格的结果(第 6 面出现 50% 或更多):

      16, 26, 36, 46, 56, 66, 
      61, 62, 63, 64, 65 
      

      总结果:6^2 = 36

      因此,11 个合格结果除以总数得出一侧发生 50% 或更多时间的概率,即 11/36

      现在我们需要连续发生 N/2 次,所以我们应该将配对概率乘以 N/2 次:(11/36)^(N/2)

      Wolfram alpha 为我们提供 3.5 * 10^-258,这意味着您需要运行程序 2.85 * 10^257 次才能预期(一次)特定一侧的频率 500 次或更多。

      将其除以 6 以查看 任何方面的情况。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-11-17
        • 2011-05-21
        • 2018-10-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-12
        相关资源
        最近更新 更多