安卓:随机数不够随机

3

我正在编写一款Android单词学习应用。

为了获取随机单词,我使用以下方法:

Random rnd = new Random();
final int rnd.nextInt(WordsNumber);

为了获得随机方向(显示单词或显示翻译),我使用以下方法:
Random rnd = new Random();
final boolean dir.nextBoolean();

然而,我发现单词分布并不均匀。我正在使用17个单词测试该应用程序。有些单词显示了10次,而有些只显示了一次。方向也存在同样的问题。第五次连续出现的方向往往是相同的。

也许有人知道如何使单词分布更加均匀?

更新: 我编写了一个测试应用程序。它会在按钮单击时生成新数字:

public class About extends Activity
{
  final int N = 10;
  int[] results;
  Random rnd;
  int total;

  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_about);

    results = new int[N];
    for (int i = 0; i < N; i++)
    {
      results[i] = 0;
    }

    rnd = new Random();
    total = 0;
  }

  public void GenerateNumber(View view)
  {
    int number = rnd.nextInt(N);
    results[number]++;
    total++;

    String output = new String();
    TextView txt = (TextView)findViewById(R.id.text1);

    output += "Total numbers: " + String.valueOf(total) + "\n";
    for (int i = 0; i < N; i++)
    {
      output += String.valueOf(i) + ": " + String.valueOf(results[i]) + "\n";
    }
    txt.setText(output);
  }
}

这里是测试结果:在此输入图像描述也许,当N=10000时会相等...但对于我的应用程序来说,这是一个可怜的慰藉。

4
很可能是由Java中C#-随机数生成器只生成一个随机数的等效实现引起的。 - Alexei Levenkov
4
让我想起了这个漫画:http://xkcd.com/221/。 - tilpner
你运行测试的频率有多高?可能只是不幸地连续得到了相同的结果,除此之外,还可能存在一些意外编程的偏见。 - tiguchi
你能否发布实际代码和实际结果(包括数字等)来验证/支持你的印象? - njzk2
在按钮点击时调用 final int rnd.nextInt(WordsNumber);。好的,我会写一个测试,但稍后一点(在周一)。 - vitperov
显示剩余2条评论
3个回答

2
你所做的应该给你非常均匀的伪随机分布。
你可以运行采样1000次,计算每个结果在最后出现的频率。它应该大致相同。否则,请发布更多导致问题的代码。 更新 为了让自己信服,请在您的平台上运行下面的简单测试,并检查观察到的结果。 testNum 越大,你将获得越均匀的结果。
        final int testNum = 10000;
        final int max = 9; // will generate integers in range [0 ; 9]
        Random rnd = new Random();
        int[] results = new int[max + 1];

        for (int i = 0; i < testNum; ++i) {
           int nextRandomNumber = rnd.nextInt(max + 1);
           results[nextRandomNumber]++;
        }

        // print statistics
        System.out.println("tests performed = " + testNum);
        for (int i = 0; i <= max; ++i) {
            System.out.println("frequency of " + i + " is " 
                + results[i] * 100 / testNum  + "%");
        }

是的,你说得对,应该是这样的!但是似乎Random()类更喜欢某些数字而不是其他数字。 - vitperov
@vitperov 请尝试运行上面的代码并发布您的结果。它应该是一致的。 - kiruwka
谢谢您的建议。我稍后会进行测试。 - vitperov

1
不要使用


Random rnd = new Random();

每次您需要一个数字时,将 rnd 变为更广泛的范围变量(实例、类等),并仅运行一次以初始化它。 然后,您只需使用它即可。
int whatever = rnd.nextInt(WordsNumber);

当您想要一个新的数字时,创建new Random()会使用当前时间作为种子初始化一个新的伪随机数生成器。如果自上次调用以来时间没有改变,则会获得相同的数字序列。

谢谢你的想法,但它并没有改变任何事情。 - vitperov
2
如果你只运行了几次迭代,很多情况下它看起来就像不是随机的。人类对于随机性的判断非常糟糕。如果你只想让单词更均匀地出现,你可能需要考虑使用洗牌算法。这将在重复任何选项之前给出所有选项。 - Geobits

0

一个由Geobits提出的洗牌算法是一个好的解决方案。

但有更简单的方法。 我决定创建一个最近单词的数组。存储6-8个最近单词足以解决这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接