Generating M Distinct Random Numbers in the Range [0..N-1]

Generating m distinct random numbers in the range [0..n-1]

Pure mathematics:

Let's calculate the quantity of rand() function calls in both cases and compare the results:

Case 1:
let's see the mathematical expectation of calls on step i = k, when you already have k numbers chosen. The probability to get a number with one rand() call is equal to p = (n-k)/n. We need to know the mathematical expectation of such calls quantity which leads to obtaining a number we don't have yet.

The probability to get it using 1 call is p. Using 2 calls - q * p, where q = 1 - p. In general case, the probability to get it exactly after n calls is (q^(n-1))*p. Thus, the mathematical expectation is

Sum[ n * q^(n-1) * p ], n = 1 --> INF. This sum is equal to 1/p (proved by wolfram alpha).

So, on the step i = k you will perform 1/p = n/(n-k) calls of the rand() function.

Now let's sum it overall:

Sum[ n/(n - k) ], k = 0 --> m - 1 = n * T - the number of rand calls in method 1.

Here T = Sum[ 1/(n - k) ], k = 0 --> m - 1

Case 2:

Here rand() is called inside random_shuffle n - 1 times (in most implementations).

Now, to choose the method, we have to compare these two values: n * T ? n - 1.

So, to choose the appropriate method, calculate T as described above. If T < (n - 1)/n it's better to use the first method. Use the second method otherwise.

Generate 'n' unique random numbers within a range

If you just need sampling without replacement:

>>> import random
>>> random.sample(range(1, 100), 3)
[77, 52, 45]

random.sample takes a population and a sample size k and returns k random members of the population.

If you have to control for the case where k is larger than len(population), you need to be prepared to catch a ValueError:

>>> try:
... random.sample(range(1, 2), 3)
... except ValueError:
... print('Sample size exceeded population size.')
...
Sample size exceeded population size

Generate unique random numbers between 1 and 100

For example: To generate 8 unique random numbers and store them to an array, you can simply do this:

var arr = [];while(arr.length < 8){    var r = Math.floor(Math.random() * 100) + 1;    if(arr.indexOf(r) === -1) arr.push(r);}console.log(arr);

Generating array of unique random numbers

A C implementation example of the algoritm is as follows in the answer you quoted:

#define M 10
#define N 100

int in, im;

im = 0;

for (in = 0; in < N && im < M; ++in) {
int rn = N - in;
int rm = M - im;
if (rand() % rn < rm)
/* Take it */
vektor[im++] = in + 1; /* +1 since your range begins from 1 */
}

The Knuth algorithm. This is a very simple algorithm with a complexity of O(N) (i.e. the numeric range), meaning that it is most usable when M is close to N.

but you set M == N which is not close, but equal

So the initial values of rn and rm are the same. so which cannot make the algorithm work properly because:

whatever % rn < rm

is always true, like 345436 % 22 < 22 would since a % b < b, always.

So test is always true, integer is stored each time, so in and im increase by 1 each time, and so on.

I basically need to shuffle the array of numbers from 0 to n

This algorithm isn't what you need: it doesn't shuffle an array at all, it yields ordered random numbers (so, unique) by picking one from the increasing value from time to time. Constraining the values like you're doing forces the algorithm to issue all the values of the range.

You'll have better luck with Shuffle array in C

Generate 3 distinct random integers via a uniformly distributed RNG

I don't know if these variations make you happier, but this rand3 has one fewer comparison at least.

The idea is to simulate a couple steps of Fisher--Yates. In rand3, we work backward from the index i3 to find the value. The first if undoes the second swap, and the second if undoes the first swap.

import collections
from random import randint

def rand2(low, high):
i1 = randint(low, high)
i2 = randint(low, high - 1)
if i2 == i1:
i2 = high
return i1, i2

def rand3(low, high):
i1 = randint(low, high)
i2 = randint(low, high - 1)
i3 = randint(low, high - 2)
if i3 == i2:
i3 = high - 1
if i3 == i1:
i3 = high
if i2 == i1:
i2 = high
return i1, i2, i3

print(collections.Counter(rand3(1, 4) for i in range(1000000)))

Generating unique random numbers (integers) between 0 and 'x'

Use the basic Math methods:

  • Math.random() returns a random number between 0 and 1 (including 0, excluding 1).
  • Multiply this number by the highest desired number (e.g. 10)
  • Round this number downward to its nearest integer

    Math.floor(Math.random()*10) + 1

Example:

//Example, including customisable intervals [lower_bound, upper_bound)
var limit = 10,
amount = 3,
lower_bound = 1,
upper_bound = 10,
unique_random_numbers = [];

if (amount > limit) limit = amount; //Infinite loop if you want more unique
//Natural numbers than exist in a
// given range
while (unique_random_numbers.length < limit) {
var random_number = Math.floor(Math.random()*(upper_bound - lower_bound) + lower_bound);
if (unique_random_numbers.indexOf(random_number) == -1) {
// Yay! new random number
unique_random_numbers.push( random_number );
}
}
// unique_random_numbers is an array containing 3 unique numbers in the given range

How to generate a list of distinct random numbers including a specific number in JAVA?

For Java 6 and newer:

final int maxNumber = 100;
final int numbersToGenerate = 4;
final int correctAnswer = 45;

Set<Integer> possibleAnswers = new HashSet<>();
Random random = new Random();

// add correct answer
possibleAnswers.add(correctAnswer);

// add as much random answers as needed, the usage of a set prevents duplicates
while(possibleAnswers.size() < numbersToGenerate) {
possibleAnswers.add(random.nextInt(maxNumber));
}

// convert set to list and shuffle it
List<Integer> answers = new ArrayList<Integer>(possibleAnswers);
Collections.shuffle(answers, new Random(System.nanoTime()));

For Java versions below 6 you have to write your own shuffle method, because Collections.shuffle was introduced in Java 6, as far as I know.

I first suggested to use the random api of Java 8, but found an bug in my idea. If the array of generated random numbers contains the correct answer it will not work. For your understanding:

NOT WORKING!!!

final int minNumber = 1;
final int maxNumber = 100;
final int numbersToGenerate = 3;

final int[] ints = new Random().ints(minNumber, maxNumber)
.distinct().limit(numbersToGenerate).toArray();

List<Integer> possibleAnswers = asList(ints);
possibleAnswers.add(correctAnswerIndex);
Collections.shuffle(possibleAnswers, new Random(System.nanoTime()));

NOT WORKING !!!

Unique (non-repeating) random numbers in O(1)?

Initialize an array of 1001 integers with the values 0-1000 and set a variable, max, to the current max index of the array (starting with 1000). Pick a random number, r, between 0 and max, swap the number at the position r with the number at position max and return the number now at position max. Decrement max by 1 and continue. When max is 0, set max back to the size of the array - 1 and start again without the need to reinitialize the array.

Update:
Although I came up with this method on my own when I answered the question, after some research I realize this is a modified version of Fisher-Yates known as Durstenfeld-Fisher-Yates or Knuth-Fisher-Yates. Since the description may be a little difficult to follow, I have provided an example below (using 11 elements instead of 1001):

Array starts off with 11 elements initialized to array[n] = n, max starts off at 10:

+--+--+--+--+--+--+--+--+--+--+--+
| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|
+--+--+--+--+--+--+--+--+--+--+--+
^
max

At each iteration, a random number r is selected between 0 and max, array[r] and array[max] are swapped, the new array[max] is returned, and max is decremented:

max = 10, r = 3
+--------------------+
v v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 1| 2|10| 4| 5| 6| 7| 8| 9| 3|
+--+--+--+--+--+--+--+--+--+--+--+

max = 9, r = 7
+-----+
v v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 1| 2|10| 4| 5| 6| 9| 8| 7: 3|
+--+--+--+--+--+--+--+--+--+--+--+

max = 8, r = 1
+--------------------+
v v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 8| 2|10| 4| 5| 6| 9| 1: 7| 3|
+--+--+--+--+--+--+--+--+--+--+--+

max = 7, r = 5
+-----+
v v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 8| 2|10| 4| 9| 6| 5: 1| 7| 3|
+--+--+--+--+--+--+--+--+--+--+--+

...

After 11 iterations, all numbers in the array have been selected, max == 0, and the array elements are shuffled:

+--+--+--+--+--+--+--+--+--+--+--+
| 4|10| 8| 6| 2| 0| 9| 5| 1| 7| 3|
+--+--+--+--+--+--+--+--+--+--+--+

At this point, max can be reset to 10 and the process can continue.



Related Topics



Leave a reply



Submit