关于java:Android:随机数不是很随机

Android: random number is not very random

我正在为Android编写一个单词学习应用程序。

要获得随机单词,我使用:

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

要获得随机方向(显示单词或显示翻译),我使用:

1
2
Random rnd = new Random();
final boolean dir.nextBoolean();

但我明白了,一个词并不是均匀分布的。我正在用17个字测试这个应用程序。有些单词显示10次,有些只显示一次。方向也有同样的问题。这种情况经常发生,因为连续第五个时间方向是相同的。

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

UPD:我写了一份测试申请。点击按钮生成新号码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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) +"
"
;
    for (int i = 0; i < N; i++)
    {
      output += String.valueOf(i) +":" + String.valueOf(results[i]) +"
"
;
    }
    txt.setText(output);
  }
}

测试结果如下:enter image description here

也许,当n=10000时,它等于…但对于我的申请,这是一个可怜的安慰。


你所做的应该给你非常均匀的伪随机分布。您可以运行采样1000次,并计算每个结果最终出现的频率。应该大致相同。否则,请发布更多导致问题的代码。

更新为了说服自己,尝试在平台上运行下面的简单测试,并检查观察到的结果。testNum越大,结果越均匀。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        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  +"%");
        }


不使用

1
Random rnd = new Random();

每次你想要一个数字。使rnd成为更大范围的变量(实例、类等),只需运行一次即可初始化它。

那你就用

1
int whatever = rnd.nextInt(WordsNumber);

当你想要一个新的号码。

创建new Random()时,它会初始化一个新的prng,并将seed设置为当前时间。如果上次调用后时间没有改变,您将得到相同的编号规则。


由geobits提出的一种洗牌算法是很好的解决方案。

但这是更简单的方法。我决定把最近的单词排成一列。存储6-8个单词足以解决此问题。


首先,你可以检查这个问题:

爪哇中随机数的获取

也可以查一下Math.random类。

第二,在一个小范围的选择中,随机选择可以返回一个数字,而其他数字则可以多返回一个数字。但如果有足够大的测试规模,它的分布应该更均匀。