问题
I am writing a word-learning application for android.
To get random word I use:
Random rnd = new Random();
final int rnd.nextInt(WordsNumber);
To get random direction (show word or show translation) I use:
Random rnd = new Random();
final boolean dir.nextBoolean();
But I see, that a words are not uniformly distributed. I'm testing the application with 17 words. Some words are shown 10 times, some are shown only once. The same problem is with direction. It often happens, for the fifth consecutive time direction is the same.
Maybe someone know, how to make distribution of words more equal?
UPD: I've written a test application. It generates new number on button click:
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);
}
}
Here are the test results:
Maybe, with N=10000 it will be equal... But for my application it's a poor consolation.
回答1:
What you do should give you very well uniform pseudo-random distribution.
You could run you sampling for, say, 1000 times and count how often each results appears in the end. It should be approximately same.
Otherwise, please post more code causing problems.
Update
To convince yourself, try running simple test below on your platform and check observed results. The bigger testNum
the more uniform result you will get.
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 + "%");
}
回答2:
Don't use
Random rnd = new Random();
each time you want a number. Make rnd
a wider scoped variable(instance, class, etc) and just run that once to initialize it.
Then you just use
int whatever = rnd.nextInt(WordsNumber);
when you want a new number.
When you create a new Random()
, it initializes a new PRNG with the seed set to current time. If the time hasn't changed since the last time you called it, you'll get the same number sequence.
回答3:
A shuffling algorithm, proposed by Geobits is good solution.
But it is more simple way. I've decided to make array of recent words. Store 6-8 last words is enough for fixing this problem.
来源:https://stackoverflow.com/questions/19732456/android-random-number-is-not-very-random