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
How Bad Is Redefining/Shadowing a Local Variable
Setting Vector Elements in Range-Based for Loop
How to Convert a Char Array to a String
What Does _Declspec(Dllimport) Really Mean
Operator Overloading Outside Class
How to Generate Assembly Code with Clang in Intel Syntax
C++ - Arguments for Exceptions Over Return Codes
Compiling External C++ Library for Use with iOS Project
Why Aren't Static Const Floats Allowed
C++: When (And How) Are C++ Global Static Constructors Called
Std::Unique_Ptr for C Functions That Need Free
Can the "Application Error" Dialog Box Be Disabled
Complete C++ I18N Gettext() "Hello World" Example
Expansion with Variadic Templates
"Symbol(S) Not Found for Architecture X86_64" on Qtcreator Project
When Will Gnu C++ Support C++11 Without Explicitly Asking for It
X86 Mul Instruction from VS 2008/2010
Template Specialization of a Single Method from a Templated Class