lingvisa
lingvisa

Reputation: 29

how to make sure random number generation with equal probability?

   Random r1 = new Random();

    for(int i=0; i<10; i++){
        System.out.print(r1.nextInt(10) + " ");
    }

output for one run: 9 7 6 8 3 5 3 3 0 4

why isn't 0-9 generated with equal probability? 3 alone occurs three times, but 1 & 2 zero times.

Upvotes: 2

Views: 1782

Answers (4)

Boris the Spider
Boris the Spider

Reputation: 61158

From, the OP's comment the requirement becomes more clear:

I want to split a file with multiple lines. The split ratio is for instance 4:5. For 100 lines, 40 goes to one file and 50 to another file. And the split must be random

So random numbers are not required, what is required is a random order of numbers 1 to numLines.

This will fulfil the requirement:

public List<Integer> randomLines(final int numLines) {
    final List<Integer> lineNumbers = new ArrayList<>(100);
    //put the line numbers into the List
    //each line occurs exactly once
    for (int i = 1; i <= numLines; ++i) {
        lineNumbers.add(i);
    }
    final Random random = new Random();
    //Carry out a random reording of the List
    Collections.shuffle(lineNumbers, random);
    return lineNumbers;
}

In order to test this code I created a simple test case:

  1. Pick a random split point
  2. Create two Set<Integer. for the line numbers of each file
  3. Verify that the Sets have size splitPoint and numLines - splitPoint

This works because a Set can only contain unique items so if there were duplicates then the Sets would have the wrong size:

@Test
public void testRandomLines() {
    final App app = new App();
    final List<Integer> lineNumbers = app.randomLines(100);
    //pick a random split point
    final int splitPoint = random.nextInt(lineNumbers.size());
    System.out.println(splitPoint);
    final Set<Integer> firstFile = new LinkedHashSet<>();
    final Set<Integer> secondFile = new LinkedHashSet<>();
    for (int i = 0; i < lineNumbers.size(); ++i) {
        if (i < splitPoint) {
            firstFile.add(lineNumbers.get(i));
        } else {
            secondFile.add(lineNumbers.get(i));
        }
    }
    assertThat(firstFile.size(), is(splitPoint));
    assertThat(secondFile.size(), is(lineNumbers.size() - splitPoint));
}

I hope this answers your question.

Upvotes: 0

Andy Senn
Andy Senn

Reputation: 649

If you want to randomize the order of the elements (0-9), you are likely looking for something like a Fisher-Yates Shuffle.

For example:

Random random = new Random();
int[] values = {1, 2, 3, 4, 5};
for(int i = values.length; i > 0; i--) {
    int index = random.nextInt(i);
    int i1 = values[index];
    int i2 = values[i - 1];

    values[i - 1] = i1;
    values[index] = i2;
}

Upvotes: 2

JB Nizet
JB Nizet

Reputation: 691775

It seems you don't want random numbers, but a shuffled list of numbers (like a deck of 52 cards).

List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
Collections.shuffle(list);
// now display them. They will appear in random order, each exactly once
for (Integer i : list) {
    System.out.println(i);
}

Upvotes: 0

nanofarad
nanofarad

Reputation: 41281

Empirical probability is not the same as theoretical probability. What you see is the fact that in this case you got 3 3's and no 2's. If you were to run this again, you would get a different set. You would approach the theoretical probability as the number of runs increases.

As others mention, is tossing a coin twice and getting heads both times a sign that the coin is flawed or has an absurd probability of heads? No. If you tossed it a few million times and got all heads? That's a bit more likely then.

Upvotes: 5

Related Questions